@womp/kookie-ui 0.31.0 → 0.33.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 (127) hide show
  1. package/components.css +101 -86
  2. package/dist/cjs/components/_internal/pane-chrome.js +1 -1
  3. package/dist/cjs/components/_internal/pane-chrome.js.map +2 -2
  4. package/dist/cjs/components/_internal/shell-bottom.d.ts +7 -2
  5. package/dist/cjs/components/_internal/shell-bottom.d.ts.map +1 -1
  6. package/dist/cjs/components/_internal/shell-bottom.js +1 -1
  7. package/dist/cjs/components/_internal/shell-bottom.js.map +3 -3
  8. package/dist/cjs/components/_internal/shell-inspector.d.ts +7 -2
  9. package/dist/cjs/components/_internal/shell-inspector.d.ts.map +1 -1
  10. package/dist/cjs/components/_internal/shell-inspector.js +1 -1
  11. package/dist/cjs/components/_internal/shell-inspector.js.map +3 -3
  12. package/dist/cjs/components/_internal/shell-pane.js +1 -1
  13. package/dist/cjs/components/_internal/shell-pane.js.map +2 -2
  14. package/dist/cjs/components/_internal/shell-sidebar.d.ts +7 -2
  15. package/dist/cjs/components/_internal/shell-sidebar.d.ts.map +1 -1
  16. package/dist/cjs/components/_internal/shell-sidebar.js +1 -1
  17. package/dist/cjs/components/_internal/shell-sidebar.js.map +3 -3
  18. package/dist/cjs/components/_internal/shell-store.d.ts +6 -6
  19. package/dist/cjs/components/_internal/shell-store.d.ts.map +1 -1
  20. package/dist/cjs/components/_internal/shell-store.js +1 -1
  21. package/dist/cjs/components/_internal/shell-store.js.map +3 -3
  22. package/dist/cjs/components/index.js +2 -2
  23. package/dist/cjs/components/index.js.map +3 -3
  24. package/dist/cjs/components/link.js +1 -1
  25. package/dist/cjs/components/link.js.map +3 -3
  26. package/dist/cjs/components/link.props.d.ts +0 -6
  27. package/dist/cjs/components/link.props.d.ts.map +1 -1
  28. package/dist/cjs/components/link.props.js +1 -1
  29. package/dist/cjs/components/link.props.js.map +3 -3
  30. package/dist/cjs/components/navigator.js +1 -1
  31. package/dist/cjs/components/navigator.js.map +2 -2
  32. package/dist/cjs/components/shell.context.js +1 -1
  33. package/dist/cjs/components/shell.context.js.map +2 -2
  34. package/dist/cjs/components/shell.d.ts +25 -7
  35. package/dist/cjs/components/shell.d.ts.map +1 -1
  36. package/dist/cjs/components/shell.hooks.js +1 -1
  37. package/dist/cjs/components/shell.hooks.js.map +2 -2
  38. package/dist/cjs/components/shell.js +1 -1
  39. package/dist/cjs/components/shell.js.map +3 -3
  40. package/dist/cjs/components/toolbar.js +1 -1
  41. package/dist/cjs/components/toolbar.js.map +2 -2
  42. package/dist/cjs/index.js +3 -3
  43. package/dist/cjs/index.js.map +3 -3
  44. package/dist/cjs/props/index.js +1 -1
  45. package/dist/cjs/props/index.js.map +3 -3
  46. package/dist/esm/chunk-3H33S3UA.js +3 -0
  47. package/dist/esm/{chunk-B7STVZPU.js.map → chunk-3H33S3UA.js.map} +3 -3
  48. package/dist/esm/chunk-5BXCPANF.js +3 -0
  49. package/dist/esm/{chunk-GHWEXMF6.js.map → chunk-5BXCPANF.js.map} +3 -3
  50. package/dist/esm/{chunk-ZG2XQUOH.js → chunk-B447PNRD.js} +2 -2
  51. package/dist/esm/{chunk-QDAM2I6O.js → chunk-BR6Z2CAE.js} +2 -2
  52. package/dist/esm/{chunk-4G3FJUER.js → chunk-INGT6DB6.js} +2 -2
  53. package/dist/esm/{chunk-4ZHBNYXM.js → chunk-J6B7UCZN.js} +2 -2
  54. package/dist/esm/chunk-KDJM4NQQ.js +3 -0
  55. package/dist/esm/chunk-KDJM4NQQ.js.map +7 -0
  56. package/dist/esm/{chunk-LTUW36HM.js → chunk-KGCGT4MJ.js} +2 -2
  57. package/dist/esm/chunk-NO2JCJWI.js +3 -0
  58. package/dist/esm/chunk-NO2JCJWI.js.map +7 -0
  59. package/dist/esm/{chunk-NFSW36RG.js → chunk-ODHCDJ3Y.js} +2 -2
  60. package/dist/esm/chunk-UMQOTGJC.js +3 -0
  61. package/dist/esm/chunk-UMQOTGJC.js.map +7 -0
  62. package/dist/esm/chunk-VKUAP54W.js +2 -0
  63. package/dist/esm/chunk-VKUAP54W.js.map +7 -0
  64. package/dist/esm/chunk-XD676L6S.js +3 -0
  65. package/dist/esm/chunk-XD676L6S.js.map +7 -0
  66. package/dist/esm/{chunk-6SGJWML7.js → chunk-XKYPJTRN.js} +2 -2
  67. package/dist/esm/components/_internal/pane-chrome.js +1 -1
  68. package/dist/esm/components/_internal/shell-bottom.d.ts +7 -2
  69. package/dist/esm/components/_internal/shell-bottom.d.ts.map +1 -1
  70. package/dist/esm/components/_internal/shell-bottom.js +1 -1
  71. package/dist/esm/components/_internal/shell-inspector.d.ts +7 -2
  72. package/dist/esm/components/_internal/shell-inspector.d.ts.map +1 -1
  73. package/dist/esm/components/_internal/shell-inspector.js +1 -1
  74. package/dist/esm/components/_internal/shell-pane.js +1 -1
  75. package/dist/esm/components/_internal/shell-sidebar.d.ts +7 -2
  76. package/dist/esm/components/_internal/shell-sidebar.d.ts.map +1 -1
  77. package/dist/esm/components/_internal/shell-sidebar.js +1 -1
  78. package/dist/esm/components/_internal/shell-store.d.ts +6 -6
  79. package/dist/esm/components/_internal/shell-store.d.ts.map +1 -1
  80. package/dist/esm/components/_internal/shell-store.js +1 -1
  81. package/dist/esm/components/index.js +1 -1
  82. package/dist/esm/components/link.js +1 -1
  83. package/dist/esm/components/link.props.d.ts +0 -6
  84. package/dist/esm/components/link.props.d.ts.map +1 -1
  85. package/dist/esm/components/link.props.js +1 -1
  86. package/dist/esm/components/navigator.js +1 -1
  87. package/dist/esm/components/shell.context.js +1 -1
  88. package/dist/esm/components/shell.d.ts +25 -7
  89. package/dist/esm/components/shell.d.ts.map +1 -1
  90. package/dist/esm/components/shell.hooks.js +1 -1
  91. package/dist/esm/components/shell.js +1 -1
  92. package/dist/esm/components/sidebar.js +1 -1
  93. package/dist/esm/components/toolbar.js +1 -1
  94. package/dist/esm/index.js +1 -1
  95. package/dist/esm/props/index.js +1 -1
  96. package/package.json +1 -1
  97. package/src/components/_internal/shell-bottom.tsx +11 -6
  98. package/src/components/_internal/shell-inspector.tsx +11 -6
  99. package/src/components/_internal/shell-sidebar.tsx +11 -6
  100. package/src/components/_internal/shell-store.tsx +13 -13
  101. package/src/components/link.css +16 -46
  102. package/src/components/link.props.tsx +0 -3
  103. package/src/components/shell.css +133 -47
  104. package/src/components/shell.tsx +50 -32
  105. package/src/styles/tokens/color.css +2 -0
  106. package/styles.css +102 -86
  107. package/tokens/base.css +1 -0
  108. package/tokens.css +1 -0
  109. package/dist/esm/chunk-4B3S2DM7.js +0 -3
  110. package/dist/esm/chunk-4B3S2DM7.js.map +0 -7
  111. package/dist/esm/chunk-AKMRPGNP.js +0 -3
  112. package/dist/esm/chunk-AKMRPGNP.js.map +0 -7
  113. package/dist/esm/chunk-B7STVZPU.js +0 -3
  114. package/dist/esm/chunk-EFXHBH3A.js +0 -2
  115. package/dist/esm/chunk-EFXHBH3A.js.map +0 -7
  116. package/dist/esm/chunk-GHWEXMF6.js +0 -3
  117. package/dist/esm/chunk-ZBSGH74F.js +0 -3
  118. package/dist/esm/chunk-ZBSGH74F.js.map +0 -7
  119. package/dist/esm/chunk-ZHXEEOGI.js +0 -3
  120. package/dist/esm/chunk-ZHXEEOGI.js.map +0 -7
  121. /package/dist/esm/{chunk-ZG2XQUOH.js.map → chunk-B447PNRD.js.map} +0 -0
  122. /package/dist/esm/{chunk-QDAM2I6O.js.map → chunk-BR6Z2CAE.js.map} +0 -0
  123. /package/dist/esm/{chunk-4G3FJUER.js.map → chunk-INGT6DB6.js.map} +0 -0
  124. /package/dist/esm/{chunk-4ZHBNYXM.js.map → chunk-J6B7UCZN.js.map} +0 -0
  125. /package/dist/esm/{chunk-LTUW36HM.js.map → chunk-KGCGT4MJ.js.map} +0 -0
  126. /package/dist/esm/{chunk-NFSW36RG.js.map → chunk-ODHCDJ3Y.js.map} +0 -0
  127. /package/dist/esm/{chunk-6SGJWML7.js.map → chunk-XKYPJTRN.js.map} +0 -0
