@flamingo-stack/openframe-frontend-core 0.0.702 → 0.0.703-snapshot.20261006080901

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 (341) hide show
  1. package/dist/{chunk-CYYTD5ZK.cjs → chunk-262YQFOS.cjs} +47 -47
  2. package/dist/{chunk-SAA7B3DA.js → chunk-2G546OND.js} +500 -67
  3. package/dist/{chunk-6JPQDYYY.js → chunk-2JDVL7UV.js} +2614 -2001
  4. package/dist/{chunk-ASN65P3F.cjs → chunk-4DQMTBMK.cjs} +15 -15
  5. package/dist/{chunk-CZ34HXDW.js → chunk-4KGXLVCF.js} +686 -725
  6. package/dist/{chunk-TCZCMD5Q.js → chunk-5HBHO5TB.js} +1 -1
  7. package/dist/{chunk-446KS5BG.js → chunk-5QJDM6UV.js} +5 -5
  8. package/dist/{chunk-UJJWTJ6S.js → chunk-6WQIUQUC.js} +30 -16
  9. package/dist/{chunk-YR6JPJF4.js → chunk-6XIF2Z7I.js} +4 -4
  10. package/dist/{chunk-YGRHITPY.cjs → chunk-7JIL3WOH.cjs} +24 -24
  11. package/dist/{chunk-RS7HWAYX.js → chunk-7LFIKJX2.js} +3 -3
  12. package/dist/{chunk-4OGAXAEG.cjs → chunk-ABU3TGXA.cjs} +3 -3
  13. package/dist/{chunk-3WSFIV5G.cjs → chunk-AMYY3PNL.cjs} +69 -55
  14. package/dist/{chunk-BRXOGCH3.cjs → chunk-BIZNSF3U.cjs} +3 -3
  15. package/dist/{chunk-2A4XES7R.cjs → chunk-BM5MVGH3.cjs} +3 -3
  16. package/dist/{chunk-IIMICN7L.cjs → chunk-C3BWIU7R.cjs} +4 -44
  17. package/dist/{chunk-LZNJH23A.cjs → chunk-C7XGRLT5.cjs} +12 -12
  18. package/dist/{chunk-6YCXA7CN.js → chunk-CH5232HV.js} +20 -19
  19. package/dist/{chunk-UIBSSVON.cjs → chunk-D7BTSVMS.cjs} +2 -2
  20. package/dist/{chunk-BO5ZHDA4.js → chunk-ERCV6HHJ.js} +7 -7
  21. package/dist/{chunk-5V6O73EH.js → chunk-FLKJYMVB.js} +3 -3
  22. package/dist/{chunk-Z5HDCZAS.js → chunk-FXENTYE5.js} +15 -15
  23. package/dist/{chunk-HIXGAY2L.cjs → chunk-HFJW24JJ.cjs} +121 -121
  24. package/dist/{chunk-HPJ4XS2L.js → chunk-HJAYVKWQ.js} +24 -24
  25. package/dist/{chunk-PLK6GHN7.js → chunk-I7DFUQMN.js} +10 -10
  26. package/dist/{chunk-KJ5LWATV.js → chunk-IHU5ANUY.js} +7 -7
  27. package/dist/{chunk-AEQANLBW.cjs → chunk-IZGDG5X6.cjs} +505 -72
  28. package/dist/{chunk-2V4Z44G6.js → chunk-JEYRXT5L.js} +17 -17
  29. package/dist/{chunk-B3LZJ6J3.cjs → chunk-L3IC42IF.cjs} +32 -32
  30. package/dist/{chunk-RTGPIHVO.cjs → chunk-LDPEQGKT.cjs} +2243 -1630
  31. package/dist/{chunk-FD4DBTFO.cjs → chunk-LTSTC3N5.cjs} +1253 -1292
  32. package/dist/{chunk-OGLCD3UL.js → chunk-MFFCUVWG.js} +6 -6
  33. package/dist/{chunk-3L7KCOGO.cjs → chunk-MGGGBHYD.cjs} +30 -30
  34. package/dist/{chunk-QFW3RUZS.cjs → chunk-MI3JUJ75.cjs} +33 -33
  35. package/dist/{chunk-EMCQGFXD.cjs → chunk-MMOODW57.cjs} +28 -27
  36. package/dist/{chunk-Q76ZTHNV.js → chunk-MP2C3LJ4.js} +1 -1
  37. package/dist/{chunk-E3DH543A.cjs → chunk-N3TO7JV3.cjs} +98 -98
  38. package/dist/{chunk-2T6QWNXU.js → chunk-NDESEPW5.js} +99 -11
  39. package/dist/{chunk-ETFFEA3J.js → chunk-NRLJUBCS.js} +7 -7
  40. package/dist/{chunk-HUOLB7ZN.cjs → chunk-OHFS7VOU.cjs} +9 -9
  41. package/dist/{chunk-MWUBBBWZ.js → chunk-QVSFBSWV.js} +10 -10
  42. package/dist/{chunk-MDBHZBW7.cjs → chunk-RKV5B7EU.cjs} +92 -4
  43. package/dist/{chunk-3G76LRGL.cjs → chunk-SYXQLETR.cjs} +29 -29
  44. package/dist/{chunk-FHM7GD5B.cjs → chunk-UK62YTH6.cjs} +28 -14
  45. package/dist/{chunk-HUMWQMCU.js → chunk-UT4YHQZW.js} +3 -3
  46. package/dist/{chunk-NGJCWEYX.cjs → chunk-VHCACDKP.cjs} +46 -46
  47. package/dist/{chunk-5FFNNJM7.js → chunk-VR2ZLFCP.js} +1 -1
  48. package/dist/{chunk-IZKOQVXO.js → chunk-VTASHWER.js} +14 -14
  49. package/dist/{chunk-64O4L7WN.js → chunk-WUJNYGO2.js} +11 -51
  50. package/dist/{chunk-JOY6HVPV.js → chunk-XATTBO5X.js} +25 -11
  51. package/dist/{chunk-L7KZA7ZD.cjs → chunk-XIFOBQRQ.cjs} +6 -6
  52. package/dist/{chunk-CXDJUKC6.cjs → chunk-XJKZ4IKT.cjs} +4 -4
  53. package/dist/{chunk-XCIFHW4E.cjs → chunk-XOYH2YQE.cjs} +2 -2
  54. package/dist/{chunk-HYFLTFFB.js → chunk-ZQFZSFQI.js} +2 -2
  55. package/dist/components/case-studies/index.cjs +24 -24
  56. package/dist/components/case-studies/index.js +10 -10
  57. package/dist/components/chat/chat-archive-page.d.ts +3 -3
  58. package/dist/components/chat/chat-archive-page.d.ts.map +1 -1
  59. package/dist/components/chat/chat-nav-sidebar.d.ts +4 -0
  60. package/dist/components/chat/chat-nav-sidebar.d.ts.map +1 -1
  61. package/dist/components/chat/chat-panel-header.d.ts +3 -2
  62. package/dist/components/chat/chat-panel-header.d.ts.map +1 -1
  63. package/dist/components/chat/embeddable-chat.d.ts +36 -2
  64. package/dist/components/chat/embeddable-chat.d.ts.map +1 -1
  65. package/dist/components/chat/index.cjs +14 -6
  66. package/dist/components/chat/index.d.ts +4 -1
  67. package/dist/components/chat/index.d.ts.map +1 -1
  68. package/dist/components/chat/index.js +13 -5
  69. package/dist/components/chat/mingo-archive-list.d.ts +17 -0
  70. package/dist/components/chat/mingo-archive-list.d.ts.map +1 -0
  71. package/dist/components/chat/mingo-chat-header.d.ts +31 -0
  72. package/dist/components/chat/mingo-chat-header.d.ts.map +1 -0
  73. package/dist/components/chat/mingo-chat-rail.d.ts +54 -0
  74. package/dist/components/chat/mingo-chat-rail.d.ts.map +1 -0
  75. package/dist/components/chat/model-display.d.ts.map +1 -1
  76. package/dist/components/contact/contact-form.d.ts.map +1 -1
  77. package/dist/components/contact/index.cjs +11 -11
  78. package/dist/components/contact/index.js +10 -10
  79. package/dist/components/content-loading-container.d.ts +1 -1
  80. package/dist/components/content-loading-container.d.ts.map +1 -1
  81. package/dist/components/docs/index.cjs +14 -14
  82. package/dist/components/docs/index.js +13 -13
  83. package/dist/components/docs/skeletons.d.ts.map +1 -1
  84. package/dist/components/embeds/index.cjs +11 -11
  85. package/dist/components/embeds/index.js +10 -10
  86. package/dist/components/faq/index.cjs +12 -12
  87. package/dist/components/faq/index.js +11 -11
  88. package/dist/components/features/figma-prototype-viewer.d.ts.map +1 -1
  89. package/dist/components/features/index.cjs +10 -10
  90. package/dist/components/features/index.js +9 -9
  91. package/dist/components/features/media-gallery-manager.d.ts.map +1 -1
  92. package/dist/components/features/parallax-image-showcase.d.ts.map +1 -1
  93. package/dist/components/features/policy-configuration-panel.d.ts.map +1 -1
  94. package/dist/components/features/section-selector.d.ts.map +1 -1
  95. package/dist/components/help-center-pages/index.cjs +119 -119
  96. package/dist/components/help-center-pages/index.js +39 -39
  97. package/dist/components/help-center-pages/trust-center-sections.d.ts +2 -2
  98. package/dist/components/help-center-pages/trust-center-sections.d.ts.map +1 -1
  99. package/dist/components/index.cjs +94 -86
  100. package/dist/components/index.js +32 -24
  101. package/dist/components/layout/article-detail-layout.d.ts +1 -1
  102. package/dist/components/layout/article-detail-layout.d.ts.map +1 -1
  103. package/dist/components/layout/page-container.d.ts.map +1 -1
  104. package/dist/components/layout/title-block.d.ts +2 -2
  105. package/dist/components/layout/title-block.d.ts.map +1 -1
  106. package/dist/components/loading/page-layout-skeleton.d.ts.map +1 -1
  107. package/dist/components/loading/unified-skeleton.d.ts.map +1 -1
  108. package/dist/components/meeting-scheduler/booking-form.d.ts +4 -4
  109. package/dist/components/meeting-scheduler/booking-form.d.ts.map +1 -1
  110. package/dist/components/meeting-scheduler/context-panel.d.ts.map +1 -1
  111. package/dist/components/meeting-scheduler/index.cjs +127 -127
  112. package/dist/components/meeting-scheduler/index.d.ts +2 -2
  113. package/dist/components/meeting-scheduler/index.d.ts.map +1 -1
  114. package/dist/components/meeting-scheduler/index.js +50 -50
  115. package/dist/components/navigation/app-header.d.ts +4 -0
  116. package/dist/components/navigation/app-header.d.ts.map +1 -1
  117. package/dist/components/navigation/app-layout-drawer.d.ts.map +1 -1
  118. package/dist/components/navigation/app-layout-side-panel.d.ts +142 -0
  119. package/dist/components/navigation/app-layout-side-panel.d.ts.map +1 -0
  120. package/dist/components/navigation/app-layout.d.ts +11 -1
  121. package/dist/components/navigation/app-layout.d.ts.map +1 -1
  122. package/dist/components/navigation/header-mingo-button.d.ts +4 -1
  123. package/dist/components/navigation/header-mingo-button.d.ts.map +1 -1
  124. package/dist/components/navigation/index.cjs +13 -13
  125. package/dist/components/navigation/index.d.ts +1 -0
  126. package/dist/components/navigation/index.d.ts.map +1 -1
  127. package/dist/components/navigation/index.js +12 -12
  128. package/dist/components/navigation/navigation-sidebar.d.ts +8 -1
  129. package/dist/components/navigation/navigation-sidebar.d.ts.map +1 -1
  130. package/dist/components/navigation/sliding-sidebar.d.ts.map +1 -1
  131. package/dist/components/onboarding-guides/index.cjs +14 -14
  132. package/dist/components/onboarding-guides/index.js +13 -13
  133. package/dist/components/persistent-filter-controls.d.ts.map +1 -1
  134. package/dist/components/related-content/index.cjs +7 -7
  135. package/dist/components/related-content/index.js +6 -6
  136. package/dist/components/shared/detail-page-skeleton.d.ts.map +1 -1
  137. package/dist/components/tickets/help-center-create-form.d.ts +4 -4
  138. package/dist/components/tickets/index.cjs +15 -15
  139. package/dist/components/tickets/index.js +14 -14
  140. package/dist/components/ui/announcement-bar-view.d.ts.map +1 -1
  141. package/dist/components/ui/breadcrumb.d.ts.map +1 -1
  142. package/dist/components/ui/checkbox-block.d.ts.map +1 -1
  143. package/dist/components/ui/dashboard-info-card.d.ts +1 -1
  144. package/dist/components/ui/dashboard-info-card.d.ts.map +1 -1
  145. package/dist/components/ui/data-table/data-table-body.d.ts +2 -2
  146. package/dist/components/ui/data-table/data-table-skeleton.d.ts +2 -2
  147. package/dist/components/ui/data-table/data-table-skeleton.d.ts.map +1 -1
  148. package/dist/components/ui/data-table/utils.d.ts +2 -2
  149. package/dist/components/ui/dialog.d.ts.map +1 -1
  150. package/dist/components/ui/drawer.d.ts +7 -3
  151. package/dist/components/ui/drawer.d.ts.map +1 -1
  152. package/dist/components/ui/entity-image.d.ts +2 -2
  153. package/dist/components/ui/file-manager/index.cjs +36 -36
  154. package/dist/components/ui/file-manager/index.js +3 -3
  155. package/dist/components/ui/filter-modal.d.ts.map +1 -1
  156. package/dist/components/ui/index.cjs +18 -10
  157. package/dist/components/ui/index.js +17 -9
  158. package/dist/components/ui/info-card-row.d.ts.map +1 -1
  159. package/dist/components/ui/menubar.d.ts +1 -1
  160. package/dist/components/ui/menubar.d.ts.map +1 -1
  161. package/dist/components/ui/modal-v2.d.ts.map +1 -1
  162. package/dist/components/ui/modal.d.ts.map +1 -1
  163. package/dist/components/ui/no-data/no-data-actions.d.ts.map +1 -1
  164. package/dist/components/ui/no-data/no-data-styles.d.ts +1 -1
  165. package/dist/components/ui/no-data/no-data-styles.d.ts.map +1 -1
  166. package/dist/components/ui/page-actions.d.ts.map +1 -1
  167. package/dist/components/ui/panel-resize-handle.d.ts +25 -0
  168. package/dist/components/ui/panel-resize-handle.d.ts.map +1 -0
  169. package/dist/components/ui/sheet.d.ts.map +1 -1
  170. package/dist/components/ui/table/table-skeleton.d.ts +1 -1
  171. package/dist/components/ui/table/table-skeleton.d.ts.map +1 -1
  172. package/dist/hooks/index.cjs +23 -9
  173. package/dist/hooks/index.js +24 -10
  174. package/dist/hooks/ui/index.d.ts +1 -0
  175. package/dist/hooks/ui/index.d.ts.map +1 -1
  176. package/dist/hooks/ui/use-content-breakpoint.d.ts +32 -0
  177. package/dist/hooks/ui/use-content-breakpoint.d.ts.map +1 -0
  178. package/dist/hooks/ui/use-isomorphic-layout-effect.d.ts +2 -2
  179. package/dist/hooks/ui/use-isomorphic-layout-effect.d.ts.map +1 -1
  180. package/dist/hooks/ui/use-media-query.d.ts.map +1 -1
  181. package/dist/hooks/ui/use-resizable-panel-size.d.ts +46 -0
  182. package/dist/hooks/ui/use-resizable-panel-size.d.ts.map +1 -0
  183. package/dist/index.cjs +39 -17
  184. package/dist/index.js +41 -19
  185. package/dist/styles/layout-steps.d.ts +30 -0
  186. package/dist/styles/layout-steps.d.ts.map +1 -0
  187. package/dist/tailwind.config.cjs +36 -11
  188. package/dist/tailwind.config.js +36 -11
  189. package/eslint-config/README.md +9 -0
  190. package/eslint-config/base.js +17 -1
  191. package/eslint-config/layout-variants.js +57 -0
  192. package/package.json +3 -1
  193. package/src/ODS_TOKEN_RULES.md +40 -0
  194. package/src/components/chat/chat-archive-page.tsx +9 -7
  195. package/src/components/chat/chat-nav-sidebar.tsx +10 -4
  196. package/src/components/chat/chat-panel-header.tsx +8 -5
  197. package/src/components/chat/embeddable-chat.tsx +686 -494
  198. package/src/components/chat/index.ts +4 -0
  199. package/src/components/chat/mingo-archive-list.tsx +108 -0
  200. package/src/components/chat/mingo-chat-header.tsx +104 -0
  201. package/src/components/chat/mingo-chat-rail.tsx +361 -0
  202. package/src/components/chat/model-display.tsx +8 -1
  203. package/src/components/contact/contact-form.tsx +11 -9
  204. package/src/components/content-loading-container.tsx +4 -2
  205. package/src/components/docs/doc-viewer.tsx +7 -7
  206. package/src/components/docs/skeletons.tsx +7 -4
  207. package/src/components/dynamic-skeleton.tsx +1 -1
  208. package/src/components/embeds/claude-embed.tsx +1 -1
  209. package/src/components/embeds/embed-viewer-frame.tsx +4 -4
  210. package/src/components/embeds/figma-embed.tsx +2 -2
  211. package/src/components/embeds/google-sheets-viewer.tsx +1 -1
  212. package/src/components/embeds/pdf-viewer.tsx +3 -3
  213. package/src/components/empty-state.tsx +6 -6
  214. package/src/components/faq/faq-section.tsx +2 -2
  215. package/src/components/faq-accordion.tsx +1 -1
  216. package/src/components/features/board/board-column-header.tsx +1 -1
  217. package/src/components/features/command-box.tsx +3 -3
  218. package/src/components/features/entity-video-section.tsx +2 -2
  219. package/src/components/features/figma-prototype-viewer.tsx +4 -1
  220. package/src/components/features/media-gallery-manager.tsx +3 -1
  221. package/src/components/features/parallax-image-showcase.tsx +9 -6
  222. package/src/components/features/policy-configuration-panel.tsx +9 -7
  223. package/src/components/features/provider-button.tsx +1 -1
  224. package/src/components/features/section-selector.tsx +11 -6
  225. package/src/components/features/select-button.tsx +4 -4
  226. package/src/components/features/seo-editor-preview.tsx +2 -2
  227. package/src/components/features/video-ratio-tabs.tsx +3 -3
  228. package/src/components/features/waitlist-form.tsx +1 -1
  229. package/src/components/help-center-pages/trust-center-page.tsx +1 -1
  230. package/src/components/help-center-pages/trust-center-sections.tsx +14 -14
  231. package/src/components/icon-display.tsx +1 -1
  232. package/src/components/layout/article-detail-layout.tsx +4 -2
  233. package/src/components/layout/list-page-layout.tsx +2 -2
  234. package/src/components/layout/page-container.tsx +26 -14
  235. package/src/components/layout/page-heading.tsx +1 -1
  236. package/src/components/layout/page-layout.tsx +1 -1
  237. package/src/components/layout/title-block.tsx +13 -13
  238. package/src/components/loading/card-skeleton.tsx +11 -11
  239. package/src/components/loading/category-vendor-selector-skeleton.tsx +1 -1
  240. package/src/components/loading/content-skeleton.tsx +6 -6
  241. package/src/components/loading/device-card-skeleton.tsx +1 -1
  242. package/src/components/loading/margin-report-skeleton.tsx +7 -7
  243. package/src/components/loading/msp-profile-form-skeleton.tsx +3 -3
  244. package/src/components/loading/organization-card-skeleton.tsx +2 -2
  245. package/src/components/loading/page-layout-skeleton.tsx +80 -68
  246. package/src/components/loading/unified-skeleton.tsx +16 -6
  247. package/src/components/media-carousel.tsx +3 -3
  248. package/src/components/meeting-scheduler/booking-form.tsx +9 -8
  249. package/src/components/meeting-scheduler/context-panel.tsx +8 -6
  250. package/src/components/meeting-scheduler/directory.tsx +4 -4
  251. package/src/components/meeting-scheduler/index.tsx +15 -15
  252. package/src/components/meeting-scheduler/slot-picker.tsx +12 -12
  253. package/src/components/navigation/app-header.tsx +6 -0
  254. package/src/components/navigation/app-layout-drawer.tsx +14 -237
  255. package/src/components/navigation/app-layout-side-panel.tsx +594 -0
  256. package/src/components/navigation/app-layout.tsx +69 -4
  257. package/src/components/navigation/header-mingo-button.tsx +13 -3
  258. package/src/components/navigation/index.ts +5 -0
  259. package/src/components/navigation/navigation-sidebar.tsx +17 -3
  260. package/src/components/navigation/sliding-sidebar.tsx +2 -1
  261. package/src/components/pagination.tsx +3 -3
  262. package/src/components/persistent-filter-controls.tsx +6 -2
  263. package/src/components/platform/ScriptArguments.tsx +1 -1
  264. package/src/components/platform/ScriptInfoSection.tsx +4 -4
  265. package/src/components/shared/article-author-byline.tsx +1 -1
  266. package/src/components/shared/delivery/delivery-lists.tsx +2 -2
  267. package/src/components/shared/delivery/delivery-row.tsx +7 -7
  268. package/src/components/shared/delivery/delivery-table.tsx +3 -3
  269. package/src/components/shared/detail-page-skeleton.tsx +11 -5
  270. package/src/components/shared/dev-section/dev-card-row.tsx +6 -6
  271. package/src/components/shared/dev-section/dev-section-view.tsx +1 -1
  272. package/src/components/shared/product-release/product-release-card-skeleton.tsx +8 -8
  273. package/src/components/shared/product-release/product-release-card.tsx +9 -9
  274. package/src/components/shared/product-release/product-releases-view.tsx +1 -1
  275. package/src/components/shared/product-release/release-detail-page.tsx +5 -5
  276. package/src/components/shared/roadmap/roadmap-grid-skeleton.tsx +1 -1
  277. package/src/components/shared/roadmap/roadmap-grid.tsx +3 -3
  278. package/src/components/tickets/help-center-card.tsx +1 -1
  279. package/src/components/tickets/help-center-create-form.tsx +12 -12
  280. package/src/components/ui/announcement-bar-view.tsx +2 -10
  281. package/src/components/ui/benefit-card.tsx +18 -18
  282. package/src/components/ui/brand-association-grid.tsx +4 -4
  283. package/src/components/ui/breadcrumb.tsx +4 -1
  284. package/src/components/ui/card.tsx +1 -1
  285. package/src/components/ui/checkbox-block.tsx +9 -7
  286. package/src/components/ui/content-loader.tsx +3 -3
  287. package/src/components/ui/cursor-pagination.tsx +3 -3
  288. package/src/components/ui/dashboard-info-card.tsx +13 -9
  289. package/src/components/ui/data-attribution.tsx +2 -2
  290. package/src/components/ui/data-table/data-table-body.tsx +2 -2
  291. package/src/components/ui/data-table/data-table-header.tsx +15 -15
  292. package/src/components/ui/data-table/data-table-skeleton.tsx +6 -6
  293. package/src/components/ui/data-table/utils.ts +5 -5
  294. package/src/components/ui/dialog.tsx +4 -1
  295. package/src/components/ui/drawer.tsx +43 -189
  296. package/src/components/ui/duration-input.tsx +1 -1
  297. package/src/components/ui/entity-image.tsx +3 -3
  298. package/src/components/ui/feature-card.tsx +10 -10
  299. package/src/components/ui/file-manager/file-manager-action-bar.tsx +1 -1
  300. package/src/components/ui/file-manager/file-manager.tsx +1 -1
  301. package/src/components/ui/filter-modal.tsx +8 -1
  302. package/src/components/ui/highlight-card.tsx +7 -7
  303. package/src/components/ui/info-card-row.tsx +10 -6
  304. package/src/components/ui/modal-v2.tsx +7 -2
  305. package/src/components/ui/modal.tsx +3 -2
  306. package/src/components/ui/no-data/no-data-actions.tsx +10 -4
  307. package/src/components/ui/no-data/no-data-styles.ts +1 -1
  308. package/src/components/ui/no-data/no-data.tsx +1 -1
  309. package/src/components/ui/organization-card.tsx +1 -1
  310. package/src/components/ui/page-actions.tsx +34 -5
  311. package/src/components/ui/panel-resize-handle.tsx +184 -0
  312. package/src/components/ui/progress-bar.tsx +2 -2
  313. package/src/components/ui/query-report-table/query-report-table.tsx +1 -1
  314. package/src/components/ui/search-input.tsx +2 -2
  315. package/src/components/ui/service-card.tsx +2 -2
  316. package/src/components/ui/sheet.tsx +2 -1
  317. package/src/components/ui/skeleton.tsx +3 -3
  318. package/src/components/ui/stacked-rows-panel.tsx +4 -4
  319. package/src/components/ui/tab-navigation.tsx +2 -2
  320. package/src/components/ui/tab-selector.tsx +2 -2
  321. package/src/components/ui/table/table-header.tsx +3 -3
  322. package/src/components/ui/table/table-skeleton.tsx +3 -3
  323. package/src/components/ui/table/utils.ts +5 -5
  324. package/src/components/ui/tag-search-input.tsx +3 -3
  325. package/src/components/ui/tags-manager.tsx +5 -5
  326. package/src/components/ui/test-run.tsx +2 -2
  327. package/src/components/ui/ticket-info-section.tsx +1 -1
  328. package/src/components/ui/ticket-notes-section.tsx +1 -1
  329. package/src/components/ui/ticket-status-config-row.tsx +15 -15
  330. package/src/hooks/ui/index.ts +1 -0
  331. package/src/hooks/ui/use-content-breakpoint.ts +58 -0
  332. package/src/hooks/ui/use-media-query.ts +3 -2
  333. package/src/hooks/ui/use-resizable-panel-size.ts +114 -0
  334. package/src/styles/index.css +2 -0
  335. package/src/styles/layout-steps.ts +14 -0
  336. package/src/styles/ods-colors.css +15 -0
  337. package/src/styles/ods-content-area-tokens.css +27 -0
  338. package/src/styles/ods-content-area.css +31 -0
  339. package/src/styles/ods-effects.css +4 -2
  340. package/src/styles/ods-responsive-tokens.css +14 -4
  341. package/tailwind.config.ts +42 -7