@@ -1,2 +1,2 @@
1
- import{a as no}from"../chunk-677CX2QF.js";import{a as lo}from"../chunk-JQVW4WNN.js";import{a as ko}from"../chunk-YLDV2HKZ.js";import{a as io,b as jo}from"../chunk-WRWNN2NW.js";import{a as to}from"../chunk-LUNWI377.js";import{a as xo,b as ao,c as bo}from"../chunk-EXF5SF27.js";import{a as co}from"../chunk-YHQTFDGN.js";import{a as go}from"../chunk-FH6RT6XH.js";import{a as ho}from"../chunk-H3IAGAEL.js";import{a as U}from"../chunk-A252TSYI.js";import{a as V,b as W,c as X}from"../chunk-HCBR74BW.js";import{a as Y}from"../chunk-NR5FQCMU.js";import{a as Z}from"../chunk-3W34KH33.js";import{a as _}from"../chunk-HIEGLLY7.js";import{a as $}from"../chunk-5XA2N2WR.js";import{a as ro,b as eo,c as fo}from"../chunk-XDVTHL3S.js";import{a as oo}from"../chunk-P7VSZYG3.js";import{a as mo,b as po}from"../chunk-TZTUPQYK.js";import{a as O}from"../chunk-RAVZ7F5L.js";import{a as P}from"../chunk-EFXHBH3A.js";import{a as Q}from"../chunk-VW46DG7H.js";import{a as R}from"../chunk-SKOYHBIE.js";import{a as S}from"../chunk-KVOWI6SN.js";import"../chunk-STPMPY3X.js";import{a as T}from"../chunk-UONSKZQT.js";import"../chunk-OA7C34MJ.js";import"../chunk-WOR3JCLX.js";import{a as J}from"../chunk-UMYPLUG3.js";import{a as K}from"../chunk-DFLWZOQO.js";import{a as I}from"../chunk-FJLYSZV3.js";import{a as N}from"../chunk-HSWMHW37.js";import{a as M}from"../chunk-WTCZAUFY.js";import"../chunk-VCV7RACK.js";import{a as L}from"../chunk-KEWNXANF.js";import{a as C}from"../chunk-CT543Q2V.js";import{a as D}from"../chunk-BIITGC3Z.js";import"../chunk-6DWDNKLS.js";import{a as E}from"../chunk-OSSNMF5U.js";import{a as F}from"../chunk-4E5XBM5Q.js";import"../chunk-UICSVJ3B.js";import{a as G}from"../chunk-UUXZ4W6H.js";import{a as H}from"../chunk-PEMFIU3B.js";import{a as w,b as y}from"../chunk-VS2ZWRGO.js";import{a as z}from"../chunk-SBRPXQWH.js";import{a as A}from"../chunk-SJXV4BWZ.js";import{a as B}from"../chunk-N6KH2EOU.js";import{a}from"../chunk-OEPVYHSS.js";import{a as b}from"../chunk-AKXBXLCP.js";import{a as c,b as d,c as g,d as h,e as i,f as j}from"../chunk-AJWCSQIE.js";import{a as k}from"../chunk-BF4WRYUX.js";import{a as l}from"../chunk-ETQNRMHU.js";import{a as u}from"../chunk-DFGY2NZB.js";import{a as s}from"../chunk-FNAE6HUI.js";import{a as q}from"../chunk-NUVUXNHF.js";import{a as n}from"../chunk-EKTVL6SS.js";import{a as v}from"../chunk-NNE3KNH4.js";import{a as t,b as x}from"../chunk-KRJTW535.js";import{a as r,b as e,c as f,d as m,e as p}from"../chunk-CUNKWFKA.js";import{a as o}from"../chunk-NZJGC6ZW.js";export{m as accentColorPropDef,r as accentColors,u as alertDialogContentPropDefs,o as asChildPropDef,v as avatarPropDefs,C as blockquotePropDefs,D as boxPropDefs,jo as breakpointSet,io as breakpoints,a as buttonPropDefs,E as cardPropDefs,F as checkboxGroupRootPropDefs,b as checkboxPropDefs,G as chipPropDefs,H as codePropDefs,f as colorPropDef,i as contextMenuCheckboxItemPropDefs,g as contextMenuContentPropDefs,h as contextMenuItemPropDefs,j as contextMenuRadioItemPropDefs,g as contextMenuSubContentPropDefs,s as dialogContentPropDefs,i as dropdownMenuCheckboxItemPropDefs,d as dropdownMenuContentPropDefs,h as dropdownMenuItemPropDefs,j as dropdownMenuRadioItemPropDefs,g as dropdownMenuSubContentPropDefs,w as emphases,y as emphasisPropDef,J as flexPropDefs,I as gapPropDefs,p as grayAccentColorPropDef,e as grayColors,K as gridPropDefs,N as headingPropDefs,q as heightPropDefs,O as kbdPropDefs,lo as layoutPropDefs,L as leadingTrimPropDef,P as linkPropDefs,ko as marginPropDefs,oo as paddingPropDefs,Q as popoverContentPropDefs,R as progressPropDefs,t as radii,S as radioGroupRootPropDefs,k as radioPropDefs,x as radiusPropDef,T as scrollAreaPropDefs,U as segmentedControlRootPropDefs,X as selectContentPropDefs,V as selectRootPropDefs,W as selectTriggerPropDefs,Y as separatorPropDefs,no as shadowPropDefs,Z as sliderPropDefs,_ as spinnerPropDefs,c as submenuBehaviors,$ as switchPropDefs,fo as tableCellPropDefs,ro as tableRootPropDefs,eo as tableRowPropDefs,po as tabsContentPropDefs,l as tabsListPropDefs,mo as tabsRootPropDefs,M as textAlignPropDef,to as textAreaPropDefs,ao as textFieldGroupPropDefs,xo as textFieldRootPropDefs,bo as textFieldSlotPropDefs,co as textPropDefs,z as textWrapPropDef,go as themePropDefs,ho as tooltipPropDefs,A as truncatePropDef,B as weightPropDef,n as widthPropDefs};
1
+ import{a as no}from"../chunk-677CX2QF.js";import{a as lo}from"../chunk-JQVW4WNN.js";import{a as ko}from"../chunk-YLDV2HKZ.js";import{a as io,b as jo}from"../chunk-WRWNN2NW.js";import{a as to}from"../chunk-LUNWI377.js";import{a as xo,b as ao,c as bo}from"../chunk-EXF5SF27.js";import{a as co}from"../chunk-YHQTFDGN.js";import{a as go}from"../chunk-FH6RT6XH.js";import{a as ho}from"../chunk-H3IAGAEL.js";import{a as U}from"../chunk-A252TSYI.js";import{a as V,b as W,c as X}from"../chunk-HCBR74BW.js";import{a as Y}from"../chunk-NR5FQCMU.js";import{a as Z}from"../chunk-3W34KH33.js";import{a as _}from"../chunk-HIEGLLY7.js";import{a as $}from"../chunk-5XA2N2WR.js";import{a as ro,b as eo,c as fo}from"../chunk-XDVTHL3S.js";import{a as oo}from"../chunk-P7VSZYG3.js";import{a as mo,b as po}from"../chunk-TZTUPQYK.js";import{a as O}from"../chunk-RAVZ7F5L.js";import{a as P}from"../chunk-VKUAP54W.js";import{a as Q}from"../chunk-VW46DG7H.js";import{a as R}from"../chunk-SKOYHBIE.js";import{a as S}from"../chunk-KVOWI6SN.js";import"../chunk-STPMPY3X.js";import{a as T}from"../chunk-UONSKZQT.js";import"../chunk-OA7C34MJ.js";import"../chunk-WOR3JCLX.js";import{a as J}from"../chunk-UMYPLUG3.js";import{a as K}from"../chunk-DFLWZOQO.js";import{a as I}from"../chunk-FJLYSZV3.js";import{a as N}from"../chunk-HSWMHW37.js";import{a as M}from"../chunk-WTCZAUFY.js";import"../chunk-VCV7RACK.js";import{a as L}from"../chunk-KEWNXANF.js";import{a as C}from"../chunk-CT543Q2V.js";import{a as D}from"../chunk-BIITGC3Z.js";import"../chunk-6DWDNKLS.js";import{a as E}from"../chunk-OSSNMF5U.js";import{a as F}from"../chunk-4E5XBM5Q.js";import"../chunk-UICSVJ3B.js";import{a as G}from"../chunk-UUXZ4W6H.js";import{a as H}from"../chunk-PEMFIU3B.js";import{a as w,b as y}from"../chunk-VS2ZWRGO.js";import{a as z}from"../chunk-SBRPXQWH.js";import{a as A}from"../chunk-SJXV4BWZ.js";import{a as B}from"../chunk-N6KH2EOU.js";import{a}from"../chunk-OEPVYHSS.js";import{a as b}from"../chunk-AKXBXLCP.js";import{a as c,b as d,c as g,d as h,e as i,f as j}from"../chunk-AJWCSQIE.js";import{a as k}from"../chunk-BF4WRYUX.js";import{a as l}from"../chunk-ETQNRMHU.js";import{a as u}from"../chunk-DFGY2NZB.js";import{a as s}from"../chunk-FNAE6HUI.js";import{a as q}from"../chunk-NUVUXNHF.js";import{a as n}from"../chunk-EKTVL6SS.js";import{a as v}from"../chunk-NNE3KNH4.js";import{a as t,b as x}from"../chunk-KRJTW535.js";import{a as r,b as e,c as f,d as m,e as p}from"../chunk-CUNKWFKA.js";import{a as o}from"../chunk-NZJGC6ZW.js";export{m as accentColorPropDef,r as accentColors,u as alertDialogContentPropDefs,o as asChildPropDef,v as avatarPropDefs,C as blockquotePropDefs,D as boxPropDefs,jo as breakpointSet,io as breakpoints,a as buttonPropDefs,E as cardPropDefs,F as checkboxGroupRootPropDefs,b as checkboxPropDefs,G as chipPropDefs,H as codePropDefs,f as colorPropDef,i as contextMenuCheckboxItemPropDefs,g as contextMenuContentPropDefs,h as contextMenuItemPropDefs,j as contextMenuRadioItemPropDefs,g as contextMenuSubContentPropDefs,s as dialogContentPropDefs,i as dropdownMenuCheckboxItemPropDefs,d as dropdownMenuContentPropDefs,h as dropdownMenuItemPropDefs,j as dropdownMenuRadioItemPropDefs,g as dropdownMenuSubContentPropDefs,w as emphases,y as emphasisPropDef,J as flexPropDefs,I as gapPropDefs,p as grayAccentColorPropDef,e as grayColors,K as gridPropDefs,N as headingPropDefs,q as heightPropDefs,O as kbdPropDefs,lo as layoutPropDefs,L as leadingTrimPropDef,P as linkPropDefs,ko as marginPropDefs,oo as paddingPropDefs,Q as popoverContentPropDefs,R as progressPropDefs,t as radii,S as radioGroupRootPropDefs,k as radioPropDefs,x as radiusPropDef,T as scrollAreaPropDefs,U as segmentedControlRootPropDefs,X as selectContentPropDefs,V as selectRootPropDefs,W as selectTriggerPropDefs,Y as separatorPropDefs,no as shadowPropDefs,Z as sliderPropDefs,_ as spinnerPropDefs,c as submenuBehaviors,$ as switchPropDefs,fo as tableCellPropDefs,ro as tableRootPropDefs,eo as tableRowPropDefs,po as tabsContentPropDefs,l as tabsListPropDefs,mo as tabsRootPropDefs,M as textAlignPropDef,to as textAreaPropDefs,ao as textFieldGroupPropDefs,xo as textFieldRootPropDefs,bo as textFieldSlotPropDefs,co as textPropDefs,z as textWrapPropDef,go as themePropDefs,ho as tooltipPropDefs,A as truncatePropDef,B as weightPropDef,n as widthPropDefs};
2
2
  //# sourceMappingURL=index.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@womp/kookie-ui",