@@ -355,7 +355,7 @@ function IconButtonsVariant({
355
355
  return (
356
356
  <>
357
357
  {/* Desktop: every action as an icon button + optional overflow menu */}
358
- <div className={cn('hidden items-center md:flex', ACTIONS_GAP, className)}>
358
+ <div className={cn('hidden items-center content-md:flex', ACTIONS_GAP, className)}>
359
359
  {selector}
360
360
  {loading ? (
361
361
  <ActionSkeletons actions={desktopActions} />
@@ -370,7 +370,7 @@ function IconButtonsVariant({
370
370
  </div>
371
371
 
372
372
  {/* Mobile: single icon button OR all actions merged into one "..." menu */}
373
- <div className={cn('flex md:hidden', className)}>
373
+ <div className={cn('flex content-md:hidden', className)}>
374
374
  {loading ? (
375
375
  <MobileTriggerSkeleton />
376
376
  ) : useSingleActionMobile && singleAction ? (
@@ -386,6 +386,12 @@ function IconButtonsVariant({
386
386
  /**
387
387
  * Primary buttons variant — primary + outline buttons on desktop,
388
388
  * fixed bottom bar on mobile.
389
+ *
390
+ * The bottom bar spans the WINDOW, so it stays on the viewport `md` step. A
391
+ * content area narrowed by a docked side panel is a third case: the window is
392
+ * wide (no bar) but the title row has no room for every labelled button, so the
393
+ * actions compact into the row instead. `md:content-max-md:` is exactly that case
394
+ * and never matches outside a content area.
389
395
  */
390
396
  function PrimaryButtonsVariant({
391
397
  actions,
@@ -407,7 +413,7 @@ function PrimaryButtonsVariant({
407
413
 
408
414
  return (
409
415
  <>
410
- <div className={cn('hidden items-center md:flex', ACTIONS_GAP, className)}>
416
+ <div className={cn('hidden items-center md:content-md:flex', ACTIONS_GAP, className)}>
411
417
  {loading ? (
412
418
  // No overflow trigger in this variant — an unknown action set settles
413
419
  // into a labelled button, not a square one.
@@ -419,6 +425,10 @@ function PrimaryButtonsVariant({
419
425
  )}
420
426
  </div>
421
427
 
428
+ <div className={cn('hidden items-center md:content-max-md:flex', ACTIONS_GAP, className)}>
429
+ {loading ? <MobileTriggerSkeleton /> : <CompactPrimaryActions actions={desktopActions} />}
430
+ </div>
431
+
422
432
  <MobileBottomActions actions={sortedActions} loading={loading} />
423
433
  </>
424
434
  );
@@ -449,7 +459,7 @@ function MenuPrimaryVariant({
449
459
 
450
460
  return (
451
461
  <>
452
- <div className={cn('hidden items-center md:flex', ACTIONS_GAP, className)}>
462
+ <div className={cn('hidden items-center content-md:flex', ACTIONS_GAP, className)}>
453
463
  {selector}
454
464
  {loading ? (
455
465
  <ActionSkeletons actions={desktopActions} />
@@ -465,7 +475,7 @@ function MenuPrimaryVariant({
465
475
  )}
466
476
  </div>
467
477
 
468
- <div className={cn('flex md:hidden', className)}>
478
+ <div className={cn('flex content-md:hidden', className)}>
469
479
  {loading ? (
470
480
  <MobileTriggerSkeleton />
471
481
  ) : hasMobileMenuItems || selector ? (
@@ -479,6 +489,25 @@ function MenuPrimaryVariant({
479
489
  );
480
490
  }
481
491
 
492
+ /**
493
+ * `primary-buttons` in a narrow content area of a wide window: the accent (and
494
+ * icon-only) actions stay buttons, the other labelled ones fold into one "..."
495
+ * menu — unless that menu would hold a single action, which stays a button.
496
+ */
497
+ function CompactPrimaryActions({ actions }: { actions: PageActionButton[] }) {
498
+ const foldable = actions.filter(action => action.variant !== 'accent' && !!action.label);
499
+ const fold = foldable.length > 1;
500
+ const inline = fold ? actions.filter(action => !foldable.includes(action)) : actions;
501
+ return (
502
+ <>
503
+ {fold && <ActionsMenuDropdown groups={[{ items: foldable.flatMap(actionToMenuItems) }]} />}
504
+ {inline.map((action, idx) => (
505
+ <React.Fragment key={`compact-${actionKey(action, idx)}`}>{renderActionButton(action)}</React.Fragment>
506
+ ))}
507
+ </>
508
+ );
509
+ }
510
+
482
511
  function MobileBottomActions({ actions, loading }: { actions: PageActionButton[]; loading?: boolean }) {
483
512
  return (
484
513
  <div
@@ -0,0 +1,184 @@
1
+ 'use client';
2
+
3
+ import { type KeyboardEvent, type PointerEvent, type RefObject, useEffect, useRef } from 'react';
4
+
5
+ import { cn } from '../../utils/cn';
6
+
7
+ /**
8
+ * The drag-to-resize handle of a side or edge panel, shared by `Drawer` and
9
+ * `AppLayoutDrawer`. A drag writes the panel's size to the DOM and reports it
10
+ * once, on release; arrow keys, Home and End report at once.
11
+ */
12
+
13
+ type PanelSide = 'right' | 'left' | 'top' | 'bottom';
14
+
15
+ const HORIZONTAL_SIDES: ReadonlySet<PanelSide> = new Set(['left', 'right']);
16
+
17
+ /** Ends a drawer resize drag: commits the size it reached and restores the
18
+ * page's cursor and text selection. No-op when no drag is in progress. */
19
+ function finishDrag(
20
+ startRef: RefObject<{ x: number; y: number; size: number } | null>,
21
+ dragSizeRef: RefObject<number | null>,
22
+ commit: (size: number) => void,
23
+ ): void {
24
+ if (!startRef.current) return;
25
+ startRef.current = null;
26
+ if (dragSizeRef.current !== null) commit(dragSizeRef.current);
27
+ dragSizeRef.current = null;
28
+ document.body.style.cursor = '';
29
+ document.body.style.userSelect = '';
30
+ }
31
+
32
+ export interface PanelResizeHandleProps {
33
+ side: PanelSide;
34
+ size: number;
35
+ minSize: number;
36
+ maxSize: number;
37
+ onSize: (next: number) => void;
38
+ /** Clamp a candidate size to the min/max and the container. */
39
+ clampSize: (next: number) => number;
40
+ /** The panel the size applies to — written directly while dragging. */
41
+ panelRef: RefObject<HTMLDivElement | null>;
42
+ /** `overlay` is the body-level `Drawer`'s handle, `inLayout` the wider one of
43
+ * `AppLayoutDrawer`. They differ in track width and grip colour only. */
44
+ variant: 'overlay' | 'inLayout';
45
+ ariaLabel?: string;
46
+ }
47
+
48
+ export function PanelResizeHandle({
49
+ side,
50
+ size,
51
+ minSize,
52
+ maxSize,
53
+ onSize,
54
+ clampSize,
55
+ panelRef,
56
+ variant,
57
+ ariaLabel,
58
+ }: PanelResizeHandleProps) {
59
+ const isHorizontal = HORIZONTAL_SIDES.has(side);
60
+ const startRef = useRef<{ x: number; y: number; size: number } | null>(null);
61
+ // Size reached by the drag in progress, committed to React state on release.
62
+ const dragSizeRef = useRef<number | null>(null);
63
+ const onSizeRef = useRef(onSize);
64
+ useEffect(() => {
65
+ onSizeRef.current = onSize;
66
+ }, [onSize]);
67
+ // The handle can unmount mid-drag (a persist-mode drawer closing), and then
68
+ // no pointer event ends the drag: end it here, or the panel keeps a width
69
+ // React state never received and the page keeps the resize cursor.
70
+ useEffect(() => () => finishDrag(startRef, dragSizeRef, onSizeRef.current), []);
71
+
72
+ const direction = side === 'right' || side === 'bottom' ? -1 : 1;
73
+
74
+ const handlePointerDown = (e: PointerEvent<HTMLDivElement>) => {
75
+ if (e.button !== 0 && e.pointerType === 'mouse') return;
76
+ e.preventDefault();
77
+ startRef.current = { x: e.clientX, y: e.clientY, size };
78
+ e.currentTarget.setPointerCapture(e.pointerId);
79
+ document.body.style.cursor = isHorizontal ? 'col-resize' : 'row-resize';
80
+ document.body.style.userSelect = 'none';
81
+ };
82
+
83
+ // The drag writes the panel's size straight to the DOM and commits it to
84
+ // state once, on release. Committing every pointermove re-rendered the
85
+ // drawer per event — ~16% of a drag's CPU in WebKit on top of the reflow the
86
+ // resize itself costs. ResizeObserver consumers inside the panel still see
87
+ // every change. A re-render of the drawer mid-drag (e.g. a streamed chunk)
88
+ // does not undo the write: React diffs against its previous render, where
89
+ // the size is unchanged, so it leaves the style alone.
90
+ const handlePointerMove = (e: PointerEvent<HTMLDivElement>) => {
91
+ const start = startRef.current;
92
+ const panel = panelRef.current;
93
+ if (!start || !panel) return;
94
+ const delta = isHorizontal ? e.clientX - start.x : e.clientY - start.y;
95
+ const next = clampSize(start.size + delta * direction);
96
+ dragSizeRef.current = next;
97
+ panel.style[isHorizontal ? 'width' : 'height'] = `${next}px`;
98
+ e.currentTarget.setAttribute('aria-valuenow', String(Math.round(next)));
99
+ };
100
+
101
+ const endDrag = (e: PointerEvent<HTMLDivElement>) => {
102
+ if (!startRef.current) return;
103
+ finishDrag(startRef, dragSizeRef, onSize);
104
+ try {
105
+ e.currentTarget.releasePointerCapture(e.pointerId);
106
+ } catch {
107
+ // ignore — pointer may already be released
108
+ }
109
+ };
110
+
111
+ const handleKeyDown = (e: KeyboardEvent<HTMLDivElement>) => {
112
+ const step = e.shiftKey ? 40 : 16;
113
+ if (isHorizontal) {
114
+ if (e.key === 'ArrowLeft') {
115
+ e.preventDefault();
116
+ onSize(size + step * (side === 'right' ? 1 : -1));
117
+ } else if (e.key === 'ArrowRight') {
118
+ e.preventDefault();
119
+ onSize(size + step * (side === 'right' ? -1 : 1));
120
+ }
121
+ } else {
122
+ if (e.key === 'ArrowUp') {
123
+ e.preventDefault();
124
+ onSize(size + step * (side === 'bottom' ? 1 : -1));
125
+ } else if (e.key === 'ArrowDown') {
126
+ e.preventDefault();
127
+ onSize(size + step * (side === 'bottom' ? -1 : 1));
128
+ }
129
+ }
130
+ if (e.key === 'Home') {
131
+ e.preventDefault();
132
+ onSize(minSize);
133
+ } else if (e.key === 'End') {
134
+ e.preventDefault();
135
+ onSize(maxSize);
136
+ }
137
+ };
138
+
139
+ // The handle is a SIBLING of the panel (a child of the dialog content), so the
140
+ // panel can clip its children without clipping the handle. The content
141
+ // wrapper pads the panel by 16px wherever the handle shows, which is what
142
+ // `top-4 bottom-4` (or `left-4 right-4`) lines the track up with.
143
+ const track = variant === 'inLayout' ? { w: 'w-6', h: 'h-6' } : { w: 'w-3', h: 'h-3' };
144
+ const trackPosition =
145
+ side === 'right'
146
+ ? `right-full top-4 bottom-4 ${track.w} items-center justify-end pr-1`
147
+ : side === 'left'
148
+ ? `left-full top-4 bottom-4 ${track.w} items-center justify-start pl-1`
149
+ : side === 'bottom'
150
+ ? `bottom-full left-4 right-4 ${track.h} justify-center items-end pb-1`
151
+ : `top-full left-4 right-4 ${track.h} justify-center items-start pt-1`;
152
+
153
+ const cursorClass = isHorizontal ? 'cursor-col-resize' : 'cursor-row-resize';
154
+ const gripClass = isHorizontal ? 'h-10 w-1' : 'w-10 h-1';
155
+
156
+ return (
157
+ <div
158
+ role="separator"
159
+ tabIndex={0}
160
+ aria-orientation={isHorizontal ? 'vertical' : 'horizontal'}
161
+ aria-valuenow={Math.round(size)}
162
+ aria-valuemin={minSize}
163
+ aria-valuemax={maxSize}
164
+ aria-label={ariaLabel ?? (isHorizontal ? 'Resize panel width' : 'Resize panel height')}
165
+ onPointerDown={handlePointerDown}
166
+ onPointerMove={handlePointerMove}
167
+ onPointerUp={endDrag}
168
+ onPointerCancel={endDrag}
169
+ onLostPointerCapture={endDrag}
170
+ onKeyDown={handleKeyDown}
171
+ className={cn(
172
+ 'group absolute z-20 flex touch-none select-none',
173
+ 'outline-none ring-0 focus:outline-none focus:ring-0 focus-visible:outline-none focus-visible:ring-0',
174
+ trackPosition,
175
+ cursorClass,
176
+ )}
177
+ >
178
+ <div
179
+ aria-hidden
180
+ className={cn('rounded-full', variant === 'inLayout' ? 'bg-ods-border' : 'bg-ods-bg-surface', gripClass)}
181
+ />
182
+ </div>
183
+ );
184
+ }
@@ -2,7 +2,7 @@
2
2
 
3
3
  import type React from 'react';
4
4
  import { useEffect, useRef, useState } from 'react';
5
- import { useMdUp } from '../../hooks';
5
+ import { useContentMdUp } from '../../hooks/ui/use-content-breakpoint';
6
6
 
7
7
  type ProgressBarProps = {
8
8
  progress: number; // 0–100
@@ -27,7 +27,7 @@ export const ProgressBar: React.FC<ProgressBarProps> = ({
27
27
  mobileHeight = 8,
28
28
  inverted = false,
29
29
  }) => {
30
- const isMdUp = useMdUp() ?? true;
30
+ const isMdUp = useContentMdUp() ?? true;
31
31
  const effectiveSegmentWidth = isMdUp ? segmentWidth : mobileSegmentWidth;
32
32
  const effectiveHeight = isMdUp ? height : mobileHeight;
33
33
 
@@ -65,7 +65,7 @@ export function QueryReportTable({
65
65
  {headerActions}
66
66
  {showExport && data.length > 0 && (
67
67
  <Button
68
- className="bg-ods-card max-md:hidden"
68
+ className="bg-ods-card content-max-md:hidden"
69
69
  variant="outline"
70
70
  leftIcon={<Download02Icon size={18} className="text-ods-text-secondary" />}
71
71
  onClick={handleExport}
@@ -117,7 +117,7 @@ export interface SearchInputProps {
117
117
 
118
118
  const containerStyles = cn(
119
119
  // Layout & spacing — matches lib Input component
120
- 'flex h-11 cursor-text items-center gap-2 rounded-[6px] border px-3 md:h-12',
120
+ 'flex h-11 cursor-text items-center gap-2 rounded-[6px] border px-3 content-md:h-12',
121
121
  'has-[:focus-visible]:outline-none',
122
122
  'group',
123
123
  'transition-colors duration-200',
@@ -456,7 +456,7 @@ export function SearchInput({
456
456
  }}
457
457
  >
458
458
  {/* Start Adornment — pinned left, shrink-0 */}
459
- <span className="flex-shrink-0 text-ods-text-secondary transition-colors duration-200 group-has-[:focus]:text-ods-accent [&_svg]:size-4 md:[&_svg]:size-6">
459
+ <span className="flex-shrink-0 text-ods-text-secondary transition-colors duration-200 group-has-[:focus]:text-ods-accent [&_svg]:size-4 content-md:[&_svg]:size-6">
460
460
  {startAdornment !== undefined ? startAdornment : <SearchIcon />}
461
461
  </span>
462
462
 
@@ -113,10 +113,10 @@ function ServiceCardRowItem({ row }: { row: ServiceCardRow }) {
113
113
 
114
114
  return (
115
115
  <div className="flex min-w-0 items-center gap-3">
116
- {row.label && <div className="w-20 shrink-0 text-ods-text-primary text-h6 md:w-24">{row.label}</div>}
116
+ {row.label && <div className="w-20 shrink-0 text-ods-text-primary text-h6 content-md:w-24">{row.label}</div>}
117
117
  <div
118
118
  className={cn(
119
- 'flex h-12 min-w-0 flex-1 items-center justify-between rounded-md border border-ods-border bg-ods-bg px-3 md:px-4',
119
+ 'flex h-12 min-w-0 flex-1 items-center justify-between rounded-md border border-ods-border bg-ods-bg px-3 content-md:px-4',
120
120
  row.monospace ? 'font-mono' : '',
121
121
  )}
122
122
  >
@@ -5,6 +5,7 @@ import { cva, type VariantProps } from 'class-variance-authority';
5
5
  import { X } from 'lucide-react';
6
6
  import { type ComponentPropsWithoutRef, type ElementRef, type HTMLAttributes, forwardRef } from 'react';
7
7
 
8
+ import { ViewportBreakpoints } from '../../hooks/ui/use-content-breakpoint';
8
9
  import { cn } from '../../utils/cn';
9
10
 
10
11
  const Sheet = SheetPrimitive.Root;
@@ -57,7 +58,7 @@ const SheetContent = forwardRef<ElementRef<typeof SheetPrimitive.Content>, Sheet
57
58
  <SheetPortal>
58
59
  <SheetOverlay />
59
60
  <SheetPrimitive.Content ref={ref} className={cn(sheetVariants({ side }), className)} {...props}>
60
- {children}
61
+ <ViewportBreakpoints>{children}</ViewportBreakpoints>
61
62
  <SheetPrimitive.Close className="absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-secondary">
62
63
  <X className="h-4 w-4" />
63
64
  <span className="sr-only">Close</span>
@@ -68,9 +68,9 @@ const SkeletonGrid = forwardRef<HTMLDivElement, SkeletonGridProps>(
68
68
  ref={ref}
69
69
  className={cn(
70
70
  `grid grid-cols-1 gap-6`,
71
- columns === 2 && 'md:grid-cols-2',
72
- columns === 3 && 'md:grid-cols-3',
73
- columns === 4 && 'md:grid-cols-4',
71
+ columns === 2 && 'content-md:grid-cols-2',
72
+ columns === 3 && 'content-md:grid-cols-3',
73
+ columns === 4 && 'content-md:grid-cols-4',
74
74
  className,
75
75
  )}
76
76
  {...props}
@@ -83,15 +83,15 @@ const CELL_ITEMS_ALIGN: Record<PanelColumnAlign, string> = {
83
83
  };
84
84
 
85
85
  const HIDE_CLASS: Record<PanelHideAt, string> = {
86
- md: 'hidden md:flex',
87
- lg: 'hidden lg:flex',
88
- xl: 'hidden xl:flex',
86
+ md: 'hidden content-md:flex',
87
+ lg: 'hidden content-lg:flex',
88
+ xl: 'hidden content-xl:flex',
89
89
  };
90
90
 
91
91
  // Base column-row class. Row height is content-driven via the min-heights, matching
92
92
  // the joined-row pattern used across the detail layouts (56px mobile, 80px tablet+).
93
93
  const ROW_CLASS =
94
- 'flex items-center gap-[var(--spacing-system-m)] px-[var(--spacing-system-m)] min-h-14 md:min-h-20 border-b border-ods-border last:border-b-0';
94
+ 'flex items-center gap-[var(--spacing-system-m)] px-[var(--spacing-system-m)] min-h-14 content-md:min-h-20 border-b border-ods-border last:border-b-0';
95
95
 
96
96
  function CellValue({ column }: { column: PanelColumn }) {
97
97
  const valueNode = (
@@ -399,7 +399,7 @@ const TabBar = memo(function TabBarImpl({
399
399
  <div className="relative flex items-center justify-center">
400
400
  <tab.icon
401
401
  className={cn(
402
- 'h-4 w-4 transition-colors md:h-6 md:w-6',
402
+ 'h-4 w-4 transition-colors content-md:h-6 content-md:w-6',
403
403
  isActive ? 'text-ods-accent' : 'text-ods-text-secondary',
404
404
  )}
405
405
  />
@@ -412,7 +412,7 @@ const TabBar = memo(function TabBarImpl({
412
412
  ) : null}
413
413
 
414
414
  {tab.sublabel ? (
415
- <span className="flex min-w-0 flex-col items-start text-left md:flex-row md:items-baseline md:gap-[var(--spacing-system-xsf)]">
415
+ <span className="flex min-w-0 flex-col items-start text-left content-md:flex-row content-md:items-baseline content-md:gap-[var(--spacing-system-xsf)]">
416
416
  <span
417
417
  className={cn(
418
418
  'whitespace-nowrap transition-colors text-h4',
@@ -78,7 +78,7 @@ export function TabSelector({
78
78
  'flex gap-[var(--spacing-system-xxs)] bg-ods-bg p-[var(--spacing-system-xxs)]',
79
79
  flush
80
80
  ? 'h-10 w-full'
81
- : cn('h-11 rounded-md border border-ods-border md:h-12', scrollable ? 'overflow-x-auto' : 'w-full'),
81
+ : cn('h-11 rounded-md border border-ods-border content-md:h-12', scrollable ? 'overflow-x-auto' : 'w-full'),
82
82
  )}
83
83
  >
84
84
  {items.map(item => {
@@ -112,7 +112,7 @@ export function TabSelector({
112
112
  )}
113
113
  >
114
114
  {item.icon && (
115
- <span className="flex size-4 shrink-0 items-center justify-center md:size-6">{item.icon}</span>
115
+ <span className="flex size-4 shrink-0 items-center justify-center content-md:size-6">{item.icon}</span>
116
116
  )}
117
117
  {item.label}
118
118
  {item.badge && item.badge}
@@ -1,6 +1,6 @@
1
1
  'use client';
2
2
 
3
- import { useLgUp } from '../../../hooks/ui/use-media-query';
3
+ import { useContentLgUp } from '../../../hooks/ui/use-content-breakpoint';
4
4
  import { cn } from '../../../utils/cn';
5
5
  import { Arrow01DownIcon } from '../../icons-v2-generated/arrows/arrow-01-down-icon';
6
6
  import { Arrow01UpIcon } from '../../icons-v2-generated/arrows/arrow-01-up-icon';
@@ -72,12 +72,12 @@ export function TableHeader<T = TableRowData>({
72
72
  );
73
73
  };
74
74
 
75
- const isLgUp = useLgUp() ?? false;
75
+ const isLgUp = useContentLgUp() ?? false;
76
76
 
77
77
  return (
78
78
  <div
79
79
  className={cn(
80
- 'relative hidden h-11 items-center gap-4 px-4 py-3 md:flex',
80
+ 'relative hidden h-11 items-center gap-4 px-4 py-3 content-md:flex',
81
81
  stickyHeader && `sticky z-10 bg-ods-bg ${stickyHeaderOffset || 'top-0'}`,
82
82
  className,
83
83
  )}
@@ -5,7 +5,7 @@ import type { TableCardSkeletonProps } from './types';
5
5
 
6
6
  // INNER row heights: the bordered row card adds 1px top + bottom, so the
7
7
  // outer block totals the designed 68px / 80px.
8
- const ROW_HEIGHT_DESKTOP = 'h-[66px] md:h-[78px]';
8
+ const ROW_HEIGHT_DESKTOP = 'h-[66px] content-md:h-[78px]';
9
9
  /**
10
10
  * A `compact` row's floor. Compact rows are content-sized (`py-2`), but every
11
11
  * row in one table renders the same cell shapes, so pinning a minimum makes the
@@ -47,7 +47,7 @@ export function TableCardSkeleton({
47
47
  the two here made every compact table jump on its first paint. */}
48
48
  <div
49
49
  className={cn(
50
- 'hidden items-center gap-4 px-4 md:flex',
50
+ 'hidden items-center gap-4 px-4 content-md:flex',
51
51
  compact ? cn('py-2', COMPACT_ROW_MIN_HEIGHT) : cn('py-0', ROW_HEIGHT_DESKTOP),
52
52
  rowClassName,
53
53
  )}
@@ -81,7 +81,7 @@ export function TableCardSkeleton({
81
81
  {/* Mobile Skeleton */}
82
82
  <div
83
83
  className={cn(
84
- 'flex items-center justify-start gap-3 px-3 md:hidden',
84
+ 'flex items-center justify-start gap-3 px-3 content-md:hidden',
85
85
  // Mirror the real row on mobile too: a compact row is
86
86
  // content-sized with a floor, a normal row a fixed height.
87
87
  // Hard-wiring ROW_HEIGHT_MOBILE made every COMPACT table jump
@@ -16,21 +16,21 @@ export function getHideClasses(hideAt?: TailwindBreakpoint | TailwindBreakpoint[
16
16
  const maxBreakpointIndex = Math.max(...breakpoints.map(bp => breakpointOrder.indexOf(bp)));
17
17
 
18
18
  // For single breakpoint: hide below, show at and above
19
- // e.g., hideAt: 'md' -> 'hidden md:flex'
19
+ // e.g., hideAt: 'md' -> 'hidden content-md:flex'
20
20
  if (breakpoints.length === 1) {
21
- return `hidden ${breakpoints[0]}:flex`;
21
+ return `hidden content-${breakpoints[0]}:flex`;
22
22
  }
23
23
 
24
24
  // For multiple breakpoints: hide at specified breakpoints, show after the largest one
25
- // e.g., hideAt: ['md', 'lg'] -> 'md:hidden lg:hidden xl:flex'
26
- const hideClasses = breakpoints.map(bp => `${bp}:hidden`).join(' ');
25
+ // e.g., hideAt: ['md', 'lg'] -> 'content-md:hidden content-lg:hidden content-xl:flex'
26
+ const hideClasses = breakpoints.map(bp => `content-${bp}:hidden`).join(' ');
27
27
 
28
28
  // Find next breakpoint after the max to show the column
29
29
  const nextBreakpointIndex = maxBreakpointIndex + 1;
30
30
  const showBreakpoint = breakpointOrder[nextBreakpointIndex];
31
31
 
32
32
  if (showBreakpoint) {
33
- return `${hideClasses} ${showBreakpoint}:flex`;
33
+ return `${hideClasses} content-${showBreakpoint}:flex`;
34
34
  }
35
35
 
36
36
  // If no next breakpoint (e.g., hideAt: '2xl'), just hide
@@ -149,7 +149,7 @@ export function TagSearchInput<T = string>({
149
149
  {/* ---- Visible container ---- */}
150
150
  <div
151
151
  className={cn(
152
- 'flex h-11 cursor-text items-center rounded-[6px] border md:h-12',
152
+ 'flex h-11 cursor-text items-center rounded-[6px] border content-md:h-12',
153
153
  'transition-colors duration-200',
154
154
  'border-ods-border bg-ods-card',
155
155
  'has-[:focus]:border-ods-accent',
@@ -170,7 +170,7 @@ export function TagSearchInput<T = string>({
170
170
  >
171
171
  {/* Search icon — pinned left, responsive size */}
172
172
  <div className="flex shrink-0 items-center pl-3">
173
- <SearchIcon className="size-4 text-ods-text-secondary md:size-6" />
173
+ <SearchIcon className="size-4 text-ods-text-secondary content-md:size-6" />
174
174
  </div>
175
175
 
176
176
  {/* Middle zone: tags + input — overflow hidden so tags never push clear btn */}
@@ -234,7 +234,7 @@ export function TagSearchInput<T = string>({
234
234
  className="flex shrink-0 cursor-pointer items-center justify-center pr-3 transition-opacity hover:opacity-70"
235
235
  aria-label="Clear all"
236
236
  >
237
- <XmarkCircleIcon className="size-4 text-ods-text-secondary md:size-6" />
237
+ <XmarkCircleIcon className="size-4 text-ods-text-secondary content-md:size-6" />
238
238
  </button>
239
239
  )}
240
240
  </div>
@@ -169,7 +169,7 @@ export function TagsManager({
169
169
  <PopoverPrimitive.Anchor asChild>
170
170
  <label
171
171
  className={cn(
172
- 'flex min-h-11 w-full cursor-text flex-wrap items-center gap-2 rounded-[6px] border px-3 py-1 md:min-h-12',
172
+ 'flex min-h-11 w-full cursor-text flex-wrap items-center gap-2 rounded-[6px] border px-3 py-1 content-md:min-h-12',
173
173
  'transition-colors duration-200',
174
174
  'border-ods-border bg-ods-card',
175
175
  'group',
@@ -185,7 +185,7 @@ export function TagsManager({
185
185
  {/* Search adornment */}
186
186
  <span
187
187
  className={cn(
188
- 'flex-shrink-0 text-ods-text-secondary transition-colors duration-200 [&_svg]:size-4 md:[&_svg]:size-6',
188
+ 'flex-shrink-0 text-ods-text-secondary transition-colors duration-200 [&_svg]:size-4 content-md:[&_svg]:size-6',
189
189
  open && 'text-ods-accent',
190
190
  )}
191
191
  >
@@ -237,7 +237,7 @@ export function TagsManager({
237
237
  <button
238
238
  type="button"
239
239
  onClick={handleClearAll}
240
- className="flex flex-shrink-0 items-center justify-center transition-opacity hover:opacity-70 [&_svg]:size-4 md:[&_svg]:size-6"
240
+ className="flex flex-shrink-0 items-center justify-center transition-opacity hover:opacity-70 [&_svg]:size-4 content-md:[&_svg]:size-6"
241
241
  aria-label="Clear all tags"
242
242
  >
243
243
  <XmarkCircleIcon className="text-ods-text-secondary" />
@@ -319,7 +319,7 @@ export function TagsManager({
319
319
  aria-selected={isSelected}
320
320
  tabIndex={0}
321
321
  className={cn(
322
- 'flex h-11 cursor-pointer items-center border-b border-ods-border px-4 transition-colors last:border-b-0 md:h-12',
322
+ 'flex h-11 cursor-pointer items-center border-b border-ods-border px-4 transition-colors last:border-b-0 content-md:h-12',
323
323
  'text-h4',
324
324
  isSelected ? 'text-ods-accent' : 'text-ods-text-primary',
325
325
  'group/item hover:bg-ods-bg-hover',
@@ -383,7 +383,7 @@ export function TagsManager({
383
383
  aria-selected={false}
384
384
  tabIndex={0}
385
385
  className={cn(
386
- 'flex h-11 cursor-pointer items-center gap-2 px-4 transition-colors text-h4 md:h-12',
386
+ 'flex h-11 cursor-pointer items-center gap-2 px-4 transition-colors text-h4 content-md:h-12',
387
387
  'hover:bg-ods-bg-hover',
388
388
  isCreating && 'pointer-events-none opacity-50',
389
389
  )}
@@ -53,7 +53,7 @@ export function TestResultsSkeleton() {
53
53
  <div className="animate-pulse overflow-hidden rounded-[6px] border border-ods-border bg-ods-card">
54
54
  {/* Same INNER row heights as the DataTable (66/78px + the 1px card
55
55
  border on each side = 68/80px total, per design). */}
56
- <div className="flex h-[66px] items-center gap-[var(--spacing-system-mf)] px-[var(--spacing-system-mf)] md:h-[78px]">
56
+ <div className="flex h-[66px] items-center gap-[var(--spacing-system-mf)] px-[var(--spacing-system-mf)] content-md:h-[78px]">
57
57
  {Array.from({ length: SKELETON_COLUMNS }).map((_, i) => (
58
58
  <div key={`skeleton-cell-${i}`} className="w-[160px] shrink-0">
59
59
  <div className="h-5 w-3/4 rounded-sm bg-ods-bg-surface" />
@@ -114,7 +114,7 @@ export function TestResultsTable({ rows, loading }: { rows: QueryResultRow[]; lo
114
114
  <ScrollShadow axis="horizontal">
115
115
  <div style={{ minWidth: Math.max(1, columnKeys.length) * RESULT_COLUMN_MIN_WIDTH }}>
116
116
  <DataTable table={table}>
117
- {/* "flex" overrides the header's default "hidden md:flex" so the
117
+ {/* "flex" overrides the header's default "hidden content-md:flex" so the
118
118
  headers render on mobile too. */}
119
119
  <DataTable.Header className="flex flex-col" />
120
120
  <DataTable.Body loading={false} />
@@ -153,7 +153,7 @@ export function TicketInfoSection({
153
153
  return (
154
154
  <div className={cn('overflow-hidden rounded-[6px] border border-ods-border', className)}>
155
155
  {/* Header row */}
156
- <div className="grid grid-cols-2 items-center gap-4 border-b border-ods-border bg-ods-card px-4 py-3 lg:grid-cols-[1fr_1fr_1fr_auto]">
156
+ <div className="grid grid-cols-2 items-center gap-4 border-b border-ods-border bg-ods-card px-4 py-3 content-lg:grid-cols-[1fr_1fr_1fr_auto]">
157
157
  {/* Organization with image */}
158
158
  <div className="flex min-w-0 items-center gap-2">
159
159
  <SquareAvatar
@@ -62,7 +62,7 @@ export function TicketNotesSection({
62
62
  onClick={handleSend}
63
63
  disabled={!noteText.trim() || isAddingNote}
64
64
  className={cn(
65
- 'flex h-11 w-11 shrink-0 items-center justify-center rounded-[6px] md:h-12 md:w-12',
65
+ 'flex h-11 w-11 shrink-0 items-center justify-center rounded-[6px] content-md:h-12 content-md:w-12',
66
66
  'border border-ods-border bg-ods-card',
67
67
  'transition-colors hover:bg-ods-bg-hover',
68
68
  'disabled:cursor-not-allowed disabled:opacity-50',