3
- "version": "0.31.0",
3
+ "version": "0.33.0",
4
4
  "description": "Kookie UI v1: a React component library with design tokens, flexible theming, a full layout shell, and comprehensive documentation.",
5
5
  "keywords": [
6
6
  "react",
@@ -7,7 +7,7 @@ import { PaneResizeContext } from './shell-resize.js';
7
7
  import { BottomHandle, PaneHandle } from './shell-handles.js';
8
8
  import { usePane, paneAttributes, usePresentationTable } from './shell-pane.js';
9
9
  import { splitHandles, useInitialPaneSize, useResizablePane, type SizeChangeMeta } from './shell-resizable.js';
10
- import { useInsetRegistration, warnOnce } from './shell-store.js';
10
+ import { useFrameRegistration, warnOnce } from './shell-store.js';
11
11
  import { bottomAnchoredGrowth, detailRest, toPaneValue, withoutRemovedPaneProps } from './shell-rest.js';
12
12
  import { PageScope } from './page-scope.js';
13
13
  import { readBreakpoint } from '../../hooks/use-breakpoint.js';
@@ -25,8 +25,13 @@ type BottomPublicProps = PaneBaseProps &
25
25
  onSizeChange?: (size: number, meta: SizeChangeMeta) => void;
26
26
  sizeUpdate?: 'throttle' | 'debounce';
27
27
  sizeUpdateMs?: number;
28
- /** When true, adds margin and triggers the gray backdrop on the Shell. */
29
- inset?: boolean;
28
+ /**
29
+ * Sets whether this pane joins the app frame. The default is `true`: the pane sits against its
30
+ * neighbours with one hairline between them. Set `flush={false}` to pull it off the frame as a
31
+ * card. It then floats over the content if the content is flush, and otherwise sits on the
32
+ * Shell's background beside a card content.
33
+ */
34
+ flush?: boolean;
30
35
  };
31
36
 
32
37
  type BottomComponent = React.ForwardRefExoticComponent<BottomPublicProps & React.RefAttributes<HTMLDivElement>> & { Handle: typeof BottomHandle };
@@ -62,7 +67,7 @@ export const Bottom = React.forwardRef<HTMLDivElement, BottomPublicProps>((props
62
67
  onSizeChange,
63
68
  sizeUpdate,
64
69
  sizeUpdateMs = 50,
65
- inset,
70
+ flush = true,
66
71
  id,
67
72
  ...domProps
68
73
  } = props;
@@ -82,7 +87,7 @@ export const Bottom = React.forwardRef<HTMLDivElement, BottomPublicProps>((props
82
87
  onCollapse,
83
88
  size: expandedSize,
84
89
  });
85
- useInsetRegistration('bottom', inset);
90
+ useFrameRegistration('bottom', flush);
86
91
 
87
92
  React.useEffect(() => {
88
93
  if (snapPoints !== undefined || collapseThreshold !== undefined || paneId !== undefined || persistence !== undefined) {
@@ -137,7 +142,7 @@ export const Bottom = React.forwardRef<HTMLDivElement, BottomPublicProps>((props
137
142
  ref={composedRef}
138
143
  className={classNames('kui-ShellPane', 'kui-ShellBottom', className)}
139
144
  {...paneAttributes(pane, attributes)}
140
- data-inset={inset || undefined}
145
+ data-flush={flush || undefined}
141
146
  tabIndex={pane.overlaying ? -1 : domProps.tabIndex}
142
147
  style={
143
148
  {
@@ -7,7 +7,7 @@ import { PaneResizeContext } from './shell-resize.js';
7
7
  import { InspectorHandle, PaneHandle } from './shell-handles.js';
8
8
  import { usePane, paneAttributes, usePresentationTable } from './shell-pane.js';
9
9
  import { splitHandles, useInitialPaneSize, useResizablePane, type SizeChangeMeta } from './shell-resizable.js';
10
- import { useInsetRegistration, warnOnce } from './shell-store.js';
10
+ import { useFrameRegistration, warnOnce } from './shell-store.js';
11
11
  import { detailRest, endAnchoredGrowth, toPaneValue, withoutRemovedPaneProps } from './shell-rest.js';
12
12
  import { PageScope } from './page-scope.js';
13
13
  import { readBreakpoint } from '../../hooks/use-breakpoint.js';
@@ -24,8 +24,13 @@ type InspectorPublicProps = PaneBaseProps &
24
24
  onSizeChange?: (size: number, meta: SizeChangeMeta) => void;
25
25
  sizeUpdate?: 'throttle' | 'debounce';
26
26
  sizeUpdateMs?: number;
27
- /** When true, adds margin and triggers the gray backdrop on the Shell. */
28
- inset?: boolean;
27
+ /**
28
+ * Sets whether this pane joins the app frame. The default is `true`: the pane sits against its
29
+ * neighbours with one hairline between them. Set `flush={false}` to pull it off the frame as a
30
+ * card. It then floats over the content if the content is flush, and otherwise sits on the
31
+ * Shell's background beside a card content.
32
+ */
33
+ flush?: boolean;
29
34
  };
30
35
 
31
36
  type InspectorComponent = React.ForwardRefExoticComponent<InspectorPublicProps & React.RefAttributes<HTMLDivElement>> & { Handle: typeof InspectorHandle };
@@ -64,7 +69,7 @@ export const Inspector = React.forwardRef<HTMLDivElement, InspectorPublicProps>(
64
69
  sizeUpdateMs = 50,
65
70
  size,
66
71
  defaultSize,
67
- inset,
72
+ flush = true,
68
73
  id,
69
74
  ...domProps
70
75
  } = props;
@@ -84,7 +89,7 @@ export const Inspector = React.forwardRef<HTMLDivElement, InspectorPublicProps>(
84
89
  onCollapse,
85
90
  size: expandedSize,
86
91
  });
87
- useInsetRegistration('inspector', inset);
92
+ useFrameRegistration('inspector', flush);
88
93
 
89
94
  React.useEffect(() => {
90
95
  if (snapPoints !== undefined || collapseThreshold !== undefined || paneId !== undefined || persistence !== undefined) {
@@ -139,7 +144,7 @@ export const Inspector = React.forwardRef<HTMLDivElement, InspectorPublicProps>(
139
144
  ref={composedRef}
140
145
  className={classNames('kui-ShellPane', 'kui-ShellInspector', className)}
141
146
  {...paneAttributes(pane, attributes)}
142
- data-inset={inset || undefined}
147
+ data-flush={flush || undefined}
143
148
  tabIndex={pane.overlaying ? -1 : domProps.tabIndex}
144
149
  style={
145
150
  {
@@ -7,7 +7,7 @@ import { PaneResizeContext } from './shell-resize.js';
7
7
  import { PaneHandle, SidebarHandle } from './shell-handles.js';
8
8
  import { usePane, paneAttributes, usePresentationTable } from './shell-pane.js';
9
9
  import { splitHandles, useInitialPaneSize, useResizablePane, type SizeChangeMeta } from './shell-resizable.js';
10
- import { useInsetRegistration, warnOnce, type PaneValue } from './shell-store.js';
10
+ import { useFrameRegistration, warnOnce, type PaneValue } from './shell-store.js';
11
11
  import { navigationRest, startAnchoredGrowth, withoutRemovedPaneProps } from './shell-rest.js';
12
12
  import { readBreakpoint } from '../../hooks/use-breakpoint.js';
13
13
  import { PaneChromeScope } from './pane-chrome.js';
@@ -23,8 +23,13 @@ type SidebarPublicProps = PaneBaseProps & {
23
23
  onSizeChange?: (size: number, meta: SizeChangeMeta) => void;
24
24
  sizeUpdate?: 'throttle' | 'debounce';
25
25
  sizeUpdateMs?: number;
26
- /** When true, adds margin and triggers the gray backdrop on the Shell. */
27
- inset?: boolean;
26
+ /**
27
+ * Sets whether this pane joins the app frame. The default is `true`: the pane sits against its
28
+ * neighbours with one hairline between them. Set `flush={false}` to pull it off the frame as a
29
+ * card. It then floats over the content if the content is flush, and otherwise sits on the
30
+ * Shell's background beside a card content.
31
+ */
32
+ flush?: boolean;
28
33
  } & (SidebarControlledProps | SidebarUncontrolledProps);
29
34
 
30
35
  type SidebarComponent = React.ForwardRefExoticComponent<SidebarPublicProps & React.RefAttributes<HTMLDivElement>> & { Handle: typeof SidebarHandle };
@@ -77,7 +82,7 @@ export const Sidebar = React.forwardRef<HTMLDivElement, SidebarPublicProps>((pro
77
82
  onSizeChange,
78
83
  sizeUpdate,
79
84
  sizeUpdateMs = 50,
80
- inset,
85
+ flush = true,
81
86
  id,
82
87
  ...domProps
83
88
  } = props;
@@ -97,7 +102,7 @@ export const Sidebar = React.forwardRef<HTMLDivElement, SidebarPublicProps>((pro
97
102
  onCollapse,
98
103
  size: expandedSize,
99
104
  });
100
- useInsetRegistration('sidebar', inset);
105
+ useFrameRegistration('sidebar', flush);
101
106
 
102
107
  React.useEffect(() => {
103
108
  if (snapPoints !== undefined || collapseThreshold !== undefined || paneId !== undefined || persistence !== undefined) {
@@ -158,7 +163,7 @@ export const Sidebar = React.forwardRef<HTMLDivElement, SidebarPublicProps>((pro
158
163
  ref={composedRef}
159
164
  className={classNames('kui-ShellPane', 'kui-ShellSidebar', className)}
160
165
  {...paneAttributes(pane, attributes)}
161
- data-inset={inset || undefined}
166
+ data-flush={flush || undefined}
162
167
  tabIndex={pane.overlaying ? -1 : domProps.tabIndex}
163
168
  style={
164
169
  {
@@ -171,25 +171,25 @@ export function usePeeking(store: ShellStore, name: PaneName): boolean {
171
171
  );
172
172
  }
173
173
 
174
- /* ── Inset ─────────────────────────────────────────────────────────────────── */
174
+ /* ── Off the frame ─────────────────────────────────────────────────────────── */
175
175
 
176
- export type InsetPaneId = 'rail' | 'panel' | 'sidebar' | 'content' | 'inspector' | 'bottom';
176
+ export type FramePaneId = 'rail' | 'panel' | 'sidebar' | 'content' | 'inspector' | 'bottom';
177
177
 
178
- export const ShellInsetContext = React.createContext<{
179
- registerInset: (id: InsetPaneId) => void;
180
- unregisterInset: (id: InsetPaneId) => void;
178
+ export const ShellFrameContext = React.createContext<{
179
+ registerOffFrame: (id: FramePaneId) => void;
180
+ unregisterOffFrame: (id: FramePaneId) => void;
181
181
  } | null>(null);
182
182
 
183
- /** Registers a pane's `inset` with the Root, which paints the backdrop while any pane is inset. */
184
- export function useInsetRegistration(id: InsetPaneId, inset: boolean | undefined) {
185
- const ctx = React.useContext(ShellInsetContext);
183
+ /** Tells the Root a pane is off the frame (`flush={false}`); the Rail's card moves a floating Panel over. */
184
+ export function useFrameRegistration(id: FramePaneId, flush: boolean) {
185
+ const ctx = React.useContext(ShellFrameContext);
186
186
  if (!ctx) throw new Error('Shell panes must be used within <Shell.Root>');
187
- const { registerInset, unregisterInset } = ctx;
187
+ const { registerOffFrame, unregisterOffFrame } = ctx;
188
188
  useLayoutEffect(() => {
189
- if (!inset) return;
190
- registerInset(id);
191
- return () => unregisterInset(id);
192
- }, [id, inset, registerInset, unregisterInset]);
189
+ if (flush) return;
190
+ registerOffFrame(id);
191
+ return () => unregisterOffFrame(id);
192
+ }, [id, flush, registerOffFrame, unregisterOffFrame]);
193
193
  }
194
194
 
195
195
  /* ── Development warnings ──────────────────────────────────────────────────── */
@@ -12,9 +12,12 @@
12
12
  &:where(:focus-visible) {
13
13
  border-radius: calc(0.07em * var(--radius-factor));
14
14
  outline-color: var(--focus-8);
15
- outline-width: 2px;
15
+ outline-width: var(--focus-ring-width);
16
16
  outline-style: solid;
17
- outline-offset: 2px;
17
+ outline-offset: var(--focus-ring-offset);
18
+ /* A wrapped link rings each line's fragment whole, not with square ends mid-word. */
19
+ -webkit-box-decoration-break: clone;
20
+ box-decoration-break: clone;
18
21
  }
19
22
 
20
23
  :where([data-accent-color]:not(.kui-theme)) &:where([data-accent-color='']) {
@@ -22,23 +25,22 @@
22
25
  }
23
26
  }
24
27
 
25
- /***************************************************************************************************
26
- * *
27
- * UNDERLINE *
28
- * *
29
- ***************************************************************************************************/
30
-
28
+ /* THE UNDERLINE IS ALWAYS THERE (from v2, 2026-11-03). Colour alone does not tell everyone which
29
+ words are a link (WCAG 1.4.1), and a hover-only underline cannot be found on a touch screen.
30
+ It rests as a quiet line in the link's own colour and darkens to the ink under the pointer. */
31
31
  .kui-Link {
32
32
  &:where(:any-link, button) {
33
- text-decoration-line: none;
33
+ text-decoration-line: underline;
34
34
  text-decoration-style: solid;
35
35
  text-decoration-thickness: min(2px, max(1px, 0.05em));
36
- text-underline-offset: calc(0.025em + 2px);
37
- text-decoration-color: var(--accent-a5);
36
+ /* Relative to the link's own type: a fixed distance crowds a descender large and floats small. */
37
+ text-underline-offset: 0.2em;
38
+ text-decoration-color: var(--accent-a6);
38
39
 
39
- /* Enhancement for bright colors */
40
- @supports (color: color-mix(in oklab, white, black)) {
41
- text-decoration-color: color-mix(in oklab, var(--accent-a5), var(--neutral-a6));
40
+ @media (hover: hover) {
41
+ &:where(:hover) {
42
+ text-decoration-color: currentcolor;
43
+ }
42
44
  }
43
45
 
44
46
  @media (pointer: coarse) {
@@ -48,41 +50,9 @@
48
50
  outline-offset: -0.6em;
49
51
  }
50
52
  }
51
-
52
- &:where(.kui-underline-auto) {
53
- @media (hover: hover) {
54
- &:where(:hover) {
55
- text-decoration-line: underline;
56
- }
57
- }
58
-
59
- :where([data-accent-color]:not(.kui-theme)) &:where([data-accent-color='']) {
60
- text-decoration-line: underline;
61
- text-decoration-color: var(--accent-a6);
62
-
63
- /* Enhancement for bright colors */
64
- @supports (color: color-mix(in oklab, white, black)) {
65
- text-decoration-color: color-mix(in oklab, var(--accent-a6), var(--neutral-a6));
66
- }
67
- }
68
- }
69
-
70
- &:where(.kui-underline-hover) {
71
- @media (hover: hover) {
72
- &:where(:hover) {
73
- text-decoration-line: underline;
74
- }
75
- }
76
- }
77
-
78
- &:where(.kui-underline-always) {
79
- text-decoration-line: underline;
80
- }
81
53
  }
82
54
  }
83
55
 
84
- /* Focus keeps the link's own underline setting; the focus outline marks focus. */
85
-
86
56
  /* Enhancement – hide underline for when Link's only child is a Code where underline is hard to see */
87
57
  .kui-Link:where(:has(.kui-Code:not(.kui-variant-ghost):only-child)) {
88
58
  text-decoration-color: transparent;
@@ -8,7 +8,6 @@ import { weightPropDef } from '../props/weight.prop.js';
8
8
  import type { PropDef } from '../props/prop-def.js';
9
9
 
10
10
  const sizes = ['1', '2', '3', '4', '5', '6', '7', '8', '9'] as const;
11
- const underline = ['auto', 'always', 'hover', 'none'] as const;
12
11
 
13
12
  const linkPropDefs = {
14
13
  ...asChildPropDef,
@@ -22,11 +21,9 @@ const linkPropDefs = {
22
21
  ...leadingTrimPropDef,
23
22
  ...truncatePropDef,
24
23
  ...textWrapPropDef,
25
- underline: { type: 'enum', className: 'kui-underline', values: underline, default: 'auto' },
26
24
  ...accentColorPropDef,
27
25
  } satisfies {
28
26
  size: PropDef<(typeof sizes)[number]>;
29
- underline: PropDef<(typeof underline)[number]>;
30
27
  };
31
28
 
32
29
  export { linkPropDefs };
@@ -26,8 +26,8 @@
26
26
  /* ── Frame ─────────────────────────────────────────────────────────────────── */
27
27
 
28
28
  .kui-ShellRoot {
29
- /* Read by inset panes. Declared here, so the documented override on the Root works. */
30
- --shell-inset-gap: var(--space-3);
29
+ /* The air around a pane pulled off the frame (`flush={false}`). Declared here, so the documented override on the Root works. */
30
+ --shell-gap: var(--space-3);
31
31
  /* Written inline by the Root while a Rail shows; stated here so a nested Shell never inherits its parent's. */
32
32
  --shell-rail-offset: 0px;
33
33
  /* How far the stuck header reaches down the screen while the page scrolls. Stated here so a nested Shell never inherits its parent's. */
@@ -938,68 +938,154 @@
938
938
  position: fixed;
939
939
  }
940
940
 
941
- /* ── Inset ─────────────────────────────────────────────────────────────────── */
941
+ /* ── Flush and off the frame (from v2, 0.33.0) ─────────────────────────────── */
942
942
 
943
943
  /*
944
- * The backdrop behind the middle row while any pane is inset. A grid item of
945
- * its own, so the header and the bottom row keep the page. `:has()` paints it
946
- * from the server markup, before any script; `data-has-inset` is the Root's
947
- * own record, which also covers a pane wrapped in another element.
944
+ * Every pane says one thing about itself: whether it joins the app frame (`flush`, the default)
945
+ * or is pulled off it as a card (`flush={false}`). Whether a card floats or sits on the Shell's
946
+ * background is not stated anywhere; it falls out of the content's own answer, here, so it is
947
+ * right at first paint:
948
+ *
949
+ * - A flush pane is level with the page: square, no fill, no shadow, and one hairline in
950
+ * `--color-border` on its inner edge. Each seam is drawn by exactly one pane, and the content
951
+ * draws none, so two neighbours never double a line.
952
+ * - With the content flush, a card floats over it: the content's grid area grows underneath.
953
+ * - With the content off the frame, nothing floats. The Shell paints its background and every
954
+ * pane, flush or not, sits on it; the content is a card, and a flush pane draws no hairline
955
+ * toward it, because a line beside a card's own edge is a second boundary.
948
956
  */
949
- .kui-ShellRoot:has(> [data-inset])::before,
950
- .kui-ShellRoot[data-has-inset]::before {
951
- content: '';
952
- grid-row: 2;
953
- grid-column: 1 / -1;
954
- background: var(--neutral-2);
957
+
958
+ .kui-ShellHeader[data-flush],
959
+ .kui-ShellPane[data-flush],
960
+ .kui-ShellContent[data-flush] {
961
+ border: 0 solid var(--color-border);
962
+ border-radius: 0;
963
+ }
964
+
965
+ .kui-ShellHeader[data-flush] {
966
+ border-block-end-width: 1px;
967
+ }
968
+
969
+ .kui-ShellRail[data-flush],
970
+ .kui-ShellPanel[data-flush],
971
+ .kui-ShellSidebar[data-flush] {
972
+ border-inline-end-width: 1px;
973
+ }
974
+
975
+ .kui-ShellInspector[data-flush] {
976
+ border-inline-start-width: 1px;
955
977
  }
956
978
 
957
- .kui-ShellPane[data-inset],
958
- .kui-ShellContent[data-inset] {
959
- margin: var(--shell-inset-gap);
979
+ .kui-ShellBottom[data-flush] {
980
+ border-block-start-width: 1px;
981
+ }
982
+
983
+ /* A seam needs something on the other side. Against a card content there is only the gap. The
984
+ Panel and the Rail face the content only when no flush pane stands between them. */
985
+ .kui-ShellRoot:has(> .kui-ShellContent:not([data-flush])) > .kui-ShellHeader[data-flush] {
986
+ border-block-end-width: 0;
987
+ }
988
+
989
+ .kui-ShellRoot:has(> .kui-ShellContent:not([data-flush])) > .kui-ShellSidebar[data-flush],
990
+ .kui-ShellRoot:has(> .kui-ShellContent:not([data-flush])):not(:has(> .kui-ShellSidebar[data-presentation='fixed'][data-mode]:not([data-mode='collapsed']))) > .kui-ShellPanel[data-flush],
991
+ .kui-ShellRoot:has(> .kui-ShellContent:not([data-flush])):not(:has(> .kui-ShellPanel[data-presentation='fixed'][data-mode]:not([data-mode='collapsed']), > .kui-ShellSidebar[data-presentation='fixed'][data-mode]:not([data-mode='collapsed']))) > .kui-ShellRail[data-flush] {
992
+ border-inline-end-width: 0;
993
+ }
994
+
995
+ .kui-ShellRoot:has(> .kui-ShellContent:not([data-flush])) > .kui-ShellInspector[data-flush] {
996
+ border-inline-start-width: 0;
997
+ }
998
+
999
+ .kui-ShellRoot:has(> .kui-ShellContent:not([data-flush])) > .kui-ShellBottom[data-flush] {
1000
+ border-block-start-width: 0;
1001
+ }
1002
+
1003
+ /* Off the frame: a card, with its own air on every side. */
1004
+ .kui-ShellHeader:not([data-flush]),
1005
+ .kui-ShellPane:not([data-flush]),
1006
+ .kui-ShellContent:not([data-flush]) {
1007
+ margin: var(--shell-gap);
960
1008
  border-radius: var(--radius-surface-1);
961
- background: var(--color-page);
1009
+ background-color: var(--color-page);
962
1010
  box-shadow: var(--surface-chrome);
963
1011
  }
964
1012
 
1013
+ /* A header card rests level with the panes below it, so its shadow falls behind them, not on them. */
1014
+ .kui-ShellHeader:not([data-flush]) {
1015
+ z-index: 1;
1016
+ }
1017
+
1018
+ /* With the content off the frame, the Shell paints the background the cards sit on. */
1019
+ .kui-ShellRoot:has(> .kui-ShellContent:not([data-flush])) {
1020
+ background-color: var(--neutral-2);
1021
+ }
1022
+
965
1023
  /*
966
- * Two inset panes side by side share one gap rather than doubling it: the
967
- * later pane in the row drops the margin on the side that meets the earlier
968
- * one. Only the pane right beside it counts, and only while it is shown in
969
- * the frame (the JS mirror's data-presentation and data-mode), so a closed,
970
- * hidden or floating pane never takes the gap away. Before hydration the
971
- * gap is doubled.
1024
+ * Two cards side by side share one gap rather than doubling it: the later card in the row drops
1025
+ * its margin on the side that meets the earlier one, so card to card and card to edge come out
1026
+ * equal. Only a pane shown in the frame counts.
972
1027
  */
973
- .kui-ShellRoot:has(> .kui-ShellRail[data-inset][data-presentation='fixed'][data-mode]:not([data-mode='collapsed'])) > .kui-ShellPanel[data-inset][data-presentation='fixed'],
974
- .kui-ShellRoot:has(> .kui-ShellPanel[data-inset][data-presentation='fixed'][data-mode]:not([data-mode='collapsed'])) > .kui-ShellSidebar[data-inset][data-presentation='fixed'],
975
- .kui-ShellRoot:has(> .kui-ShellRail[data-inset][data-presentation='fixed'][data-mode]:not([data-mode='collapsed'])):not(
976
- :has(> .kui-ShellPanel[data-presentation='fixed'][data-mode]:not([data-mode='collapsed']))
977
- )
978
- > .kui-ShellSidebar[data-inset][data-presentation='fixed'],
979
- .kui-ShellRoot:has(> .kui-ShellSidebar[data-inset][data-presentation='fixed'][data-mode]:not([data-mode='collapsed'])) > .kui-ShellContent[data-inset],
980
- .kui-ShellRoot:has(> .kui-ShellPanel[data-inset][data-presentation='fixed'][data-mode]:not([data-mode='collapsed'])):not(
981
- :has(> .kui-ShellSidebar[data-presentation='fixed'][data-mode]:not([data-mode='collapsed']))
982
- )
983
- > .kui-ShellContent[data-inset],
984
- .kui-ShellRoot:has(> .kui-ShellRail[data-inset][data-presentation='fixed'][data-mode]:not([data-mode='collapsed'])):not(
985
- :has(> .kui-ShellPanel[data-presentation='fixed'][data-mode]:not([data-mode='collapsed']), > .kui-ShellSidebar[data-presentation='fixed'][data-mode]:not([data-mode='collapsed']))
986
- )
987
- > .kui-ShellContent[data-inset],
988
- .kui-ShellRoot:has(> .kui-ShellContent[data-inset]) > .kui-ShellInspector[data-inset][data-presentation='fixed'] {
1028
+ .kui-ShellRoot:has(> .kui-ShellRail:not([data-flush])[data-presentation='fixed'][data-mode]:not([data-mode='collapsed'])) > .kui-ShellPanel:not([data-flush])[data-presentation='fixed'],
1029
+ .kui-ShellRoot:has(> .kui-ShellPanel:not([data-flush])[data-presentation='fixed'][data-mode]:not([data-mode='collapsed'])) > .kui-ShellSidebar:not([data-flush])[data-presentation='fixed'],
1030
+ .kui-ShellRoot:has(> .kui-ShellRail:not([data-flush])[data-presentation='fixed'][data-mode]:not([data-mode='collapsed'])):not(:has(> .kui-ShellPanel[data-presentation='fixed'][data-mode]:not([data-mode='collapsed']))) > .kui-ShellSidebar:not([data-flush])[data-presentation='fixed'],
1031
+ .kui-ShellRoot:has(> .kui-ShellSidebar:not([data-flush])[data-presentation='fixed'][data-mode]:not([data-mode='collapsed'])) > .kui-ShellContent:not([data-flush]),
1032
+ .kui-ShellRoot:has(> .kui-ShellPanel:not([data-flush])[data-presentation='fixed'][data-mode]:not([data-mode='collapsed'])):not(:has(> .kui-ShellSidebar[data-presentation='fixed'][data-mode]:not([data-mode='collapsed']))) > .kui-ShellContent:not([data-flush]),
1033
+ .kui-ShellRoot:has(> .kui-ShellRail:not([data-flush])[data-presentation='fixed'][data-mode]:not([data-mode='collapsed'])):not(:has(> .kui-ShellPanel[data-presentation='fixed'][data-mode]:not([data-mode='collapsed']), > .kui-ShellSidebar[data-presentation='fixed'][data-mode]:not([data-mode='collapsed']))) > .kui-ShellContent:not([data-flush]),
1034
+ .kui-ShellRoot:has(> .kui-ShellContent:not([data-flush])) > .kui-ShellInspector:not([data-flush])[data-presentation='fixed'] {
989
1035
  margin-inline-start: 0;
990
1036
  }
991
1037
 
992
- .kui-ShellRoot:has(
993
- > .kui-ShellRail[data-inset][data-presentation='fixed'][data-mode]:not([data-mode='collapsed']),
994
- > .kui-ShellPanel[data-inset][data-presentation='fixed'][data-mode]:not([data-mode='collapsed']),
995
- > .kui-ShellSidebar[data-inset][data-presentation='fixed'][data-mode]:not([data-mode='collapsed']),
996
- > .kui-ShellContent[data-inset],
997
- > .kui-ShellInspector[data-inset][data-presentation='fixed'][data-mode]:not([data-mode='collapsed'])
998
- )
999
- > .kui-ShellBottom[data-inset] {
1038
+ .kui-ShellRoot:has(> .kui-ShellHeader:not([data-flush])) > :is(.kui-ShellPane:not(.kui-ShellBottom), .kui-ShellContent):not([data-flush]),
1039
+ .kui-ShellRoot:has(> :is(.kui-ShellRail, .kui-ShellPanel, .kui-ShellSidebar, .kui-ShellInspector):not([data-flush])[data-presentation='fixed'][data-mode]:not([data-mode='collapsed']), > .kui-ShellContent:not([data-flush])) > .kui-ShellBottom:not([data-flush]) {
1000
1040
  margin-block-start: 0;
1001
1041
  }
1002
1042
 
1043
+ /* A card content pays no air toward a flush side pane in the frame: the pane's padding is the
1044
+ air. Toward a flush header it keeps its gap, since a header's row has no padding below it. */
1045
+ .kui-ShellRoot:has(> .kui-ShellSidebar[data-flush][data-presentation='fixed'][data-mode]:not([data-mode='collapsed'])) > .kui-ShellContent:not([data-flush]),
1046
+ .kui-ShellRoot:has(> .kui-ShellPanel[data-flush][data-presentation='fixed'][data-mode]:not([data-mode='collapsed'])):not(:has(> .kui-ShellSidebar[data-presentation='fixed'][data-mode]:not([data-mode='collapsed']))) > .kui-ShellContent:not([data-flush]),
1047
+ .kui-ShellRoot:has(> .kui-ShellRail[data-flush][data-presentation='fixed'][data-mode]:not([data-mode='collapsed'])):not(:has(> .kui-ShellPanel[data-presentation='fixed'][data-mode]:not([data-mode='collapsed']), > .kui-ShellSidebar[data-presentation='fixed'][data-mode]:not([data-mode='collapsed']))) > .kui-ShellContent:not([data-flush]) {
1048
+ margin-inline-start: 0;
1049
+ }
1050
+
1051
+ .kui-ShellRoot:has(> .kui-ShellInspector[data-flush][data-presentation='fixed'][data-mode]:not([data-mode='collapsed'])) > .kui-ShellContent:not([data-flush]) {
1052
+ margin-inline-end: 0;
1053
+ }
1054
+
1055
+ .kui-ShellRoot:has(> .kui-ShellBottom[data-flush][data-presentation='fixed'][data-mode]:not([data-mode='collapsed'])) > .kui-ShellContent:not([data-flush]) {
1056
+ margin-block-end: 0;
1057
+ }
1058
+
1059
+ /*
1060
+ * Floating: with the content flush, a card is over it, and the content's grid area grows to the
1061
+ * card's own line so the content runs underneath. It grows only on the sides something floats
1062
+ * on. The Rail and the Panel float over the content only when no flush pane stands between.
1063
+ * The panes already sit above the content (`z-index` 1 against the content's isolated layer).
1064
+ */
1065
+ .kui-ShellRoot:has(> .kui-ShellSidebar:not([data-flush])) > .kui-ShellContent[data-flush] {
1066
+ grid-column-start: sidebar-start;
1067
+ }
1068
+
1069
+ .kui-ShellRoot:has(> .kui-ShellPanel:not([data-flush])):not(:has(> .kui-ShellSidebar[data-flush])) > .kui-ShellContent[data-flush] {
1070
+ grid-column-start: panel-start;
1071
+ }
1072
+
1073
+ .kui-ShellRoot:has(> .kui-ShellRail:not([data-flush])):not(:has(> .kui-ShellPanel[data-flush], > .kui-ShellSidebar[data-flush])) > .kui-ShellContent[data-flush] {
1074
+ grid-column-start: rail-start;
1075
+ }
1076
+
1077
+ .kui-ShellRoot:has(> .kui-ShellInspector:not([data-flush])) > .kui-ShellContent[data-flush] {
1078
+ grid-column-end: inspector-end;
1079
+ }
1080
+
1081
+ .kui-ShellRoot:has(> .kui-ShellHeader:not([data-flush])) > .kui-ShellContent[data-flush] {
1082
+ grid-row-start: header-start;
1083
+ }
1084
+
1085
+ .kui-ShellRoot:has(> .kui-ShellBottom:not([data-flush])) > .kui-ShellContent[data-flush] {
1086
+ grid-row-end: bottom-end;
1087
+ }
1088
+
1003
1089
  /* ── On a phone, the page scrolls (0.27.0) ────────────────────────────────── */
1004
1090
 
1005
1091
  /*