@muten/shadcn 0.1.15 → 0.2.1

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 (183) hide show
  1. package/AGENTS.md +88 -1
  2. package/globals.css +1 -0
  3. package/kit.css +348 -126
  4. package/motion.css +3 -0
  5. package/package.json +1 -1
  6. package/registry/accordion.muten +3 -3
  7. package/registry/agenda.js +20 -16
  8. package/registry/agenda.muten +14 -12
  9. package/registry/alert-dialog.muten +2 -2
  10. package/registry/alert.muten +1 -1
  11. package/registry/app-shell.muten +1 -1
  12. package/registry/attachment.muten +1 -1
  13. package/registry/avatar.muten +4 -4
  14. package/registry/badge.muten +14 -3
  15. package/registry/band.muten +2 -2
  16. package/registry/bar-chart.muten +2 -2
  17. package/registry/bio-play.muten +2 -2
  18. package/registry/booking-play.muten +5 -5
  19. package/registry/booking.muten +2 -2
  20. package/registry/breadcrumb.muten +4 -4
  21. package/registry/button.muten +9 -7
  22. package/registry/calendar.js +15 -10
  23. package/registry/calendar.muten +1 -1
  24. package/registry/card.muten +1 -1
  25. package/registry/carousel.muten +1 -1
  26. package/registry/chat-play.muten +8 -8
  27. package/registry/chatbot.muten +5 -4
  28. package/registry/checklist.muten +1 -1
  29. package/registry/choice-list.muten +3 -3
  30. package/registry/code.js +10 -4
  31. package/registry/collapsible.muten +2 -2
  32. package/registry/color-picker.js +37 -36
  33. package/registry/color-picker.muten +1 -1
  34. package/registry/combobox.js +1 -1
  35. package/registry/combobox.muten +2 -2
  36. package/registry/command-palette.muten +2 -2
  37. package/registry/command.js +1 -1
  38. package/registry/command.muten +7 -7
  39. package/registry/context-menu.muten +3 -3
  40. package/registry/count-up.js +33 -31
  41. package/registry/count-up.muten +6 -4
  42. package/registry/date-field.js +1 -1
  43. package/registry/date-field.muten +3 -3
  44. package/registry/day-plan.muten +5 -5
  45. package/registry/device-frame.muten +3 -3
  46. package/registry/dialog.muten +1 -1
  47. package/registry/dirty-bar.js +2 -2
  48. package/registry/dirty-bar.muten +3 -3
  49. package/registry/drawer.muten +1 -1
  50. package/registry/dropdown-menu.muten +4 -4
  51. package/registry/empty.muten +1 -1
  52. package/registry/feature-grid.muten +1 -1
  53. package/registry/feature-rows.muten +2 -2
  54. package/registry/field-behavior.js +13 -3
  55. package/registry/field-behavior.muten +3 -3
  56. package/registry/field.muten +5 -5
  57. package/registry/file-input.js +8 -4
  58. package/registry/file-input.muten +3 -3
  59. package/registry/fixed-card.muten +4 -4
  60. package/registry/folder-picker.js +6 -2
  61. package/registry/folder-picker.muten +2 -2
  62. package/registry/heatmap.muten +5 -5
  63. package/registry/image-upload.js +1 -1
  64. package/registry/image-upload.muten +2 -2
  65. package/registry/inbox-play.muten +5 -5
  66. package/registry/indicator.muten +1 -1
  67. package/registry/info-table.muten +1 -1
  68. package/registry/input-group.muten +11 -11
  69. package/registry/input-otp.muten +2 -2
  70. package/registry/input.muten +1 -1
  71. package/registry/inspector.muten +2 -2
  72. package/registry/item.muten +2 -2
  73. package/registry/kit/board.js +36 -34
  74. package/registry/kit/collections.js +24 -24
  75. package/registry/kit/core.js +231 -118
  76. package/registry/kit/dates.js +29 -27
  77. package/registry/kit/i18n.js +172 -0
  78. package/registry/kit/menus.js +14 -13
  79. package/registry/kit/overlays.js +7 -2
  80. package/registry/kit/structure.js +66 -61
  81. package/registry/kit/table.js +19 -17
  82. package/registry/kit/values.js +36 -28
  83. package/registry/kit-skeleton.muten +1 -1
  84. package/registry/kit-widget.js +9 -4
  85. package/registry/lang-scope.js +8 -0
  86. package/registry/lang-scope.muten +5 -0
  87. package/registry/legal-doc.muten +5 -5
  88. package/registry/link-btn.muten +1 -1
  89. package/registry/list-motion.js +46 -0
  90. package/registry/list-motion.muten +4 -0
  91. package/registry/live-stack.muten +2 -2
  92. package/registry/logo-cloud.muten +2 -2
  93. package/registry/marketing.muten +7 -7
  94. package/registry/member-list.muten +2 -2
  95. package/registry/menubar.muten +3 -3
  96. package/registry/message-scroller.muten +3 -3
  97. package/registry/message.muten +9 -9
  98. package/registry/messaging.muten +1 -1
  99. package/registry/modal-behavior.js +24 -0
  100. package/registry/modal.muten +4 -4
  101. package/registry/money-field.js +1 -1
  102. package/registry/money-field.muten +2 -2
  103. package/registry/nav-button.muten +4 -4
  104. package/registry/navigation-menu.muten +4 -4
  105. package/registry/navpill.muten +6 -6
  106. package/registry/new-appointment.js +1 -1
  107. package/registry/new-appointment.muten +4 -4
  108. package/registry/number-field.js +6 -4
  109. package/registry/number-field.muten +1 -1
  110. package/registry/order-board.js +1 -1
  111. package/registry/order-board.muten +2 -2
  112. package/registry/order-play.muten +4 -4
  113. package/registry/pagination-nav.js +1 -1
  114. package/registry/pagination-nav.muten +3 -3
  115. package/registry/pagination.muten +4 -4
  116. package/registry/password-field.muten +2 -2
  117. package/registry/permission-matrix.muten +4 -4
  118. package/registry/phone-bar.muten +6 -6
  119. package/registry/phone-field.js +1 -1
  120. package/registry/phone-field.muten +1 -1
  121. package/registry/phone-shell.js +1 -1
  122. package/registry/pill.muten +2 -2
  123. package/registry/plans.muten +1 -1
  124. package/registry/popover.muten +2 -2
  125. package/registry/pricing.muten +4 -4
  126. package/registry/product-play.muten +3 -3
  127. package/registry/progress.muten +3 -3
  128. package/registry/queue.muten +1 -1
  129. package/registry/radio-group.muten +1 -1
  130. package/registry/rank-item.muten +4 -4
  131. package/registry/resizable.muten +1 -1
  132. package/registry/row-menu.js +1 -1
  133. package/registry/row-menu.muten +2 -2
  134. package/registry/save-button.muten +5 -5
  135. package/registry/scale-slider.js +1 -1
  136. package/registry/scale-slider.muten +2 -2
  137. package/registry/screen-tour.muten +1 -1
  138. package/registry/share-bar.muten +2 -2
  139. package/registry/share-button.muten +4 -4
  140. package/registry/sheet.muten +1 -1
  141. package/registry/sidebar.muten +12 -6
  142. package/registry/site-footer.muten +6 -6
  143. package/registry/sortable-behavior.js +67 -20
  144. package/registry/sortable-list.js +3 -1
  145. package/registry/sortable-list.muten +2 -2
  146. package/registry/sortable.muten +5 -4
  147. package/registry/spinner.muten +2 -2
  148. package/registry/split-button.muten +2 -2
  149. package/registry/stacked-bars.js +3 -3
  150. package/registry/stacked-bars.muten +2 -2
  151. package/registry/stamp-card.muten +2 -2
  152. package/registry/stat-band.muten +3 -3
  153. package/registry/stat.muten +3 -3
  154. package/registry/status-bar.muten +2 -2
  155. package/registry/stepper.muten +4 -4
  156. package/registry/store-qr.js +1 -1
  157. package/registry/store-qr.muten +2 -2
  158. package/registry/swatch.muten +1 -1
  159. package/registry/switch.muten +8 -7
  160. package/registry/table-view.muten +3 -3
  161. package/registry/tabs-behavior.js +9 -1
  162. package/registry/tabs.muten +2 -2
  163. package/registry/tag-input.js +1 -1
  164. package/registry/tag-input.muten +2 -2
  165. package/registry/text.muten +2 -2
  166. package/registry/time-field.js +1 -1
  167. package/registry/time-field.muten +3 -3
  168. package/registry/timeline.muten +4 -4
  169. package/registry/toaster.muten +2 -2
  170. package/registry/toggle-group.muten +1 -1
  171. package/registry/toggle.muten +3 -3
  172. package/registry/toolbar.muten +4 -4
  173. package/registry/tooltip.muten +2 -2
  174. package/registry/tree-view.js +38 -25
  175. package/registry/tree-view.muten +1 -1
  176. package/registry/veil.muten +1 -1
  177. package/registry/virtual-list.js +1 -1
  178. package/registry/virtual-list.muten +2 -2
  179. package/registry/virtual-window.js +4 -4
  180. package/registry/virtual-window.muten +2 -2
  181. package/registry/wordline.muten +1 -1
  182. package/registry/zoom-control.muten +1 -1
  183. package/registry.json +22 -2
package/kit.css CHANGED
@@ -35,7 +35,7 @@
35
35
  .cn-alert[data-tone="info"] > .mu-icon { color: var(--info); } .cn-alert[data-tone="ok"] > .mu-icon { color: var(--success); } .cn-alert[data-tone="wait"] > .mu-icon { color: var(--warning); }
36
36
  .cn-alert[data-tone="wait"] { background: color-mix(in srgb, var(--warning) 6%, var(--card)); }
37
37
  /* Progress: the value rides --w (muten's style(w: …)); Nova's flex-1 would stretch it to full. */
38
- .cn-progress > .cn-progress-indicator:not([style*="transform"]) { flex: none; width: var(--w, 0%); transition: width 260ms cubic-bezier(.22, 1, .36, 1); }
38
+ .cn-progress > .cn-progress-indicator:not([style*="transform"]) { flex: none; width: var(--w, 0%); transition: width var(--t-move) var(--ease-out); }
39
39
  /* Skeleton: the shimmer on Nova's block (the kit's own .cx-sk keeps working for Customs). */
40
40
  .cn-skeleton { background: linear-gradient(90deg, var(--sk-a) 0%, var(--sk-b) 50%, var(--sk-a) 100%); background-size: 200% 100%; animation: cx-sk 1.3s linear infinite; }
41
41
  .cn-skeleton[data-shape="circle"], .cn-skeleton[data-shape="pill"] { border-radius: 99px; }
@@ -58,6 +58,9 @@
58
58
  .cx-switch-row > .cx-switch-why { grid-column: 1; margin: 0; font-size: 13px; color: var(--muted-foreground); line-height: 1.45; }
59
59
  .cx-switch-row > .cx-switch-why:empty { display: none; }
60
60
  .cx-switch-row > .cn-switch { margin-top: 1px; }
61
+ /* Switch(disabled): the native attribute, dimmed like Nova's data-disabled; its row's words dim with it */
62
+ .cn-switch:disabled { cursor: not-allowed; opacity: .5; }
63
+ .cx-switch-row[data-disabled="true"] > :is(.cn-label, .cx-switch-why) { opacity: .55; }
61
64
  /* Tokens swatches from muten (the artifact paints them with <i style>): the color rides --c. */
62
65
  .cx-sw > .cx-sw-i { width: 22px; height: 22px; border-radius: 6px; box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--foreground) 15%, transparent); flex: none; background: var(--c); }
63
66
  .cx-z > .cx-z-code { font: 12px var(--font-mono); color: var(--muted-foreground); }
@@ -83,20 +86,13 @@ button.cn-item { width: 100%; font: inherit; text-align: left; cursor: pointer;
83
86
  .cx-row3 .cx-row3-s:empty { display: none; }
84
87
  .cx-empty-mini > .mu-icon { font-size: 22px; color: var(--success); }
85
88
  /* Text atom from a part: data-variant comes from data(), same rules as the kit's .cx-text below. */
86
- /* Button icon motion, for span.mu-icon (the kit's rules below key on svg). */
87
- @media (hover: hover) and (prefers-reduced-motion: no-preference) {
88
- .cn-button > .mu-icon { transition: transform 180ms cubic-bezier(.22, 1, .36, 1); }
89
- .cn-button:not(:disabled):hover > .mu-icon:last-child:not(:first-child) { transform: translateX(2px); }
90
- .cn-button:not(:disabled):hover > .mu-icon:first-child:not(:last-child) { transform: scale(1.12); }
91
- .cn-button:not(:disabled):hover > .mu-icon:only-child { transform: scale(1.12); }
92
- }
93
89
 
94
90
 
95
91
  /* ═════════════════════════ 1b. the artifact page's library rules (floating panels, drawer, svg size, checkbox, toasts) ═════════════════════════ */
96
92
  .pg-pop { position: fixed; top: 0; left: 0; z-index: 60; }
97
- .pg-drw-o { position: fixed; inset: 0; z-index: 50; background: rgb(0 0 0 / .3); backdrop-filter: blur(8px); opacity: 0; transition: opacity 450ms cubic-bezier(0.22, 1, 0.36, 1); }
93
+ .pg-drw-o { position: fixed; inset: 0; z-index: 50; background: rgb(0 0 0 / .3); backdrop-filter: blur(8px); opacity: 0; transition: opacity 450ms var(--ease-out); }
98
94
  .pg-drw-o[data-state="open"] { opacity: 1; }
99
- .pg-drw { position: fixed; z-index: 50; margin: 8px; display: flex; flex-direction: column; border-radius: 24px; border: 1px solid var(--popover); background: var(--popover); color: var(--popover-foreground); font-size: 14px; box-shadow: 0 20px 25px -5px rgb(0 0 0 / .1), 0 8px 10px -6px rgb(0 0 0 / .1); transition: transform 450ms cubic-bezier(0.22, 1, 0.36, 1); will-change: transform; outline: none; }
95
+ .pg-drw { position: fixed; z-index: 50; margin: 8px; display: flex; flex-direction: column; border-radius: 24px; border: 1px solid var(--popover); background: var(--popover); color: var(--popover-foreground); font-size: 14px; box-shadow: 0 20px 25px -5px rgb(0 0 0 / .1), 0 8px 10px -6px rgb(0 0 0 / .1); transition: transform 450ms var(--ease-out); will-change: transform; outline: none; }
100
96
  :root[data-theme="dark"] .pg-drw { border-color: var(--border); }
101
97
  .pg-drw[data-dir="right"] { top: 0; right: 0; bottom: 0; width: calc(75% - 16px); max-width: 24rem; transform: translateX(calc(100% + 8px)); }
102
98
  .pg-drw[data-dir="bottom"] { left: 0; right: 0; bottom: 0; max-height: calc(100dvh - 6rem); transform: translateY(calc(100% + 8px)); }
@@ -115,7 +111,7 @@ button.cn-item { width: 100%; font: inherit; text-align: left; cursor: pointer;
115
111
  .cb-mark { width: 14px; height: 14px; }
116
112
  [data-state="unchecked"] > .cn-checkbox-indicator { visibility: hidden; }
117
113
  .style-nova .cb-mark path { stroke-dasharray: 24; stroke-dashoffset: 24; }
118
- .style-nova [data-state="checked"] .cb-mark path { stroke-dashoffset: 0; transition: stroke-dashoffset 200ms cubic-bezier(0.22, 1, 0.36, 1) 40ms; }
114
+ .style-nova [data-state="checked"] .cb-mark path { stroke-dashoffset: 0; transition: stroke-dashoffset 200ms var(--ease-out) 40ms; }
119
115
  .style-nova [data-state="checked"] > .cn-checkbox-indicator { visibility: visible; }
120
116
  .style-nova .cn-checkbox { transition: background-color 150ms, border-color 150ms, color 150ms; }
121
117
  .style-nova .cn-checkbox:active { scale: .92; transition: scale 100ms; }
@@ -125,12 +121,12 @@ button.cn-item { width: 100%; font: inherit; text-align: left; cursor: pointer;
125
121
  --gap: .75rem; --peek: .75rem; --scale: max(0, 1 - var(--i) * 0.1); --shrink: calc(1 - var(--scale));
126
122
  height: var(--front-h); z-index: calc(1000 - var(--i));
127
123
  transform: translateY(calc(0px - var(--i) * var(--peek) - var(--shrink) * var(--front-h))) scale(var(--scale));
128
- transition: transform 500ms cubic-bezier(0.22, 1, 0.36, 1), opacity 500ms, height 150ms; will-change: transform; }
124
+ transition: transform 500ms var(--ease-out), opacity 500ms, height 150ms; will-change: transform; }
129
125
  .pg-toast::after { content: ""; position: absolute; top: 100%; left: 0; width: 100%; height: calc(var(--gap) + 1px); }
130
126
  .pg-toasts[data-expanded] .pg-toast { height: var(--h); transform: translateY(calc(0px - var(--off) - var(--i) * var(--gap))); }
131
127
  .pg-toast[data-start], .pg-toast[data-end] { transform: translateY(150%) !important; }
132
128
  .pg-toast[data-limited] { opacity: 0; }
133
- .pg-toast-c { display: flex; height: 100%; align-items: center; gap: 12px; overflow: hidden; padding: 16px; transition: opacity 250ms cubic-bezier(0.22, 1, 0.36, 1); }
129
+ .pg-toast-c { display: flex; height: 100%; align-items: center; gap: 12px; overflow: hidden; padding: 16px; transition: opacity 250ms var(--ease-out); }
134
130
  .pg-toast[data-behind] .pg-toast-c { opacity: 0; }
135
131
  .pg-toasts[data-expanded] .pg-toast-c { opacity: 1; }
136
132
  .pg-toast-t { font-size: 14px; font-weight: 500; } .pg-toast-d { font-size: 14px; color: var(--muted-foreground); }
@@ -151,7 +147,7 @@ button.cn-item { width: 100%; font: inherit; text-align: left; cursor: pointer;
151
147
  /* spinner (shadcn's animate-spin) */
152
148
  @keyframes pg-spin { to { transform: rotate(360deg); } }
153
149
  .animate-spin { animation: pg-spin 1s linear infinite; }
154
- .cn-progress-indicator { transition: transform 450ms ease; }
150
+ .cn-progress-indicator { transition: transform var(--t-move) var(--ease-out); }
155
151
  /* native select: options readable in both themes */
156
152
  .pg-opt-native { background: var(--popover); color: var(--popover-foreground); }
157
153
  /* textarea counter (our extra) */
@@ -195,7 +191,14 @@ button.cn-item { width: 100%; font: inherit; text-align: left; cursor: pointer;
195
191
  --overlay: rgb(0 0 0 / 0.1);
196
192
  --on-destructive: oklch(1 0 0);
197
193
  --z-content: 0; --z-sticky: 20; --z-fab: 30; --z-popover: 40; --z-sheet: 50; --z-modal: 60; --z-toast: 70;
194
+ /* MOTION: the library's one rhythm (docs: AGENTS.md «Motion», bench /motion). Three curves, six durations; a
195
+ component never writes its own. Entering or appearing: --ease-out. Moving on screen: --ease-in-out. A panel that
196
+ slides in: --ease-drawer. Leaving takes about 0.7 of entering. A hover never animates (0 ms). */
197
+ --ease-out: cubic-bezier(.23, 1, .32, 1); --ease-in-out: cubic-bezier(.77, 0, .175, 1); --ease-drawer: cubic-bezier(.32, .72, 0, 1);
198
+ --t-press: 100ms; --t-micro: 150ms; --t-pop: 180ms; --t-move: 240ms; --t-modal: 240ms; --t-sheet: 380ms;
198
199
  }
200
+ /* reduce motion, in one place: every duration token drops to nearly nothing and everything still works */
201
+ @media (prefers-reduced-motion: reduce) { :root { --t-press: 1ms; --t-micro: 1ms; --t-pop: 1ms; --t-move: 1ms; --t-modal: 1ms; --t-sheet: 1ms; } }
199
202
 
200
203
  /* ── pieles de ejemplo: lo único que cambia entre apps y tiendas ── */
201
204
  [data-skin="storio"] {
@@ -233,16 +236,25 @@ button.cn-item { width: 100%; font: inherit; text-align: left; cursor: pointer;
233
236
  .cx-create { background: var(--primary); color: var(--primary-foreground); }
234
237
  .cx-save { width: 9.25rem; justify-content: center; }
235
238
  .cx-save[data-status="saving"] { pointer-events: none; opacity: .85; }
236
- .cx-save[data-status="saved"] { background: var(--success); color: #fff; animation: cx-pop 260ms cubic-bezier(.22, 1, .36, 1); }
239
+ .cx-save[data-status="saved"] { background: var(--success); color: #fff; animation: cx-pop 260ms var(--ease-out); }
237
240
  @keyframes cx-pop { 50% { transform: scale(1.04); } }
238
241
  .cx-btn-label { display: inline-flex; align-items: center; gap: 6px; }
239
242
 
240
243
  /* ── Badge tones + dot + removable chip ── */
241
- .cx-tone-new { background: var(--info-soft); color: var(--info); }
242
- .cx-tone-ok { background: var(--success-soft); color: var(--success); }
243
- .cx-tone-wait { background: var(--warning-soft); color: var(--warning); }
244
- .cx-tone-bad { background: color-mix(in srgb, var(--destructive) 14%, transparent); color: var(--destructive); }
245
- .cx-tone-pro { background: var(--selected); color: var(--selected-foreground); letter-spacing: .04em; }
244
+ /* shadcn's custom colours: a light tint and the word pulled toward the ink, so it reads in light and dark alike */
245
+ .cn-badge[class*="cx-tone-"] { background: color-mix(in oklch, var(--tone, var(--muted-foreground)) 14%, transparent); color: color-mix(in oklch, var(--tone, var(--muted-foreground)) 72%, var(--foreground)); }
246
+ .cx-tone-new { --tone: var(--info); }
247
+ .cx-tone-ok { --tone: var(--success); }
248
+ .cx-tone-wait { --tone: var(--warning); }
249
+ .cx-tone-bad { --tone: var(--destructive); }
250
+ .cn-badge.cx-tone-pro { background: var(--selected); color: var(--selected-foreground); letter-spacing: .04em; }
251
+ .cn-badge[class*="cx-tone-"] .cx-dot { background: var(--tone, currentColor); }
252
+ /* IconBadge / LinkBadge: shadcn's data-icon padding (the side with the icon is tighter), icon 12 px */
253
+ .cn-badge.cx-badge-icon { padding-left: 6px; }
254
+ .cn-badge.cx-badge-icon.cx-badge-end { padding-left: 8px; padding-right: 6px; }
255
+ .cn-badge.cx-badge-icon > svg, .cn-badge.cx-badge-icon > .cn-spinner { width: 12px; height: 12px; flex: none; }
256
+ .cn-badge.cx-badge-end > :first-child { order: 2; }
257
+ .cn-badge.cx-badge-link { text-decoration: none; }
246
258
  .cx-dot { width: 6px; height: 6px; border-radius: 99px; background: currentColor; flex: none; }
247
259
 
248
260
 
@@ -260,8 +272,16 @@ button.cn-item { width: 100%; font: inherit; text-align: left; cursor: pointer;
260
272
  [aria-checked="true"] > .cx-radio { border-color: var(--selected); }
261
273
  [aria-checked="true"] > .cx-radio::after { content: ""; width: 8px; height: 8px; border-radius: 99px; background: var(--selected); }
262
274
 
263
- .cx-sortable .cx-item { transition: transform 180ms cubic-bezier(.22, 1, .36, 1); background: var(--background); }
264
- .cx-sortable .cx-item.lifting { transition: none; z-index: 2; box-shadow: 0 8px 24px -8px rgb(0 0 0 / .25); position: relative; }
275
+ /* Sortable (sortable-behavior.js): the others slide apart, the row taken lifts and follows the pointer, a ghost of it
276
+ glides to where it will land; on release it settles onto the ghost */
277
+ .cx-sortable { position: relative; }
278
+ .cx-sortable .cx-item { position: relative; transition: translate var(--t-move) var(--ease-out); background: var(--background); }
279
+ .cx-sortable .cx-item.lifting { z-index: 3; scale: 1.02; cursor: grabbing; border-color: color-mix(in srgb, var(--foreground) 22%, transparent); box-shadow: 0 1px 2px rgb(0 0 0 / .06), 0 14px 32px -12px rgb(0 0 0 / .32); transition: scale var(--t-micro) var(--ease-out), box-shadow var(--t-micro) var(--ease-out), border-color var(--t-micro) var(--ease-out); } /* the border reads where the shadow does not (dark) */
280
+ .cx-sortable .cx-item.settling { z-index: 3; transition: translate 200ms var(--ease-out), scale 200ms var(--ease-out), box-shadow 200ms var(--ease-out); }
281
+ .cx-sortable .cx-item.cx-sort-ghost { position: absolute; top: 0; margin: 0; z-index: 1; pointer-events: none; opacity: 0; border-style: dashed; border-color: color-mix(in srgb, var(--selected) 55%, transparent); background: color-mix(in srgb, var(--selected) 6%, var(--background)); box-shadow: none; scale: 1; transition: translate var(--t-move) var(--ease-out), opacity var(--t-micro) var(--ease-out); }
282
+ .cx-sortable .cx-item.cx-sort-ghost.on { opacity: 1; }
283
+ .cx-sortable .cx-item.cx-sort-ghost > * { opacity: .45; }
284
+ :root.cx-sorting, :root.cx-sorting * { cursor: grabbing !important; user-select: none; }
265
285
 
266
286
  /* ── Card de forma fija ── */
267
287
  .cx-fixed-card { width: 100%; max-width: 380px; }
@@ -285,7 +305,7 @@ button.cn-item { width: 100%; font: inherit; text-align: left; cursor: pointer;
285
305
 
286
306
 
287
307
 
288
- .cx-tab-ind { position: absolute; z-index: 0; top: 3px; height: 26px; border-radius: calc(var(--radius) * .8); background: var(--background); box-shadow: 0 1px 3px 0 rgb(0 0 0 / .1), 0 1px 2px -1px rgb(0 0 0 / .1); transition: left 260ms cubic-bezier(.22, 1, .36, 1), width 260ms cubic-bezier(.22, 1, .36, 1); }
308
+ .cx-tab-ind { position: absolute; z-index: 0; top: 3px; height: 26px; border-radius: calc(var(--radius) * .8); background: var(--background); box-shadow: 0 1px 3px 0 rgb(0 0 0 / .1), 0 1px 2px -1px rgb(0 0 0 / .1); transition: left var(--t-move) var(--ease-out), width var(--t-move) var(--ease-out); }
289
309
  .cx-tabs.line { background: transparent; border-bottom: 1px solid var(--border); border-radius: 0; padding: 0; }
290
310
 
291
311
  .cx-tabs.line .cx-tab-ind { top: auto; bottom: -1px; height: 2px; border-radius: 2px; background: var(--selected); box-shadow: none; }
@@ -320,7 +340,8 @@ button.cn-item { width: 100%; font: inherit; text-align: left; cursor: pointer;
320
340
  .cx-book-sum b { color: var(--foreground); font-weight: 600; }
321
341
 
322
342
  /* ── Modal adaptable: Dialog en escritorio, Drawer en el teléfono (o forzado con data-mode) ── */
323
- .cx-overlay { position: fixed; inset: 0; z-index: var(--z-modal); background: var(--overlay); backdrop-filter: blur(4px); opacity: 0; transition: opacity 160ms ease; }
343
+ .cx-overlay { position: fixed; inset: 0; z-index: var(--z-modal); background: var(--overlay); backdrop-filter: blur(4px); opacity: 0; transition: opacity calc(var(--t-modal) * .62) ease; }
344
+ .cx-modal-root[data-open="true"] > .cx-overlay { transition-duration: calc(var(--t-modal) * .84); }
324
345
  .cx-overlay[data-state="open"] { opacity: 1; }
325
346
  .cx-modal { position: fixed; z-index: var(--z-modal); display: flex; flex-direction: column; background: var(--popover); color: var(--popover-foreground); box-shadow: 0 0 0 1px color-mix(in srgb, var(--foreground) 10%, transparent), 0 20px 25px -5px rgb(0 0 0 / .1); outline: none; font-size: 14px;
326
347
  /* one height for every control in a modal's form: a select, a time and a text field side by side read as one form */
@@ -341,11 +362,13 @@ button.cn-item { width: 100%; font: inherit; text-align: left; cursor: pointer;
341
362
  .cx-handle { display: none; width: 96px; height: 4px; margin: 10px auto 0; border-radius: 99px; background: var(--muted); flex: none; }
342
363
  /* escritorio = Dialog */
343
364
  .cx-modal[data-mode="dialog"] { top: 50%; left: 50%; width: min(28rem, calc(100% - 2rem)); max-height: min(36rem, calc(100dvh - 4rem)); border-radius: calc(var(--radius) * 1.4); overflow: hidden;
344
- transform: translate(-50%, -50%) scale(.95); opacity: 0; transition: transform 160ms cubic-bezier(.22, 1, .36, 1), opacity 160ms ease; }
365
+ transform: translate(-50%, calc(-50% + 6px)) scale(.97); opacity: 0; transition: transform calc(var(--t-modal) * .62) ease, opacity calc(var(--t-modal) * .5) ease; }
366
+ /* entering is slower than leaving: it comes up from 6 px lower at 97 %, and goes in about 0.6 of the time */
367
+ .cx-modal[data-mode="dialog"][data-state="open"], .cx-modal-root[data-open="true"] > .cx-modal[data-mode="dialog"] { transition: transform var(--t-modal) var(--ease-out), opacity calc(var(--t-modal) * .75) var(--ease-out); }
345
368
  .cx-modal[data-mode="dialog"][data-state="open"] { transform: translate(-50%, -50%); opacity: 1; }
346
369
  /* teléfono = Drawer desde abajo, arrastrable */
347
370
  .cx-modal[data-mode="drawer"] { left: 0; right: 0; bottom: 0; margin-inline: auto; width: min(100%, 34rem); max-height: calc(100dvh - 3rem); border-radius: calc(var(--radius) * 1.8) calc(var(--radius) * 1.8) 0 0; overflow: hidden;
348
- transform: translateY(100%); transition: transform 450ms cubic-bezier(.32, .72, 0, 1); touch-action: none; }
371
+ transform: translateY(100%); transition: transform 450ms var(--ease-drawer); touch-action: none; }
349
372
  .cx-modal[data-mode="drawer"][data-state="open"] { transform: translateY(0); }
350
373
  .cx-modal[data-mode="drawer"] .cx-handle { display: block; }
351
374
  .cx-modal[data-mode="drawer"] .cx-modal-body { touch-action: pan-y; }
@@ -367,7 +390,8 @@ button.cn-item { width: 100%; font: inherit; text-align: left; cursor: pointer;
367
390
  .cx-sw i { width: 22px; height: 22px; border-radius: 6px; box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--foreground) 15%, transparent); flex: none; }
368
391
 
369
392
  /* ── 44 px touch target without changing the drawn size ── */
370
- @media (pointer: coarse) { .cn-button { position: relative; } .cn-button::before { content: ""; position: absolute; left: 50%; top: 50%; width: max(100%, 44px); height: max(100%, 44px); transform: translate(-50%, -50%); } }
393
+ /* :where() keeps it at zero specificity: a button placed on purpose (the modal ✕, a pinned action) keeps its position */
394
+ @media (pointer: coarse) { :where(.cn-button) { position: relative; } .cn-button::before { content: ""; position: absolute; left: 50%; top: 50%; width: max(100%, 44px); height: max(100%, 44px); transform: translate(-50%, -50%); } }
371
395
 
372
396
  /* ── page scaffolding for this preview (not part of the library) ── */
373
397
  .cx-lib { display: flex; flex-direction: column; gap: 18px; }
@@ -432,7 +456,7 @@ html.cx-locked { overflow: hidden; }
432
456
  .cx-who b { display: block; font-weight: 500; }
433
457
  .cx-who small { color: var(--muted-foreground); font-size: 13px; }
434
458
  .cx-online { background: var(--success) !important; box-shadow: 0 0 0 2px var(--background); }
435
- .cx-tip { position: fixed; z-index: var(--z-toast); padding: 6px 12px; border-radius: calc(var(--radius) - 2px); background: var(--foreground); color: var(--background); font-size: 12px; font-weight: 500; line-height: 1.35; white-space: nowrap; pointer-events: none; opacity: 0; transform: translateY(3px) scale(.96); transform-origin: var(--ax, 50%) 100%; transition: opacity 120ms ease-out, transform 160ms cubic-bezier(.23, 1, .32, 1); }
459
+ .cx-tip { position: fixed; z-index: var(--z-toast); padding: 6px 12px; border-radius: calc(var(--radius) - 2px); background: var(--foreground); color: var(--background); font-size: 12px; font-weight: 500; line-height: 1.35; white-space: nowrap; pointer-events: none; opacity: 0; transform: translateY(3px) scale(.96); transform-origin: var(--ax, 50%) 100%; transition: opacity calc(var(--t-micro) * .8) ease-out, transform var(--t-micro) var(--ease-out); }
436
460
  /* its arrow, toward the trigger (shadcn's TooltipArrow: the pill's own colour, a softly rounded square half out) */
437
461
  .cx-tip::after { content: ""; position: absolute; left: calc(var(--ax, 50%) - 5px); bottom: -4px; width: 10px; height: 10px; border-radius: 2px; background: inherit; transform: rotate(45deg); }
438
462
  .cx-tip[data-side="bottom"] { transform: translateY(-3px) scale(.96); transform-origin: var(--ax, 50%) 0; }
@@ -449,7 +473,13 @@ html.cx-locked { overflow: hidden; }
449
473
  /* ── Fields ── */
450
474
  .cx-form { display: flex; flex-direction: column; gap: 18px; width: 100%; max-width: 380px; }
451
475
  .cx-num { font-variant-numeric: tabular-nums; }
452
- .cx-clear { opacity: 1; transition: opacity 120ms ease; }
476
+ /* the browser's own clear X never shows: SearchInput draws its own (.cx-clear) in its end addon, where it keeps its
477
+ place empty or not, so nothing beside it moves */
478
+ /* on EVERY search field of an app with the kit, not only .cn-input: muten writes each SearchField as type=search, and
479
+ Chrome drew its own X behind whatever sits at the field's end (Storio's «Ask Storio» send button) */
480
+ input[type="search"]::-webkit-search-cancel-button, input[type="search"]::-webkit-search-decoration { -webkit-appearance: none; appearance: none; display: none; }
481
+ .cx-clear { opacity: 1; transition: opacity 120ms ease, visibility 120ms; }
482
+ .cx-clear.cx-off { opacity: 0; visibility: hidden; }
453
483
  .cx-clear[hidden] { display: inline-flex !important; opacity: 0; pointer-events: none; }
454
484
  .cx-count-line { display: flex; justify-content: space-between; gap: 12px; }
455
485
  .cx-count-line span:last-child { font-variant-numeric: tabular-nums; flex: none; }
@@ -461,8 +491,8 @@ html.cx-locked { overflow: hidden; }
461
491
 
462
492
  /* ── Combobox list: under the field, its width, Nova's popover look ── */
463
493
  .cx-combo-list { max-height: 248px; overflow-y: auto; padding: 4px; border-radius: calc(var(--radius) * 1); background: var(--popover); color: var(--popover-foreground); box-shadow: 0 0 0 1px color-mix(in srgb, var(--foreground) 10%, transparent), 0 4px 6px -1px rgb(0 0 0 / .1), 0 2px 4px -2px rgb(0 0 0 / .1); font-size: 14px; overscroll-behavior: contain;
464
- opacity: 0; transform: scale(.96); transition: opacity 100ms ease, transform 100ms ease !important; transition-property: opacity, transform !important; }
465
- .cx-combo-list[data-state="open"] { opacity: 1; transform: none; }
494
+ opacity: 0; transform: scale(.96); transition: opacity calc(var(--t-pop) * .67) ease, transform calc(var(--t-pop) * .67) ease !important; transition-property: opacity, transform !important; }
495
+ .cx-combo-list[data-state="open"] { opacity: 1; transform: none; transition-duration: var(--t-pop) !important; transition-timing-function: var(--ease-out) !important; }
466
496
  .cx-opt { display: flex; align-items: center; gap: 8px; min-height: 32px; padding: 6px 8px; border-radius: calc(var(--radius) * .6); cursor: default; user-select: none; }
467
497
  .cx-opt[data-hl] { background: var(--accent); color: var(--accent-foreground); }
468
498
  .cx-opt mark { background: none; color: inherit; font-weight: 600; }
@@ -490,7 +520,7 @@ html.cx-locked { overflow: hidden; }
490
520
  .cx-fake i { display: block; height: 34px; border-radius: calc(var(--radius) * .8); background: var(--muted); }
491
521
  .cx-fake i:nth-child(2n) { width: 80%; }
492
522
  /* Band: grows its own height in, pushes content (never covers it), one at a time */
493
- .cx-band-slot { display: grid; grid-template-rows: 0fr; transition: grid-template-rows 260ms cubic-bezier(.22, 1, .36, 1); flex: none; }
523
+ .cx-band-slot { display: grid; grid-template-rows: 0fr; transition: grid-template-rows 260ms var(--ease-out); flex: none; }
494
524
  .cx-band-slot[data-open] { grid-template-rows: 1fr; }
495
525
  .cx-band-slot > div { overflow: hidden; min-height: 0; }
496
526
  .cx-band { display: flex; align-items: center; gap: 10px; padding: 9px 14px 9px 18px; font-size: 13px; line-height: 1.35; border-bottom: 1px solid var(--border); }
@@ -506,16 +536,16 @@ html.cx-locked { overflow: hidden; }
506
536
  .cx-band-slot:not([data-open]) > div > .cx-band { opacity: 0; }
507
537
  /* Island: one pill that changes shape and text in place */
508
538
  .cx-island { position: absolute; top: 10px; left: 50%; z-index: 3; display: flex; align-items: center; gap: 8px; height: 34px; padding: 0 14px 0 10px; border-radius: 99px; background: oklch(0.16 0 0); color: #fff; font-size: 13px; font-weight: 500; white-space: nowrap; overflow: hidden;
509
- transform: translateX(-50%); transition: width 380ms cubic-bezier(.22, 1, .36, 1), opacity 200ms ease, transform 380ms cubic-bezier(.22, 1, .36, 1); }
539
+ transform: translateX(-50%); transition: width 380ms var(--ease-out), opacity 200ms ease, transform 380ms var(--ease-out); }
510
540
  .cx-island[data-state="hidden"] { opacity: 0; transform: translateX(-50%) scale(.7); }
511
541
  .cx-island-icon { width: 18px; height: 18px; display: grid; place-items: center; flex: none; }
512
542
  .cx-island-icon svg { width: 16px; height: 16px; }
513
543
  .cx-island[data-tone="done"] .cx-island-icon { color: oklch(0.8 0.17 150); }
514
544
  .cx-island[data-tone="error"] .cx-island-icon { color: oklch(0.72 0.19 25); }
515
- .cx-island[data-tone="error"] { animation: cx-shake 320ms ease; }
545
+ .cx-island[data-tone="error"] { animation: cx-shake calc(var(--t-move) * 1.35) var(--ease-out); }
516
546
  .cx-island-text { transition: opacity 140ms ease; }
517
547
  .cx-island-text.swap { opacity: 0; }
518
- @keyframes cx-shake { 25% { margin-left: -4px; } 75% { margin-left: 4px; } }
548
+ @keyframes cx-shake { 25% { translate: -4px 0; } 75% { translate: 4px 0; } } /* translate, not margin: a shake never moves the layout around it */
519
549
 
520
550
  /* ── Accordion chevron rotates ── */
521
551
  .cx-acc-chev { margin-left: auto; width: 16px; height: 16px; flex: none; color: var(--muted-foreground); transition: transform 200ms ease; pointer-events: none; }
@@ -565,7 +595,7 @@ html.cx-locked { overflow: hidden; }
565
595
  .cx-otp-sep span { width: 8px; height: 2px; border-radius: 2px; background: var(--muted-foreground); }
566
596
  .cx-otp .cn-input-otp { display: flex; align-items: center; }
567
597
  .cx-otp[data-state="bad"] .cn-input-otp-slot { border-color: var(--destructive); }
568
- .cx-otp[data-state="bad"] { animation: cx-shake 320ms ease; }
598
+ .cx-otp[data-state="bad"] { animation: cx-shake calc(var(--t-move) * 1.35) var(--ease-out); }
569
599
  .cx-otp[data-state="ok"] .cn-input-otp-slot { border-color: var(--success); color: var(--success); }
570
600
  #otp-msg[data-tone="bad"] { color: var(--destructive); }
571
601
  #otp-msg[data-tone="ok"] { color: var(--success); }
@@ -698,9 +728,9 @@ html.cx-locked { overflow: hidden; }
698
728
  .cx-check { width: 16px; }
699
729
 
700
730
  /* ── DataTable: a table while its box is wide, a list of Items when the box is narrow ── */
701
- .cx-dt-host { container-type: inline-size; width: 100%; max-width: 920px; margin: 0 auto; display: flex; flex-direction: column; transition: max-width 320ms cubic-bezier(.22, 1, .36, 1); }
731
+ .cx-dt-host { container-type: inline-size; width: 100%; max-width: 920px; margin: 0 auto; display: flex; flex-direction: column; transition: max-width 320ms var(--ease-out); }
702
732
  .cx-dt-host[data-narrow] { max-width: 380px; }
703
- .cx-dt-bulk { display: grid; grid-template-rows: 0fr; transition: grid-template-rows 220ms cubic-bezier(.22, 1, .36, 1); }
733
+ .cx-dt-bulk { display: grid; grid-template-rows: 0fr; transition: grid-template-rows 220ms var(--ease-out); }
704
734
  .cx-dt-bulk[data-open] { grid-template-rows: 1fr; }
705
735
  .cx-dt-bulk > div { overflow: hidden; min-height: 0; display: flex; align-items: center; justify-content: space-between; gap: 12px; font-size: 13px; font-weight: 500; }
706
736
  .cx-dt-bulk[data-open] > div { padding: 0 4px 10px; }
@@ -709,7 +739,6 @@ html.cx-locked { overflow: hidden; }
709
739
  .cx-dt th { position: sticky; top: 0; z-index: 1; background: var(--muted); text-align: left; font-weight: 500; color: var(--muted-foreground); height: 40px; padding: 0 12px; border-bottom: 1px solid var(--border); white-space: nowrap; }
710
740
  .cx-dt td { height: 52px; padding: 0 12px; border-bottom: 1px solid var(--border); vertical-align: middle; }
711
741
  .cx-dt tbody tr:last-child td { border-bottom: 0; }
712
- .cx-dt tbody tr { transition: background-color 120ms; }
713
742
  .cx-dt tbody tr:hover { background: color-mix(in srgb, var(--muted) 50%, transparent); }
714
743
  .cx-dt tbody tr[data-selected] { background: var(--selected-soft); }
715
744
  .cx-dt .cx-dt-check { width: 40px; padding-right: 0; }
@@ -1282,7 +1311,7 @@ html.cx-locked { overflow: hidden; }
1282
1311
  .cn-item-description .cx-ellipsis, .cn-item-description { overflow: hidden; text-overflow: ellipsis; }
1283
1312
 
1284
1313
  /* ═════ board behaviour only (the look is the Card atom) ═════ */
1285
- .cx-bcard { cursor: grab; touch-action: none; user-select: none; transition: transform 200ms cubic-bezier(.22, 1, .36, 1), box-shadow 150ms; }
1314
+ .cx-bcard { cursor: grab; touch-action: none; user-select: none; transition: transform 200ms var(--ease-out), box-shadow 150ms; }
1286
1315
  .cx-bcard-static { cursor: default; touch-action: auto; user-select: auto; }
1287
1316
  .cx-bcard:focus-visible { outline: 2px solid var(--ring); outline-offset: 2px; }
1288
1317
  .cx-bcard[data-lifted], .cx-bcard[data-held] { box-shadow: 0 0 0 2px var(--selected), 0 12px 28px -10px rgb(0 0 0 / .3); }
@@ -1310,6 +1339,11 @@ html.cx-locked { overflow: hidden; }
1310
1339
  .cx-tab { position: relative; z-index: 1; color: color-mix(in srgb, var(--foreground) 62%, transparent); }
1311
1340
  .cx-tab:hover { background: transparent; color: var(--foreground); }
1312
1341
  .cx-tab[aria-selected="true"] { color: var(--foreground); }
1342
+ /* only the pill moves: a tab never paints its own fill (hover, press, focus, chosen), or the clicked tab shows a second
1343
+ box under the pill while it slides; the word changes colour on the pill's own 260 ms curve */
1344
+ .cx-tabs > .cn-button.cx-tab, .cx-tabs > .cn-button.cx-tab:is(:hover, :active, :focus-visible, [aria-selected="true"], [aria-expanded="true"]) { background: transparent; border-color: transparent; box-shadow: none; transform: none; }
1345
+ .cx-tabs > .cn-button.cx-tab:focus-visible { outline: 2px solid var(--ring); outline-offset: -2px; }
1346
+ .cx-tabs > .cn-button.cx-tab { transition: color var(--t-move) var(--ease-out); }
1313
1347
  /* a segment picks with the sliding pill, not with a filled button: beats the generic «pressed = selected» fill above */
1314
1348
  .cx-tabs > .cn-button.cx-tab[aria-pressed="true"][aria-pressed][aria-pressed],
1315
1349
  .cx-tabs > .cn-button.cx-tab[aria-pressed="true"][aria-pressed][aria-pressed]:hover { background: transparent; border-color: transparent; color: var(--foreground); }
@@ -1338,7 +1372,7 @@ th[aria-sort="ascending"] .cx-th svg, th[aria-sort="descending"] .cx-th svg { op
1338
1372
  .cx-ph-tab[aria-current] { color: var(--selected); background: transparent; }
1339
1373
  .cx-ph-tab[aria-current]::after { content: ""; position: absolute; bottom: 4px; width: 4px; height: 4px; border-radius: 99px; background: var(--selected); }
1340
1374
  /* carousel dots: a real button (24 px) with a small mark */
1341
- .cx-dotb .cx-dot-mark { width: 8px; height: 8px; border-radius: 99px; background: color-mix(in srgb, var(--foreground) 22%, transparent); transition: width 240ms cubic-bezier(.22, 1, .36, 1), background-color 200ms; }
1375
+ .cx-dotb .cx-dot-mark { width: 8px; height: 8px; border-radius: 99px; background: color-mix(in srgb, var(--foreground) 22%, transparent); transition: width 240ms var(--ease-out), background-color 200ms; }
1342
1376
  .cx-dotb[aria-selected="true"] { width: 34px; }
1343
1377
  .cx-dotb[aria-selected="true"] .cx-dot-mark { width: 22px; background: var(--selected); }
1344
1378
  .cx-car-dots { display: flex; gap: 0; }
@@ -1361,6 +1395,9 @@ th[aria-sort="ascending"] .cx-th svg, th[aria-sort="descending"] .cx-th svg { op
1361
1395
  .cn-card[data-size="sm"] { gap: 0; padding-block: 0; }
1362
1396
  .cn-card[data-size="sm"] > .cn-card-header { padding: 12px 12px 4px; }
1363
1397
  .cn-card[data-size="sm"] > .cn-card-content { padding: 0 12px; }
1398
+ /* a content with nothing above or below it keeps the card's 12 px there too (it was glued to the edge) */
1399
+ .cn-card[data-size="sm"] > .cn-card-content:first-child { padding-top: 12px; }
1400
+ .cn-card[data-size="sm"] > .cn-card-content:last-child { padding-bottom: 12px; }
1364
1401
  .cn-card[data-size="sm"] > .cn-card-footer { margin-top: 8px; padding: 10px 12px; }
1365
1402
  .cn-card[data-size="sm"] .cn-item-group { gap: 0; }
1366
1403
  .cn-card[data-size="sm"] .cn-item-separator { margin-block: 0; }
@@ -1423,10 +1460,15 @@ p.cx-text { margin: 0; }
1423
1460
  .cx-car-track.dragging { scroll-snap-type: none; scroll-behavior: auto; cursor: grabbing; user-select: none; }
1424
1461
  .cx-car-track:focus-visible { outline: 2px solid var(--ring); outline-offset: 4px; }
1425
1462
  .cx-car-slide { scroll-snap-align: start; min-width: 0; }
1463
+ /* a scrolling track clips both axes: 6 px of room above and below keeps a card's ring and shadow whole (it was cut at
1464
+ the top), taken back with a negative margin so the carousel does not grow */
1465
+ .cx-car-track { padding-block: 6px; margin-block: -6px; }
1426
1466
  /* while the mouse drags the track it follows the hand; on release kit core settles it on the nearest page */
1427
1467
  .cx-car-track.dragging { scroll-snap-type: none; scroll-behavior: auto; cursor: grabbing; user-select: none; }
1428
- .cx-car[data-center] .cx-car-track { grid-auto-columns: 72%; padding-inline: 14%; }
1429
- .cx-car[data-center] .cx-car-slide { scroll-snap-align: center; transition: transform 260ms cubic-bezier(.22, 1, .36, 1), opacity 260ms; transform: scale(.92); opacity: .55; }
1468
+ /* centred like Embla's containScroll: the first slide sits at the start and the last at the end (no empty strip
1469
+ beside them), the ones between snap to the centre */
1470
+ .cx-car[data-center] .cx-car-track { grid-auto-columns: 72%; }
1471
+ .cx-car[data-center] .cx-car-slide { scroll-snap-align: center; transition: transform 260ms var(--ease-out), opacity 260ms; transform: scale(.92); opacity: .55; }
1430
1472
  .cx-car[data-center] .cx-car-slide[data-active] { transform: none; opacity: 1; }
1431
1473
  .cx-car-bar { display: flex; align-items: center; justify-content: space-between; gap: 12px; min-height: 28px; }
1432
1474
  .cx-car-ind { flex: 1; min-width: 0; }
@@ -1473,9 +1515,9 @@ p.cx-text { margin: 0; }
1473
1515
  .cn-sidebar-menu-badge { background: color-mix(in srgb, var(--foreground) 8%, transparent); }
1474
1516
 
1475
1517
  /* ═════ App frame (the shell is a molecule of Sidebar + Inset + Sheet) ═════ */
1476
- .cx-app { position: relative; display: flex; height: 600px; width: 100%; max-width: 1180px; margin: 0 auto; border-radius: calc(var(--radius) * 1.6); overflow: hidden; background: var(--background); box-shadow: 0 0 0 1px var(--border), 0 24px 60px -30px rgb(0 0 0 / .35); transition: max-width 320ms cubic-bezier(.22, 1, .36, 1); }
1518
+ .cx-app { position: relative; display: flex; height: 600px; width: 100%; max-width: 1180px; margin: 0 auto; border-radius: calc(var(--radius) * 1.6); overflow: hidden; background: var(--background); box-shadow: 0 0 0 1px var(--border), 0 24px 60px -30px rgb(0 0 0 / .35); transition: max-width 320ms var(--ease-out); }
1477
1519
  .cx-app[data-narrow] { max-width: 390px; }
1478
- .cx-app-sb { flex: none; width: var(--sidebar-width); border-right: 1px solid var(--sidebar-border); transition: width 220ms cubic-bezier(.22, 1, .36, 1); overflow: hidden; }
1520
+ .cx-app-sb { flex: none; width: var(--sidebar-width); border-right: 1px solid var(--sidebar-border); transition: width 220ms var(--ease-out); overflow: hidden; }
1479
1521
  .cx-app-sb[data-collapsible="icon"] { width: var(--sidebar-width-icon); }
1480
1522
  .cx-app-sb .cn-sidebar-inner { height: 100%; display: flex; flex-direction: column; padding: 8px; gap: 8px; }
1481
1523
  .cx-app-sb .cn-sidebar-content { gap: 6px; }
@@ -1492,12 +1534,12 @@ p.cx-text { margin: 0; }
1492
1534
  .cx-app-head { display: flex; flex-wrap: wrap; align-items: flex-end; justify-content: space-between; gap: 12px; }
1493
1535
  .cx-app-head h1.cx-text { margin: 0; font-size: 22px; }
1494
1536
  .cx-app-list { gap: 8px; }
1495
- .cx-app-row { width: 100%; text-align: left; font: inherit; color: inherit; background: var(--background); cursor: pointer; transition: background-color 150ms, border-color 150ms; }
1537
+ .cx-app-row { width: 100%; text-align: left; font: inherit; color: inherit; background: var(--background); cursor: pointer; }
1496
1538
  .cx-app-row:hover { background: color-mix(in srgb, var(--foreground) 3%, var(--background)); }
1497
1539
  .cx-app-row[data-active] { border-color: var(--selected); background: var(--selected-soft); }
1498
1540
  .cx-app-row .cn-item-actions { gap: 14px; }
1499
1541
  /* detail Sheet: inside the frame, slides from the right */
1500
- .cx-app .cn-sheet-content.cx-app-sheet[data-side] { position: absolute; top: 0; bottom: 0; right: 0; left: auto; height: auto; max-width: none; width: min(380px, 100%); border-left: 1px solid var(--border); box-shadow: -18px 0 40px -24px rgb(0 0 0 / .3); gap: 0; z-index: 3; transform: translateX(100%); transition: transform 240ms cubic-bezier(.22, 1, .36, 1); }
1542
+ .cx-app .cn-sheet-content.cx-app-sheet[data-side] { position: absolute; top: 0; bottom: 0; right: 0; left: auto; height: auto; max-width: none; width: min(380px, 100%); border-left: 1px solid var(--border); box-shadow: -18px 0 40px -24px rgb(0 0 0 / .3); gap: 0; z-index: 3; transform: translateX(100%); transition: transform 240ms var(--ease-out); }
1501
1543
  .cx-app .cn-sheet-content.cx-app-sheet[data-side][data-state="open"] { transform: none; }
1502
1544
  .cx-app-sheet .cn-sheet-header { padding: 16px 16px 8px; }
1503
1545
  .cx-app-sheet-body { flex: 1; overflow-y: auto; padding: 0 12px; scrollbar-width: thin; }
@@ -1514,7 +1556,7 @@ p.cx-text { margin: 0; }
1514
1556
  .cx-timeline li:not(:last-child)::after { content: ""; position: absolute; left: 3.5px; top: 18px; bottom: -10px; width: 1px; background: var(--border); }
1515
1557
  .cx-timeline li[data-now]::before { background: var(--selected); box-shadow: 0 0 0 4px var(--selected-soft); }
1516
1558
  /* the shell on a narrow box: sidebar becomes an off-canvas menu */
1517
- .cx-app[data-mobile] .cx-app-sb { position: absolute; z-index: 4; top: 0; bottom: 0; left: 0; width: min(270px, 85%); transform: translateX(-102%); transition: transform 240ms cubic-bezier(.22, 1, .36, 1); box-shadow: 18px 0 40px -24px rgb(0 0 0 / .35); }
1559
+ .cx-app[data-mobile] .cx-app-sb { position: absolute; z-index: 4; top: 0; bottom: 0; left: 0; width: min(270px, 85%); transform: translateX(-102%); transition: transform 240ms var(--ease-out); box-shadow: 18px 0 40px -24px rgb(0 0 0 / .35); }
1518
1560
  .cx-app[data-mobile][data-sb-open] .cx-app-sb { transform: none; }
1519
1561
  .cx-app[data-mobile] [data-app-scrim]:not([hidden]) { opacity: 1; z-index: 3; }
1520
1562
  .cx-app[data-mobile] .cx-app-search { width: 36px; padding: 0; justify-content: center; }
@@ -1533,21 +1575,6 @@ p.cx-text { margin: 0; }
1533
1575
 
1534
1576
 
1535
1577
  /* ═════════════════════════ 3. sys ═════════════════════════ */
1536
- /* ═════ Button · icon motion on hover (atom-level, every button with an icon) ═════ */
1537
- .cn-button svg { transition: transform 180ms cubic-bezier(.22, 1, .36, 1); }
1538
- @media (hover: hover) and (prefers-reduced-motion: no-preference) {
1539
- .cn-button:not(:disabled):hover > svg:last-child:not(:first-child) { transform: translateX(2px); } /* trailing arrow moves on */
1540
- .cn-button:not(:disabled):hover > svg:first-child:not(:last-child) { transform: scale(1.12); } /* leading icon lifts */
1541
- .cn-button:not(:disabled):hover > svg:first-child:not(:last-child):has(use[href="#plus"]) { transform: rotate(90deg); }
1542
- .cn-button:not(:disabled):hover > svg:only-child { transform: scale(1.12); }
1543
- .cn-button:not(:disabled):hover > svg:only-child:has(use[href="#left"]) { transform: translateX(-2px); }
1544
- .cn-button:not(:disabled):hover > svg:only-child:has(use[href="#right"]) { transform: translateX(2px); }
1545
- .cn-button:not(:disabled):hover > svg:only-child:has(use[href="#x"]) { transform: rotate(90deg); }
1546
- .cn-button:not(:disabled):hover > svg:only-child:has(use[href="#i-send"]) { transform: translate(2px, -2px); }
1547
- .cn-button:not(:disabled):hover > svg:only-child:has(use[href="#i-bell"]) { animation: cx-ring 600ms ease; }
1548
- .cn-button:not(:disabled):active > svg { transform: scale(.92); }
1549
- }
1550
- @keyframes cx-ring { 20% { transform: rotate(14deg); } 40% { transform: rotate(-12deg); } 60% { transform: rotate(8deg); } 80% { transform: rotate(-4deg); } }
1551
1578
 
1552
1579
  /* ═════ Calendar ═════ */
1553
1580
  .cx-cal { position: relative; display: inline-flex; flex-direction: column; gap: 8px; padding: 12px; border-radius: calc(var(--radius) * 1.2); box-shadow: 0 0 0 1px var(--border); background: var(--background); }
@@ -1571,28 +1598,39 @@ p.cx-text { margin: 0; }
1571
1598
  /* ═════ Agenda ═════ */
1572
1599
  .cx-agenda { display: flex; flex-direction: column; gap: 12px; width: 100%; max-width: var(--agenda-max, none); margin: 0 auto; }
1573
1600
  .cx-ag-bar { display: flex; flex-wrap: wrap; align-items: center; gap: 8px 10px; }
1601
+ /* Today · the date · Day/List stay on ONE row: the date gives way (ellipsis), the view switch never drops below */
1602
+ .cx-ag-bar:not(:has(> .cx-text[data-variant="heading"])) { flex-wrap: nowrap; }
1603
+ .cx-ag-bar > .cx-ag-title { flex: 0 1 auto; }
1604
+ .cx-ag-bar > .cx-tabs, .cx-ag-bar > .cn-button { flex: none; }
1574
1605
  .cx-ag-scroll { max-height: 520px; overflow: auto; }
1575
1606
  .cx-ag { position: relative; display: grid; grid-template-rows: 36px 1fr; min-width: calc(56px + var(--cols) * 140px); }
1576
1607
  .cx-ag-head { position: sticky; top: 0; z-index: 3; display: grid; grid-template-columns: 56px repeat(var(--cols), 1fr); background: var(--background); border-bottom: 1px solid var(--border); }
1577
1608
  .cx-ag-colhead { display: grid; place-items: center; font-size: 13px; font-weight: 600; border-left: 1px solid var(--border); }
1578
1609
  .cx-ag-body { position: relative; display: grid; grid-template-columns: 56px repeat(var(--cols), 1fr); background-image: repeating-linear-gradient(to bottom, var(--border) 0 1px, transparent 1px var(--h)); }
1579
1610
  .cx-ag-times { position: relative; }
1580
- .cx-ag-times span { position: absolute; right: 8px; transform: translateY(-50%); white-space: nowrap; }
1581
- .cx-ag-times span:first-child { transform: none; }
1611
+ /* only the hour's own box (a direct child) sits on its line, centred on it; the text inside it is not a second
1612
+ absolute box (it was: the box collapsed to 0 high and the hour hung below its line) */
1613
+ .cx-ag-times > span { position: absolute; right: 8px; transform: translateY(-50%); white-space: nowrap; line-height: 1; }
1614
+ .cx-ag-times > span:first-child { transform: none; }
1582
1615
  .cx-ag-col { position: relative; border-left: 1px solid var(--border); }
1583
1616
  .cx-ag-slot { position: absolute; left: 0; right: 0; border: 0; background: transparent; cursor: pointer; }
1584
1617
  .cx-ag-slot:hover { background: color-mix(in srgb, var(--selected) 6%, transparent); }
1585
- .cx-ag-ev { --tone: var(--info); position: absolute; left: 4px; right: 4px; z-index: 1; display: flex; flex-direction: column; align-items: flex-start; gap: 0; overflow: hidden; padding: 4px 8px; border: 0; border-radius: calc(var(--radius) * .7); background: color-mix(in srgb, var(--tone) 20%, var(--background)); box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--tone) 28%, transparent); color: var(--foreground); font: inherit; text-align: left; cursor: grab; touch-action: none; transition: box-shadow 150ms, top 160ms cubic-bezier(.22, 1, .36, 1); }
1618
+ .cx-ag-ev { --tone: var(--info); position: absolute; left: 4px; right: 4px; z-index: 1; display: flex; flex-direction: column; align-items: flex-start; gap: 0; overflow: hidden; padding: 4px 8px; border: 0; border-radius: calc(var(--radius) * .7); background: color-mix(in srgb, var(--tone) 20%, var(--background)); box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--tone) 28%, transparent); color: var(--foreground); font: inherit; text-align: left; cursor: grab; touch-action: none; transition: box-shadow 150ms, top 160ms var(--ease-out); }
1586
1619
  .cx-ag-ev[data-tone="ok"] { --tone: var(--success); } .cx-ag-ev[data-tone="wait"] { --tone: var(--warning); } .cx-ag-ev[data-tone="info"] { --tone: var(--info); } .cx-ag-ev[data-tone="bad"] { --tone: var(--destructive); }
1587
1620
  .cx-ag-ev:hover { box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--tone) 40%, transparent), 0 4px 12px -6px rgb(0 0 0 / .35); }
1588
1621
  .cx-ag-ev[data-dragging] { transition: none; cursor: grabbing; z-index: 2; box-shadow: 0 10px 24px -10px rgb(0 0 0 / .4); }
1589
1622
  .cx-ag-ev:focus-visible { outline: 2px solid var(--ring); outline-offset: 1px; }
1590
1623
  .cx-ag-ev .cx-text { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 100%; }
1591
- .cx-ag-now { position: absolute; left: 56px; right: 0; height: 0; border-top: 2px solid var(--destructive); z-index: 2; pointer-events: none; }
1624
+ /* what the app's assistant did (event by "agent"): its mark before the name, ringed so it reads on any tone; on the
1625
+ phone's list, a line under the service. --cx-ag-by-ink colours that line (the app's assistant colour). */
1626
+ .cx-ag-by { display: inline-block; flex: none; width: 13px; height: 13px; margin-right: 4px; vertical-align: -2px; border-radius: 50%; box-shadow: 0 0 0 1.5px var(--background); }
1627
+ .cx-ag-byline { display: inline-flex; align-items: center; gap: 5px; margin-top: 2px; font-size: 12.5px; font-weight: 600; line-height: 1.3; color: var(--cx-ag-by-ink, var(--primary)); }
1628
+ .cx-ag-byline .cx-ag-by { width: 14px; height: 14px; margin: 0; box-shadow: none; }
1629
+ .cx-ag-now { position: absolute; left: 56px; right: 0; height: 0; margin-top: -1px; border-top: 2px solid var(--destructive); z-index: 2; pointer-events: none; } /* the 2px border centred ON the hour, like the pill and its tail */
1592
1630
  .cx-ag-now i { position: absolute; left: -5px; top: -6px; width: 10px; height: 10px; border-radius: 99px; background: var(--destructive); }
1593
1631
 
1594
1632
  /* ═════ Chat (inbox + chatbot) ═════ */
1595
- .cx-inbox { display: grid; grid-template-columns: 300px 1fr; height: 560px; width: 100%; max-width: 980px; margin: 0 auto; border-radius: calc(var(--radius) * 1.6); overflow: hidden; box-shadow: 0 0 0 1px var(--border); background: var(--background); transition: max-width 320ms cubic-bezier(.22, 1, .36, 1); }
1633
+ .cx-inbox { display: grid; grid-template-columns: 300px 1fr; height: 560px; width: 100%; max-width: 980px; margin: 0 auto; border-radius: calc(var(--radius) * 1.6); overflow: hidden; box-shadow: 0 0 0 1px var(--border); background: var(--background); transition: max-width 320ms var(--ease-out); }
1596
1634
  .cx-inbox[data-force-narrow] { max-width: 390px; }
1597
1635
  .cx-ib-list { display: flex; flex-direction: column; min-height: 0; border-right: 1px solid var(--border); }
1598
1636
  .cx-ib-items { flex: 1; overflow-y: auto; padding: 0 8px 8px; display: flex; flex-direction: column; gap: 2px; }
@@ -1633,6 +1671,7 @@ p.cx-text { margin: 0; }
1633
1671
  @keyframes cx-typing { 0%, 60%, 100% { opacity: .3; transform: none; } 30% { opacity: 1; transform: translateY(-3px); } }
1634
1672
  .cx-bot { display: flex; flex-direction: column; width: 100%; max-width: 440px; height: 520px; margin: 0 auto; border-radius: calc(var(--radius) * 1.6); overflow: hidden; box-shadow: 0 0 0 1px var(--border); background: var(--background); }
1635
1673
  .cx-bot-face { display: flex; align-items: center; justify-content: center; gap: 7px; width: 36px; height: 36px; flex: none; border-radius: 12px; background: var(--selected); }
1674
+ .cx-bot-logo { width: 36px; height: 36px; flex: none; border-radius: 12px; object-fit: contain; background: var(--muted); }
1636
1675
  .cx-bot-face i { display: block; width: 5px; height: 9px; border-radius: 99px; background: var(--selected-foreground); animation: cx-blink-eye 4s infinite; }
1637
1676
  @keyframes cx-blink-eye { 0%, 92%, 100% { transform: none; } 95% { transform: scaleY(.15); } }
1638
1677
  .cx-bot-sugs { padding: 8px 12px; gap: 6px; border-top: 1px solid var(--border); }
@@ -1657,7 +1696,7 @@ p.cx-text { margin: 0; }
1657
1696
  .cx-chart-x { display: grid; grid-template-columns: repeat(var(--n), 1fr); }
1658
1697
  .cx-chart-x span { overflow: visible; white-space: nowrap; }
1659
1698
  .cx-check-dot { display: grid; place-items: center; width: 24px; height: 24px; border-radius: 99px; box-shadow: inset 0 0 0 1.5px var(--border); font-size: 12px; font-weight: 600; color: var(--muted-foreground); }
1660
- .cx-check-dot[data-done] { background: var(--success); box-shadow: none; color: #fff; animation: cx-pop 300ms cubic-bezier(.22, 1, .36, 1); }
1699
+ .cx-check-dot[data-done] { background: var(--success); box-shadow: none; color: #fff; animation: cx-pop 300ms var(--ease-out); }
1661
1700
  .cx-check-dot svg { width: 13px; height: 13px; }
1662
1701
 
1663
1702
  /* ═════ Settings ═════ */
@@ -1669,8 +1708,8 @@ p.cx-text { margin: 0; }
1669
1708
  .cx-settings { container-type: inline-size; }
1670
1709
  /* floats over the form: it never takes or gives back space, it only fades and slides */
1671
1710
  .cx-dirty { position: sticky; bottom: 0; z-index: 5; height: 88px; box-sizing: border-box; padding: 24px 0 16px; display: flex; justify-content: flex-end; align-items: flex-end; pointer-events: none; }
1672
- .cx-dirty > .cx-dirty-in { position: relative; max-width: 100%; height: 48px; box-sizing: border-box; display: flex; align-items: center; gap: 16px; padding: 0 8px 0 18px; white-space: nowrap; border-radius: 99px; background: var(--foreground); color: var(--background); box-shadow: 0 16px 36px -14px rgb(0 0 0 / .45); opacity: 0; transform: translateY(10px) scale(.98); visibility: hidden; transition: opacity 180ms ease, transform 240ms cubic-bezier(.22, 1, .36, 1), visibility 0s linear 240ms; }
1673
- .cx-dirty[data-open] > .cx-dirty-in { opacity: 1; transform: none; visibility: visible; pointer-events: auto; transition: opacity 180ms ease, transform 240ms cubic-bezier(.22, 1, .36, 1), visibility 0s; }
1711
+ .cx-dirty > .cx-dirty-in { position: relative; max-width: 100%; height: 48px; box-sizing: border-box; display: flex; align-items: center; gap: 16px; padding: 0 8px 0 18px; white-space: nowrap; border-radius: 99px; background: var(--foreground); color: var(--background); box-shadow: 0 16px 36px -14px rgb(0 0 0 / .45); opacity: 0; transform: translateY(10px) scale(.98); visibility: hidden; transition: opacity 180ms ease, transform 240ms var(--ease-out), visibility 0s linear 240ms; }
1712
+ .cx-dirty[data-open] > .cx-dirty-in { opacity: 1; transform: none; visibility: visible; pointer-events: auto; transition: opacity 180ms ease, transform 240ms var(--ease-out), visibility 0s; }
1674
1713
  @media (prefers-reduced-motion: reduce) { .cx-dirty > .cx-dirty-in { transform: none; } }
1675
1714
  .cx-dirty .cx-text { color: inherit; }
1676
1715
  .cx-dirty .cn-button-variant-ghost { color: inherit; }
@@ -1688,6 +1727,8 @@ p.cx-text { margin: 0; }
1688
1727
  .cx-plans { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 240px), 1fr)); gap: 14px; width: 100%; max-width: 920px; }
1689
1728
  .cx-plan { display: flex; flex-direction: column; gap: 12px; padding: 0; cursor: pointer; transition: box-shadow 160ms, transform 160ms; }
1690
1729
  .cx-plan:hover { transform: translateY(-2px); }
1730
+ .style-nova .cn-card.cx-plan, .cn-card.cx-plan { overflow: visible; } /* nothing in a plan needs clipping, and a clipped card would also clip the strip below */
1731
+ .cx-plan:hover::after { content: ""; position: absolute; left: 0; right: 0; top: calc(100% - 2px); height: 8px; } /* fills the gap it lifts from: no blinking hover on its bottom edge */
1691
1732
  .cx-plan[aria-checked="true"] { box-shadow: 0 0 0 2px var(--selected); }
1692
1733
  .cx-plan:focus-visible { outline: 2px solid var(--ring); outline-offset: 3px; }
1693
1734
  .cx-plan-price { display: flex; align-items: baseline; gap: 6px; }
@@ -1737,7 +1778,7 @@ p.cx-text { margin: 0; }
1737
1778
  .cx-pw-meter { display: flex; flex-direction: column; gap: 8px; }
1738
1779
  .cx-pw-bars { display: grid; grid-template-columns: repeat(4, 1fr); gap: 4px; }
1739
1780
  .cx-pw-bars .cn-progress { height: 4px; }
1740
- .cx-pw-bars .cn-progress .cn-progress-indicator { transition: transform 260ms cubic-bezier(.22, 1, .36, 1), background-color 200ms; }
1781
+ .cx-pw-bars .cn-progress .cn-progress-indicator { transition: transform var(--t-move) var(--ease-out), background-color var(--t-move); }
1741
1782
  .cx-pw-bars .cn-progress[data-tone="bad"] .cn-progress-indicator { background: var(--destructive); }
1742
1783
  .cx-pw-bars .cn-progress[data-tone="wait"] .cn-progress-indicator { background: var(--warning); }
1743
1784
  .cx-pw-bars .cn-progress[data-tone="ok"] .cn-progress-indicator { background: var(--success); }
@@ -1785,9 +1826,14 @@ p.cx-text { margin: 0; }
1785
1826
  .cx-ag-who .cn-button .cn-avatar { width: 20px; height: 20px; }
1786
1827
  .cx-ag-who .cn-button .cn-avatar .cn-avatar-fallback { font-size: 9px; }
1787
1828
  .cx-ag-who .cn-button[aria-checked="true"][aria-checked][aria-checked] { background: var(--selected-soft); color: var(--selected); border-color: transparent; }
1788
- .cx-ag-strip { display: grid; grid-template-columns: repeat(7, 1fr); gap: 4px; }
1829
+ .cx-ag-strip { display: grid; grid-template-columns: repeat(7, minmax(0, 1fr)); gap: 4px; }
1830
+ /* a narrow phone: the seven days always fit (a long «TODAY» clips instead of pushing the week off the screen) */
1831
+ .cx-ag-strip .cx-ag-day { min-width: 0; padding-inline: 2px; }
1832
+ .cx-ag-strip .cx-ag-day small { max-width: 100%; overflow: hidden; text-overflow: clip; white-space: nowrap; }
1789
1833
  .cx-ag-day small { font-size: 11px; color: var(--muted-foreground); text-transform: uppercase; letter-spacing: .04em; }
1790
1834
  .cx-ag-day b { font-size: 16px; font-weight: 600; font-variant-numeric: tabular-nums; }
1835
+ /* a day with nothing booked has no count line: its name and number sit in the middle of the pill, not at its top */
1836
+ .cx-ag-day .cx-ag-count:empty { display: none; }
1791
1837
  .cx-ag-day .cx-ag-count { min-width: 18px; height: 16px; border-radius: 99px; font-size: 11px; font-weight: 600; color: var(--muted-foreground); font-variant-numeric: tabular-nums; }
1792
1838
  .cx-ag-day[data-today] b { color: var(--selected); }
1793
1839
  .cx-ag-day[aria-pressed="true"] small, .cx-ag-day[aria-pressed="true"] .cx-ag-count, .cx-ag-day[aria-pressed="true"] b { color: inherit; }
@@ -1851,7 +1897,7 @@ p.cx-text { margin: 0; }
1851
1897
  .cx-chat-sys svg { width: 14px; height: 14px; flex: none; }
1852
1898
 
1853
1899
  /* ── Messaging: 3 panes (wide) · thread + sheet (mid) · one pane (narrow) ── */
1854
- .cx-mx { display: grid; grid-template-columns: 320px minmax(0, 1fr) 288px; height: 640px; width: 100%; margin: 0 auto; border-radius: calc(var(--radius) * 1.6); border: 1px solid var(--border); background: var(--background); overflow: hidden; transition: max-width 260ms cubic-bezier(.22, 1, .36, 1); }
1900
+ .cx-mx { display: grid; grid-template-columns: 320px minmax(0, 1fr) 288px; height: 640px; width: 100%; margin: 0 auto; border-radius: calc(var(--radius) * 1.6); border: 1px solid var(--border); background: var(--background); overflow: hidden; transition: max-width 260ms var(--ease-out); }
1855
1901
  .cx-mx[data-layout="mid"] { grid-template-columns: 300px minmax(0, 1fr); }
1856
1902
  .cx-mx[data-layout="narrow"] { grid-template-columns: minmax(0, 1fr); }
1857
1903
  .cx-mx:not([data-layout="wide"]) .cx-mx-ctx:not(.cx-mx-ctx-sheet) { display: none; }
@@ -2013,7 +2059,7 @@ p.cx-text { margin: 0; }
2013
2059
  @container (max-width: 700px) {
2014
2060
  .cx-ag-scroll { scroll-snap-type: x mandatory; scroll-padding-left: 48px; }
2015
2061
  .cx-ag-col { scroll-snap-align: start; }
2016
- .cx-ag-times span { right: 5px; }
2062
+ .cx-ag-times > span { right: 5px; }
2017
2063
  .cx-ag-times .cx-text { font-size: 11px; letter-spacing: -.01em; } /* «09:00» fits its 48px column, never cut at the edge */
2018
2064
  }
2019
2065
 
@@ -2041,12 +2087,12 @@ p.cx-text { margin: 0; }
2041
2087
  .pk-scrim{ position:fixed; inset:0; z-index:var(--z-modal); background:transparent; }
2042
2088
  .pk-pop{ color:var(--popover-foreground); overflow-y:auto; overscroll-behavior:contain; scrollbar-width:thin; position:fixed; z-index:calc(var(--z-modal) + 1); width:292px; box-sizing:border-box; background:var(--popover); border-radius:20px;
2043
2089
  box-shadow:0 24px 60px -18px rgba(31,22,60,.38), 0 0 0 1px var(--border); padding:12px;
2044
- display:flex; flex-direction:column; gap:11px; animation:pk-in .18s cubic-bezier(.2,.8,.3,1); }
2090
+ display:flex; flex-direction:column; gap:11px; animation:pk-in .18s var(--ease-out); }
2045
2091
  @keyframes pk-in{ from{ opacity:0; transform:translateY(6px) scale(.98); } to{ opacity:1; transform:none; } }
2046
2092
  @media (max-width:35rem){
2047
2093
  .pk-scrim{ background:rgba(16,16,20,.28); }
2048
2094
  .pk-pop{ left:0 !important; right:0; top:auto !important; bottom:0 !important; max-height:88dvh !important; width:auto; border-radius:22px 22px 0 0;
2049
- padding:10px 16px calc(16px + env(safe-area-inset-bottom,0px)); animation:pk-up .24s cubic-bezier(.2,.8,.3,1); }
2095
+ padding:10px 16px calc(16px + env(safe-area-inset-bottom,0px)); animation:pk-up .24s var(--ease-out); }
2050
2096
  .pk-pop::before{ content:""; width:38px; height:5px; border-radius:5px; background:var(--muted); margin:0 auto 2px; }
2051
2097
  }
2052
2098
  @keyframes pk-up{ from{ transform:translateY(100%); } to{ transform:none; } }
@@ -2182,9 +2228,12 @@ p.cx-text { margin: 0; }
2182
2228
  .cx-band[data-tone="warn"] > .mu-icon { color: var(--warning); }
2183
2229
  .cx-band > .cx-band-text { flex: 1; }
2184
2230
  /* Accordion from muten: the panel folds with grid rows (exact height, no measuring) and its text fades. */
2185
- .cn-accordion-content.cx-acc-fold { display: grid; grid-template-rows: 1fr; transition: grid-template-rows 200ms ease; animation: none; }
2231
+ .cn-accordion-content.cx-acc-fold { display: grid; grid-template-rows: 1fr; transition: grid-template-rows var(--t-move) var(--ease-out); animation: none; }
2186
2232
  .cn-accordion-content.cx-acc-fold[data-open="false"] { grid-template-rows: 0fr; }
2187
- .cn-accordion-content.cx-acc-fold > .cn-accordion-content-inner { overflow: hidden; min-height: 0; transition: opacity 160ms ease; }
2233
+ /* the fold clips (it closes to 0 high) but 4 px past its box, so the first row's top edge and focus ring are not cut;
2234
+ folded, its opacity is 0, so those 4 px show nothing */
2235
+ .cn-accordion-content.cx-acc-fold > .cn-accordion-content-inner { overflow: clip; overflow-clip-margin: 4px; min-height: 0; transition: opacity var(--t-micro) ease, translate var(--t-move) var(--ease-out); }
2236
+ .cn-accordion-content.cx-acc-fold[data-open="false"] > .cn-accordion-content-inner { translate: 0 -4px; }
2188
2237
  .cn-accordion-content.cx-acc-fold[data-open="false"] > .cn-accordion-content-inner { opacity: 0; padding-bottom: 0; }
2189
2238
  .cn-accordion-trigger > .cx-acc-chev { margin-left: auto; font-size: 16px; color: var(--muted-foreground); transition: transform 200ms ease; }
2190
2239
  .cn-accordion-trigger[aria-expanded="true"] > .cx-acc-chev { transform: rotate(180deg); }
@@ -2205,9 +2254,9 @@ p.cx-text { margin: 0; }
2205
2254
 
2206
2255
  /* ── Loading: the content fades in where its skeleton was (kit-skeleton.muten) ── */
2207
2256
  :where(.style-nova) .cx-loading, :where(.style-nova) .cx-loaded, :where(.style-nova) .cx-sk-host { display: block; }
2208
- .cx-loaded { animation: cx-loaded-in 180ms ease-out; }
2209
- @keyframes cx-loaded-in { from { opacity: 0.001; } to { opacity: 1; } }
2210
- @media (prefers-reduced-motion: reduce) { .cx-loaded { animation: none; } }
2257
+ /* the content lands where its skeleton was, out of a short blur: the shape does not change, only the pixels */
2258
+ .cx-loaded { animation: cx-loaded-in var(--t-move) var(--ease-out); }
2259
+ @keyframes cx-loaded-in { from { opacity: 0.001; filter: blur(3px); } to { opacity: 1; filter: none; } }
2211
2260
  /* a skeleton line inside an Item title takes the title's width (the title shrinks to its text otherwise) */
2212
2261
  .cn-item-title:has(> .cx-sk) { width: 100%; }
2213
2262
  .cx-sk-tr > .cx-sk { flex: 0 1 auto; min-width: 0; }
@@ -2237,7 +2286,7 @@ p.cx-text { margin: 0; }
2237
2286
  .cx-rg-row:focus-visible .cx-rg-dot { border-color: var(--ring); box-shadow: 0 0 0 3px color-mix(in srgb, var(--ring) 50%, transparent); }
2238
2287
  .cx-rg-dot { position: relative; display: block; width: 16px; height: 16px; margin-top: 2px; border-radius: 99px; border: 1px solid var(--input); background: transparent; transition: background-color 150ms, border-color 150ms; }
2239
2288
  .cx-rg-dot[data-state="true"] { background: var(--primary); border-color: var(--primary); }
2240
- .cx-rg-dot::after { content: ""; position: absolute; top: 50%; left: 50%; width: 8px; height: 8px; border-radius: 99px; background: var(--primary-foreground); transform: translate(-50%, -50%) scale(0); transition: transform 150ms cubic-bezier(.22, 1, .36, 1); }
2289
+ .cx-rg-dot::after { content: ""; position: absolute; top: 50%; left: 50%; width: 8px; height: 8px; border-radius: 99px; background: var(--primary-foreground); transform: translate(-50%, -50%) scale(0); transition: transform 150ms var(--ease-out); }
2241
2290
  .cx-rg-dot[data-state="true"]::after { transform: translate(-50%, -50%) scale(1); }
2242
2291
  .cx-rg-row:active .cx-rg-dot { scale: .92; }
2243
2292
  .cx-rg-text { display: flex; flex-direction: column; gap: 2px; }
@@ -2259,16 +2308,15 @@ p.cx-text { margin: 0; }
2259
2308
 
2260
2309
  /* ── NumberField / VectorField (number-field.js, vector-field.muten) ── */
2261
2310
  .cx-nf-host { display: block; }
2262
- .cx-nf { width: fit-content; max-width: 100%; }
2263
- .cx-nf-input { text-align: left; font-variant-numeric: tabular-nums; field-sizing: content; min-width: 3ch; width: auto; flex: 0 1 auto; padding-right: 2px; }
2311
+ .cx-nf { width: 100%; }
2312
+ .cx-nf-input { text-align: left; font-variant-numeric: tabular-nums; min-width: 3ch; flex: 1 1 auto; padding-right: 2px; }
2264
2313
  .cx-nf-prefix { font-size: 12px; font-weight: 600; color: var(--muted-foreground); min-width: 14px; }
2265
2314
  .cx-nf-unit { font-size: 13px; color: var(--muted-foreground); padding-right: 2px; }
2266
2315
  .cx-nf-steps { gap: 0; padding-right: 4px; }
2267
2316
  .cx-nf-btn:disabled { opacity: .35; }
2268
- .cx-vector { display: flex; flex-wrap: wrap; gap: 8px; width: fit-content; max-width: 100%; }
2269
- .cx-vector .cx-nf { max-width: none; }
2317
+ .cx-vector { display: grid; grid-template-columns: repeat(auto-fit, minmax(120px, 1fr)); gap: 8px; width: 100%; }
2270
2318
  /* ── FileInput (file-input.js) ── */
2271
- .cx-file-host { display: flex; flex-direction: column; gap: 8px; width: 100%; max-width: 360px; }
2319
+ .cx-file-host { display: flex; flex-direction: column; gap: 8px; width: 100%; }
2272
2320
  .cx-file-drop { aspect-ratio: auto; min-height: 132px; }
2273
2321
  .cx-file-drop[data-over] { border-color: var(--primary); background: color-mix(in srgb, var(--primary) 6%, transparent); }
2274
2322
  .cx-file-msg { text-align: left; margin: 0; color: var(--destructive); }
@@ -2326,7 +2374,7 @@ p.cx-text { margin: 0; }
2326
2374
  .cx-stp { display: grid; grid-template-columns: repeat(var(--n, 3), minmax(0, 1fr)); gap: 6px; width: 100%; max-width: 480px; }
2327
2375
  .cx-stp-step { display: flex; flex-direction: column; gap: 6px; min-width: 0; }
2328
2376
  .cx-stp-bar { height: 4px; }
2329
- .cx-stp-bar > .cn-progress-indicator { width: 0; transition: width 260ms cubic-bezier(.22, 1, .36, 1); }
2377
+ .cx-stp-bar > .cn-progress-indicator { width: 0; transition: width var(--t-move) var(--ease-out); }
2330
2378
  .cx-stp-step[data-state="done"] .cx-stp-bar > .cn-progress-indicator, .cx-stp-step[data-state="now"] .cx-stp-bar > .cn-progress-indicator { width: 100%; }
2331
2379
  .cx-stp-dot, .cx-stp-desc { display: none; }
2332
2380
  .cx-stp-label { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
@@ -2425,6 +2473,9 @@ p.cx-text { margin: 0; }
2425
2473
  .cx-ov-trigger { display: inline-flex; }
2426
2474
  .cx-ov-zone > .cx-ov-trigger { display: flex; width: 100%; }
2427
2475
  .cx-ov-behavior { display: none; }
2476
+ /* a panel place() lifted to the top layer: the browser's popover look goes (zero specificity, so the panel's own
2477
+ padding, border and background still win) */
2478
+ :where(.cx-floated[popover]) { position: fixed; inset: auto; margin: 0; border: 0; padding: 0; overflow: visible; background: transparent; color: inherit; }
2428
2479
  .cx-ov-content[popover] { position: fixed; inset: auto; margin: 0; border: 0; overflow: visible; width: var(--w, auto); max-width: calc(100vw - 16px); color: var(--popover-foreground); }
2429
2480
  .cx-ov-content:not([popover]) { display: none; }
2430
2481
  .cx-ov-content[popover]:popover-open { display: flex; flex-direction: column; }
@@ -2460,21 +2511,22 @@ p.cx-text { margin: 0; }
2460
2511
  .cx-navmenu-trigger .cn-navigation-menu-trigger-icon { width: 12px; height: 12px; transition: rotate 200ms ease; }
2461
2512
  .cx-ov-trigger[data-open] .cn-navigation-menu-trigger-icon { rotate: 180deg; }
2462
2513
  .cx-navmenu-panel[popover]:popover-open { display: grid; grid-template-columns: repeat(var(--cols, 2), minmax(0, 1fr)); gap: 4px; padding: 8px; border-radius: calc(var(--radius) * 1.2); background: var(--popover); box-shadow: 0 0 0 1px color-mix(in srgb, var(--foreground) 10%, transparent), 0 10px 30px -10px rgb(0 0 0 / .25); }
2463
- .cx-navmenu-link { display: flex; flex-direction: column; align-items: flex-start; gap: 2px; padding: 10px; border-radius: calc(var(--radius) * .8); color: inherit; text-decoration: none; }
2514
+ .cx-navmenu-link.cn-navigation-menu-link { display: flex; flex-direction: column; align-items: flex-start; text-align: start; gap: 2px; padding: 10px; border-radius: calc(var(--radius) * .8); color: inherit; text-decoration: none; }
2464
2515
  .cx-navmenu-link:hover, .cx-navmenu-link:focus-visible { background: var(--muted); outline: none; }
2465
2516
  .cx-navmenu-title { font-size: 14px; font-weight: 500; }
2466
2517
  .cx-navmenu-desc { font-size: 13px; line-height: 1.4; color: var(--muted-foreground); }
2467
2518
  .cx-navmenu-desc:empty { display: none; }
2468
2519
  /* the panels' enter / exit (Nova's animate-in reads data-open / data-closed, which the kit sets) */
2469
- .cx-ov-content[data-open] { animation: cx-ov-in 120ms cubic-bezier(.22, 1, .36, 1); }
2470
- .cx-ov-content[data-closed] { animation: cx-ov-out 100ms ease forwards; }
2520
+ .cx-ov-content[data-open] { animation: cx-ov-in var(--t-pop) var(--ease-out); }
2521
+ .cx-ov-content[data-closed] { animation: cx-ov-out calc(var(--t-pop) * .67) ease forwards; }
2471
2522
  @keyframes cx-ov-in { from { opacity: 0; transform: scale(.96) translateY(var(--ov-dy, -4px)); } }
2472
2523
  @keyframes cx-ov-out { to { opacity: 0; transform: scale(.97); } }
2473
2524
  .cx-ov-content[data-side="top"] { --ov-dy: 4px; }
2474
2525
  @media (prefers-reduced-motion: reduce) { .cx-ov-content[data-open], .cx-ov-content[data-closed] { animation-duration: 1ms; } }
2475
2526
 
2476
2527
  /* ── Modal mode sheet (sheet.muten): a full-height panel from a side, or full-width from the top/bottom ── */
2477
- .cx-modal[data-mode="sheet"] { top: 0; bottom: 0; right: 0; width: min(26rem, calc(100% - 2rem)); max-height: none; border-radius: 0; overflow: hidden; transition: transform 300ms cubic-bezier(.32, .72, 0, 1); transform: translateX(100%); }
2528
+ .cx-modal[data-mode="sheet"] { top: 0; bottom: 0; right: 0; width: min(26rem, calc(100% - 2rem)); max-height: none; border-radius: 0; overflow: hidden; transition: transform calc(var(--t-sheet) * .68) var(--ease-in-out); transform: translateX(100%); }
2529
+ .cx-modal-root[data-open="true"] > .cx-modal[data-mode="sheet"] { transition: transform var(--t-sheet) var(--ease-drawer); }
2478
2530
  .cx-modal[data-mode="sheet"][data-side="left"] { right: auto; left: 0; transform: translateX(-100%); }
2479
2531
  .cx-modal[data-mode="sheet"]:is([data-side="top"], [data-side="bottom"]) { left: 0; right: 0; width: 100%; height: auto; max-height: min(80dvh, 40rem); }
2480
2532
  .cx-modal[data-mode="sheet"][data-side="top"] { bottom: auto; transform: translateY(-100%); }
@@ -2520,7 +2572,7 @@ a.cx-bc-item:hover { color: var(--foreground); }
2520
2572
  .cx-pl-row { display: flex; flex-direction: row; align-items: center; gap: 4px; }
2521
2573
  .cx-pl-more { display: inline-grid; place-items: center; width: 32px; height: 32px; color: var(--muted-foreground); }
2522
2574
  /* ── AppSidebar ── */
2523
- .cx-sidebar { display: flex; width: 248px; flex: none; border-right: 1px solid var(--border); background: color-mix(in srgb, var(--muted) 35%, var(--background)); transition: width 200ms cubic-bezier(.22, 1, .36, 1); overflow: hidden; }
2575
+ .cx-sidebar { display: flex; width: 248px; flex: none; border-right: 1px solid var(--border); background: color-mix(in srgb, var(--muted) 35%, var(--background)); transition: width 200ms var(--ease-out); overflow: hidden; }
2524
2576
  .cx-sidebar[data-collapsed="true"] { width: 56px; }
2525
2577
  .cx-sb-inner { display: flex; flex-direction: column; width: 100%; gap: 4px; padding: 8px; }
2526
2578
  .cx-sb-head, .cx-sb-foot { display: flex; flex-direction: column; gap: 4px; }
@@ -2531,7 +2583,7 @@ a.cx-bc-item:hover { color: var(--foreground); }
2531
2583
  .cx-sb-menu { display: flex; flex-direction: column; gap: 2px; }
2532
2584
  .cx-sb-item { display: flex; align-items: center; gap: 8px; width: 100%; height: 32px; padding: 0 8px; border: 0; border-radius: calc(var(--radius) * .7); background: none; color: inherit; font: inherit; font-size: 14px; text-align: left; cursor: pointer; white-space: nowrap; }
2533
2585
  .cx-sb-item:hover { background: var(--accent); }
2534
- .cx-sb-item[data-active="true"], .cx-sb-item[aria-current="page"] { background: var(--selected-soft); color: var(--selected); font-weight: 500; }
2586
+ .cx-sb-item[data-active="true"], .cx-sb-item[aria-current="page"], .cx-sb-item[aria-current="true"], .cx-sb-item.is-active { background: var(--selected-soft); color: var(--selected); font-weight: 500; }
2535
2587
  .cx-sb-item { position: relative; text-decoration: none; } /* the count sits inside its own row, never past its edge */
2536
2588
  .cx-sb-item > .mu-icon { width: 16px; height: 16px; flex: none; }
2537
2589
  .cx-sb-label { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; }
@@ -2591,12 +2643,19 @@ a.cx-bc-item:hover { color: var(--foreground); }
2591
2643
  .cx-insp-head:hover { background: color-mix(in srgb, var(--muted) 50%, transparent); }
2592
2644
  .cx-insp-head .cx-acc-chev { width: 14px; height: 14px; color: var(--muted-foreground); transition: rotate 200ms ease; }
2593
2645
  .cx-insp-head[aria-expanded="false"] .cx-acc-chev { rotate: -90deg; }
2594
- .cx-insp-body { display: flex; flex-direction: column; gap: 8px; padding: 2px 12px 12px; }
2646
+ .cx-insp-body { display: flex; flex-direction: column; gap: 8px; padding: 4px 12px 12px; }
2595
2647
  .cx-insp-row { display: grid; grid-template-columns: 84px minmax(0, 1fr); align-items: center; gap: 10px; }
2596
2648
  .cx-insp-label { font-size: 13px; color: var(--muted-foreground); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
2597
2649
  .cx-insp-ctl { display: flex; flex-direction: row; align-items: center; min-width: 0; }
2598
- .cx-insp-ctl .cx-nf, .cx-insp-ctl .cx-vector { max-width: 100%; }
2599
- .cx-tree-host { display: block; width: 100%; max-width: 320px; }
2650
+ .cx-tree-host { display: block; width: 100%; max-width: 320px; min-width: 220px; }
2651
+ /* a folder's group folds like the accordion (no rebuild, no jump): rows 0fr ↔ 1fr, its rows fade with it */
2652
+ .cx-tree-fold { display: grid; grid-template-rows: 0fr; transition: grid-template-rows 200ms var(--ease-out); }
2653
+ .cx-tree-row[aria-expanded="true"] + .cx-tree-fold { grid-template-rows: 1fr; }
2654
+ .cx-tree-inner { display: flex; flex-direction: column; min-height: 0; overflow: clip; overflow-clip-margin: 2px; opacity: 0; transition: opacity 160ms ease; }
2655
+ .cx-tree-row[aria-expanded="true"] + .cx-tree-fold > .cx-tree-inner { opacity: 1; }
2656
+ .cx-tree-chev svg { transition: rotate 200ms var(--ease-out); }
2657
+ .cx-tree-row[aria-expanded="true"] > .cx-tree-chev svg { rotate: 90deg; }
2658
+ @media (prefers-reduced-motion: reduce) { .cx-tree-fold, .cx-tree-inner, .cx-tree-chev svg { transition: none; } }
2600
2659
  .cx-tree { display: flex; flex-direction: column; padding: 4px; border: 1px solid var(--border); border-radius: calc(var(--radius) * 1.2); }
2601
2660
  .cx-tree-row { display: flex; align-items: center; gap: 6px; width: 100%; height: 30px; padding-right: 8px; border: 0; border-radius: calc(var(--radius) * .6); background: none; color: inherit; font: inherit; font-size: 13px; text-align: left; cursor: pointer; outline: none; }
2602
2661
  .cx-tree-row:hover { background: var(--accent); }
@@ -2808,7 +2867,7 @@ a.cx-bc-item:hover { color: var(--foreground); }
2808
2867
 
2809
2868
  /* ── LiveStack: news that keeps arriving; the newest in front, the older ones step back behind it ── */
2810
2869
  .cx-live { position: relative; display: block; width: 100%; max-width: 380px; height: var(--live-h, 200px); }
2811
- .cx-live-card { position: absolute; left: 0; right: 0; top: 0; z-index: calc(10 - var(--i, 0)); display: flex; align-items: center; gap: 12px; padding: 14px 16px; border-radius: calc(var(--radius) * 1.6); border: 1px solid var(--border); background: var(--card); color: var(--card-foreground); box-shadow: 0 18px 36px -24px rgb(11 11 13 / .45); transform-origin: top center; transform: translateY(calc(var(--i, 0) * 14px)) scale(calc(1 - var(--i, 0) * 0.05)); opacity: calc(1 - var(--i, 0) * 0.28); transition: transform 560ms cubic-bezier(.23, 1, .32, 1), opacity 420ms ease, filter 420ms ease; }
2870
+ .cx-live-card { position: absolute; left: 0; right: 0; top: 0; z-index: calc(10 - var(--i, 0)); display: flex; align-items: center; gap: 12px; padding: 14px 16px; border-radius: calc(var(--radius) * 1.6); border: 1px solid var(--border); background: var(--card); color: var(--card-foreground); box-shadow: 0 18px 36px -24px rgb(11 11 13 / .45); transform-origin: top center; transform: translateY(calc(var(--i, 0) * 14px)) scale(calc(1 - var(--i, 0) * 0.05)); opacity: calc(1 - var(--i, 0) * 0.28); transition: transform 560ms var(--ease-out), opacity 420ms ease, filter 420ms ease; }
2812
2871
  .cx-live-card[data-enter] { transform: translateY(-28px) scale(.96); opacity: 0; filter: blur(4px); }
2813
2872
  .cx-live-card + .cx-live-card + .cx-live-card + .cx-live-card { opacity: 0; }
2814
2873
  .cx-live-ic { display: grid; place-items: center; flex: none; width: 36px; height: 36px; border-radius: 10px; background: var(--muted); color: var(--foreground); }
@@ -2823,8 +2882,13 @@ a.cx-bc-item:hover { color: var(--foreground); }
2823
2882
  @media (prefers-reduced-motion: reduce) { .cx-live-card { transition: none; } }
2824
2883
 
2825
2884
  /* ── Press: anything you press gives way a little (0.97), so the page feels it heard you ── */
2826
- .style-nova .cn-button { transition-property: color, background-color, border-color, box-shadow, transform; transition-duration: 160ms; transition-timing-function: cubic-bezier(.23, 1, .32, 1); }
2827
- .style-nova .cn-button:active:not(:disabled) { transform: scale(0.97); }
2885
+ /* HOVER IS INSTANT (shadcn's menus and Emil's rule for what is seen tens of times a day): a row, a menu item or a
2886
+ button changes colour the moment the pointer is on it and the moment it leaves. A fade there leaves trails when the
2887
+ pointer sweeps a list (the last row still fading out, the next fading in, all of them dimming in the gap between
2888
+ two rows), which reads as the whole menu blinking. Only what moves keeps its motion: the press, the focus ring. */
2889
+ .style-nova .cn-button { transition-property: box-shadow, transform; transition-duration: 160ms; transition-timing-function: var(--ease-out); }
2890
+ .style-nova :is(.cx-sb-item, .cx-tree-row, .cx-app-row, .cx-navmenu-link, .cn-sidebar-menu-button, .cn-dropdown-menu-item, .cn-context-menu-item, .cn-menubar-item, .cn-menubar-trigger, .cn-navigation-menu-trigger, .cn-navigation-menu-link, .cn-command-item, .cn-select-item, .cn-item, .cn-toggle, .cn-tabs-trigger), :is(.cx-sb-item, .cx-tree-row, .cx-app-row, .cx-navmenu-link, .cn-sidebar-menu-button, .cn-dropdown-menu-item, .cn-context-menu-item, .cn-menubar-item, .cn-menubar-trigger, .cn-navigation-menu-trigger, .cn-navigation-menu-link, .cn-command-item, .cn-select-item, .cn-item, .cn-toggle, .cn-tabs-trigger) { transition-property: none; } /* .style-nova: beats Nova's own transition-all */
2891
+ /* pressing a button: Nova's own 1px drop (active:translate-y-px), as shadcn; no scale (it changed the button's size) */
2828
2892
 
2829
2893
  /* contrast: the label of the hour groups (Mañana, Tarde) and an appointment's second line read at 4.5:1 */
2830
2894
  .cx-hours-h { margin: 0; font-size: 12px; font-weight: 600; color: var(--muted-foreground); }
@@ -2876,13 +2940,13 @@ a.cx-bc-item:hover { color: var(--foreground); }
2876
2940
  .cx-play[data-in] .cx-bkp-ok { animation: cx-bkp-ok 9s infinite; }
2877
2941
  }
2878
2942
  @media (prefers-reduced-motion: reduce) { .cx-bkp-on { opacity: 1; transform: none; } }
2879
- @keyframes cx-bkp-day { 0%, 12% { opacity: 0; transform: scale(.92); } 16%, 86% { opacity: 1; transform: none; animation-timing-function: cubic-bezier(.23, 1, .32, 1); } 92%, 100% { opacity: 0; transform: scale(.92); } }
2943
+ @keyframes cx-bkp-day { 0%, 12% { opacity: 0; transform: scale(.92); } 16%, 86% { opacity: 1; transform: none; animation-timing-function: var(--ease-out); } 92%, 100% { opacity: 0; transform: scale(.92); } }
2880
2944
  @keyframes cx-bkp-hour { 0%, 26% { opacity: 0; transform: scale(.92); } 30%, 86% { opacity: 1; transform: none; } 92%, 100% { opacity: 0; transform: scale(.92); } }
2881
2945
  @keyframes cx-bkp-tap1 { 0%, 12% { opacity: 0; transform: scale(.4); } 14% { opacity: 1; transform: scale(.8); } 22%, 100% { opacity: 0; transform: scale(2); } }
2882
2946
  @keyframes cx-bkp-tap2 { 0%, 26% { opacity: 0; transform: scale(.4); } 28% { opacity: 1; transform: scale(.8); } 36%, 100% { opacity: 0; transform: scale(2); } }
2883
2947
  @keyframes cx-bkp-tap3 { 0%, 39% { opacity: 0; transform: scale(.4); } 41% { opacity: 1; transform: scale(.8); } 49%, 100% { opacity: 0; transform: scale(2.4); } }
2884
2948
  @keyframes cx-bkp-press { 0%, 39% { transform: none; } 41% { transform: scale(.97); } 44%, 100% { transform: none; } }
2885
- @keyframes cx-bkp-done { 0%, 45% { opacity: 0; transform: translateY(16px); } 51%, 84% { opacity: 1; transform: none; animation-timing-function: cubic-bezier(.23, 1, .32, 1); } 90%, 100% { opacity: 0; transform: translateY(16px); } }
2949
+ @keyframes cx-bkp-done { 0%, 45% { opacity: 0; transform: translateY(16px); } 51%, 84% { opacity: 1; transform: none; animation-timing-function: var(--ease-out); } 90%, 100% { opacity: 0; transform: translateY(16px); } }
2886
2950
  @keyframes cx-bkp-ok { 0%, 48% { transform: scale(.4); } 56%, 100% { transform: none; } }
2887
2951
 
2888
2952
  /* DayPlan (10s) */
@@ -2926,7 +2990,7 @@ a.cx-bc-item:hover { color: var(--foreground); }
2926
2990
  }
2927
2991
  @media (prefers-reduced-motion: reduce) { .cx-dp-free { display: none; } }
2928
2992
  @keyframes cx-dp-free { 0%, 28% { opacity: 1; } 34%, 88% { opacity: 0; } 94%, 100% { opacity: 1; } }
2929
- @keyframes cx-dp-new { 0%, 30% { opacity: 0; transform: translateY(-8px) scale(.98); } 36%, 88% { opacity: 1; transform: none; animation-timing-function: cubic-bezier(.23, 1, .32, 1); } 94%, 100% { opacity: 0; transform: translateY(-8px) scale(.98); } }
2993
+ @keyframes cx-dp-new { 0%, 30% { opacity: 0; transform: translateY(-8px) scale(.98); } 36%, 88% { opacity: 1; transform: none; animation-timing-function: var(--ease-out); } 94%, 100% { opacity: 0; transform: translateY(-8px) scale(.98); } }
2930
2994
  @keyframes cx-dp-ring { 0%, 34% { opacity: 0; } 38% { opacity: 1; } 60%, 100% { opacity: 0; } }
2931
2995
  @keyframes cx-dp-dot { 0%, 34% { opacity: 0; } 38%, 88% { opacity: 1; } 94%, 100% { opacity: 0; } }
2932
2996
  @keyframes cx-dp-out { 0%, 36% { opacity: 1; transform: none; } 40%, 88% { opacity: 0; transform: translateY(-100%); } 94%, 100% { opacity: 1; transform: none; } }
@@ -2999,8 +3063,8 @@ a.cx-bc-item:hover { color: var(--foreground); }
2999
3063
  it comes near the viewport. */
3000
3064
  .cx-device-link { position: absolute; inset: 0; z-index: 4; border-radius: inherit; }
3001
3065
  .cx-device-link:focus-visible { outline: 3px solid var(--ring, #6B46F2); outline-offset: 4px; }
3002
- .cx-device[data-link="true"] { transition: transform .25s cubic-bezier(.2, .8, .2, 1); }
3003
- @media (hover: hover) { .cx-device[data-link="true"]:has(> .cx-device-link:hover) { transform: translateY(-4px); } }
3066
+ .cx-device[data-link="true"] { transition: transform .25s var(--ease-out); }
3067
+ @media (hover: hover) { .cx-device[data-link="true"]:has(> .cx-device-link:hover) { transform: translateY(-4px); } .cx-device-link:hover::after { content: ""; position: absolute; left: 0; right: 0; top: calc(100% - 2px); height: 10px; } } /* the strip fills the gap it lifts from: no blinking hover on its bottom edge */
3004
3068
  @media (prefers-reduced-motion: reduce) { .cx-device[data-link="true"] { transition: none; transform: none !important; } }
3005
3069
  .cx-device[data-shot="true"] > .cx-device-screen { background: #111; content-visibility: auto; }
3006
3070
  .cx-device-shot { position: absolute; inset: 0; background: var(--shot) top center / cover no-repeat; }
@@ -3211,7 +3275,7 @@ a.cx-bc-item:hover { color: var(--foreground); }
3211
3275
  .cx-play[data-in] .cx-odp-go[data-next] .cx-odp-g2, .cx-play[data-in] .cx-odp-badge[data-next] .cx-odp-b2 { animation: cx-odp-in 9s infinite; }
3212
3276
  }
3213
3277
  @keyframes cx-odp-out { 0%, 42% { opacity: 1; transform: none; } 47%, 88% { opacity: 0; transform: translateY(-100%); } 94%, 100% { opacity: 1; transform: none; } }
3214
- @keyframes cx-odp-in { 0%, 42% { opacity: 0; transform: translateY(100%); } 47%, 88% { opacity: 1; transform: none; animation-timing-function: cubic-bezier(.23, 1, .32, 1); } 94%, 100% { opacity: 0; transform: translateY(100%); } }
3278
+ @keyframes cx-odp-in { 0%, 42% { opacity: 0; transform: translateY(100%); } 47%, 88% { opacity: 1; transform: none; animation-timing-function: var(--ease-out); } 94%, 100% { opacity: 0; transform: translateY(100%); } }
3215
3279
 
3216
3280
  /* a play fills its bento cell: the two twins end at the same line */
3217
3281
  .cx-bento-cell .cx-play { flex: 1; }
@@ -3260,7 +3324,7 @@ a.cx-bc-item:hover { color: var(--foreground); }
3260
3324
  /* The native accordion opens and closes to its content's height (browsers with ::details-content; the rest snap). */
3261
3325
  @media (prefers-reduced-motion: no-preference) {
3262
3326
  .cn-accordion > details.cn-accordion-item { interpolate-size: allow-keywords; }
3263
- .cn-accordion > details.cn-accordion-item::details-content { height: 0; overflow: clip; transition: height 200ms cubic-bezier(.23, 1, .32, 1), content-visibility 200ms allow-discrete; }
3327
+ .cn-accordion > details.cn-accordion-item::details-content { height: 0; overflow: clip; transition: height 200ms var(--ease-out), content-visibility 200ms allow-discrete; }
3264
3328
  .cn-accordion > details.cn-accordion-item[open]::details-content { height: auto; }
3265
3329
  }
3266
3330
 
@@ -4157,12 +4221,12 @@ a.cx-bc-item:hover { color: var(--foreground); }
4157
4221
  .cx-nav-fixed .cx-navpill-wrap { position: relative; top: auto; }
4158
4222
 
4159
4223
  .cx-nav-sheet { position: fixed; inset: 0; z-index: var(--z-sheet, 50); display: flex; flex-direction: column; padding: 12px 16px calc(20px + env(safe-area-inset-bottom, 0px)); box-sizing: border-box; background: var(--background); color: var(--foreground); font-family: var(--font-sans); visibility: hidden; opacity: 0; transform: translateY(-8px); transition: opacity 200ms ease, transform 200ms ease, visibility 0s linear 200ms; }
4160
- .cx-nav-sheet[data-open] { visibility: visible; opacity: 1; transform: none; transition: opacity 250ms ease, transform 300ms cubic-bezier(.23, 1, .32, 1); }
4224
+ .cx-nav-sheet[data-open] { visibility: visible; opacity: 1; transform: none; transition: opacity 250ms ease, transform 300ms var(--ease-out); }
4161
4225
  @media (min-width: 641px) { .cx-nav-sheet { display: none; } }
4162
4226
  .cx-nav-sheet-top { display: flex; flex-direction: row; align-items: center; justify-content: space-between; height: 58px; padding: 0 8px 0 16px; border: 1px solid var(--border); border-radius: 18px; box-sizing: border-box; }
4163
4227
  .cx-nav-sheet-top img { height: 14px; width: auto; display: block; }
4164
4228
  .cx-nav-sheet-list { display: flex; flex-direction: column; margin-top: 22px; }
4165
- .cx-nav-sheet-item { display: flex; flex-direction: row; align-items: center; justify-content: space-between; gap: 16px; padding: 18px 6px; border-bottom: 1px solid var(--border); color: var(--foreground); text-decoration: none; opacity: 0; transform: translateY(6px); transition: opacity 250ms ease, transform 300ms cubic-bezier(.23, 1, .32, 1); }
4229
+ .cx-nav-sheet-item { display: flex; flex-direction: row; align-items: center; justify-content: space-between; gap: 16px; padding: 18px 6px; border-bottom: 1px solid var(--border); color: var(--foreground); text-decoration: none; opacity: 0; transform: translateY(6px); transition: opacity 250ms ease, transform 300ms var(--ease-out); }
4166
4230
  .cx-nav-sheet[data-open] .cx-nav-sheet-item { opacity: 1; transform: none; }
4167
4231
  .cx-nav-sheet[data-open] .cx-nav-sheet-item:nth-child(2) { transition-delay: 50ms; }
4168
4232
  .cx-nav-sheet[data-open] .cx-nav-sheet-item:nth-child(3) { transition-delay: 100ms; }
@@ -4223,10 +4287,10 @@ a.cx-bc-item:hover { color: var(--foreground); }
4223
4287
  .cx-tour-hit { position: absolute; inset: 0; z-index: 1; margin: 0; padding: 0; border: 0; border-radius: inherit; background: transparent; cursor: pointer; }
4224
4288
  .cx-tour-hit:focus-visible { outline: 2px solid var(--ring); outline-offset: 2px; }
4225
4289
  /* the open step's line unfolds to its height and the others fold, so the list glides instead of jumping */
4226
- .cx-tour-desc { display: grid; grid-template-rows: 0fr; opacity: 0; transition: grid-template-rows 420ms cubic-bezier(.23, 1, .32, 1), opacity 260ms ease; }
4290
+ .cx-tour-desc { display: grid; grid-template-rows: 0fr; opacity: 0; transition: grid-template-rows 420ms var(--ease-out), opacity 260ms ease; }
4227
4291
  .cx-tour-desc > .cx-stp-desc { overflow: hidden; min-height: 0; margin: 0; }
4228
4292
  .cx-tour-steps > li[data-state="now"] .cx-tour-desc { grid-template-rows: 1fr; opacity: 1; transition-delay: 0ms, 120ms; }
4229
- .cx-tour-steps .cx-stp-label, .cx-tour-steps .cx-stp-dot { transition: color 260ms ease, background-color 260ms ease, transform 260ms cubic-bezier(.23, 1, .32, 1); }
4293
+ .cx-tour-steps .cx-stp-label, .cx-tour-steps .cx-stp-dot { transition: color 260ms ease, background-color 260ms ease, transform 260ms var(--ease-out); }
4230
4294
  .cx-tour-steps > li[data-state="now"] .cx-stp-dot { transform: scale(1.06); }
4231
4295
  .cx-tour-steps > li { position: relative; }
4232
4296
  .cx-tour-steps > li > .cx-stp-bar { display: none; position: absolute; left: 40px; right: 0; bottom: 6px; height: 3px; overflow: hidden; border-radius: 3px; background: var(--muted); }
@@ -4243,15 +4307,15 @@ a.cx-bc-item:hover { color: var(--foreground); }
4243
4307
  .cx-device[data-kind="phone"] > .cx-device-screen.cx-tour-screen > .cx-tour-tap { width: 34px; height: 34px; }
4244
4308
  .cx-device[data-kind="phone"] > .cx-device-screen.cx-tour-screen > img { width: 100%; }
4245
4309
  .cx-tour-screen { position: relative; aspect-ratio: 390 / 844; overflow: hidden; background: var(--muted); }
4246
- .cx-tour-screen > img { position: absolute; left: 0; top: 0; width: 100%; height: auto; display: block; opacity: 0; transform: scale(1.015); transition: opacity 480ms cubic-bezier(.23, 1, .32, 1), transform 620ms cubic-bezier(.23, 1, .32, 1); will-change: opacity; }
4310
+ .cx-tour-screen > img { position: absolute; left: 0; top: 0; width: 100%; height: auto; display: block; opacity: 0; transform: scale(1.015); transition: opacity 480ms var(--ease-out), transform 620ms var(--ease-out); will-change: opacity; }
4247
4311
  .cx-tour-screen > img:not([data-long]) { height: 100%; object-fit: cover; object-position: top; }
4248
4312
  .cx-tour-screen > img[data-on="1"] { opacity: 1; transform: none; }
4249
4313
  .cx-tour-tap { position: absolute; z-index: 3; width: 34px; height: 34px; margin: -17px 0 0 -17px; border-radius: 50%; background: rgb(255 255 255 / .55); box-shadow: 0 0 0 2px rgb(255 255 255 / .9), 0 6px 16px rgb(0 0 0 / .25); opacity: 0; pointer-events: none; }
4250
- .cx-tour-tap[data-go] { animation: cx-tour-tap 1.1s cubic-bezier(.23, 1, .32, 1) 1.2s both; }
4314
+ .cx-tour-tap[data-go] { animation: cx-tour-tap 1.1s var(--ease-out) 1.2s both; }
4251
4315
  @keyframes cx-tour-tap { 0% { opacity: 0; transform: scale(1.4); } 30% { opacity: 1; transform: scale(1); } 45% { transform: scale(.82); } 60% { transform: scale(1); } 100% { opacity: 0; transform: scale(1); } }
4252
4316
  .cx-tour-done { position: absolute; inset: 0; z-index: 4; display: flex; align-items: flex-end; background: rgb(11 11 13 / 0); pointer-events: none; transition: background 300ms ease; }
4253
4317
  .cx-tour-done[data-on="1"] { background: rgb(11 11 13 / .35); }
4254
- .cx-tour-sheet { width: 100%; padding: 10px 18px 22px; border-radius: 22px 22px 0 0; background: var(--card, #fff); color: var(--foreground); display: flex; flex-direction: column; align-items: center; gap: 10px; text-align: center; transform: translateY(100%); transition: transform 420ms cubic-bezier(.23, 1, .32, 1); font-family: var(--font-sans); }
4318
+ .cx-tour-sheet { width: 100%; padding: 10px 18px 22px; border-radius: 22px 22px 0 0; background: var(--card, #fff); color: var(--foreground); display: flex; flex-direction: column; align-items: center; gap: 10px; text-align: center; transform: translateY(100%); transition: transform 420ms var(--ease-out); font-family: var(--font-sans); }
4255
4319
  .cx-tour-done[data-on="1"] .cx-tour-sheet { transform: none; }
4256
4320
  .cx-tour-grab { width: 36px; height: 4px; border-radius: 4px; background: var(--border); }
4257
4321
  .cx-tour-ok { width: 44px; height: 44px; border-radius: 50%; background: var(--success); color: #fff; display: grid; place-items: center; }
@@ -4566,7 +4630,7 @@ a.cx-bc-item:hover { color: var(--foreground); }
4566
4630
  .cx-cp[data-skin] .cx-cp-t, .cx-cp[data-skin] .cx-cp-s { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
4567
4631
  /* never blank: no hide-and-show loop with a skin, only a rise when it comes into view */
4568
4632
  @media (prefers-reduced-motion: no-preference) {
4569
- .cx-cp[data-skin][data-in] :is(.cx-cp-msg, .cx-cp-card, .cx-cp-btns, .cx-cp-note) { opacity: 1; animation: cx-cp-rise 420ms cubic-bezier(.23, 1, .32, 1) both; }
4633
+ .cx-cp[data-skin][data-in] :is(.cx-cp-msg, .cx-cp-card, .cx-cp-btns, .cx-cp-note) { opacity: 1; animation: cx-cp-rise 420ms var(--ease-out) both; }
4570
4634
  .cx-cp[data-skin][data-in] [data-step="2"] { animation-delay: 120ms; } .cx-cp[data-skin][data-in] [data-step="3"] { animation-delay: 240ms; }
4571
4635
  .cx-cp[data-skin][data-in] [data-step="4"] { animation-delay: 360ms; } .cx-cp[data-skin][data-in] [data-step="5"] { animation-delay: 480ms; }
4572
4636
  }
@@ -4880,7 +4944,12 @@ a.cx-bc-item:hover { color: var(--foreground); }
4880
4944
  /* the time now: the line runs from each today column's edge, its dot on the first, and the time sits in the hours gutter */
4881
4945
  .cx-ag-col > .cx-ag-now { left: 0; right: 0; }
4882
4946
  .cx-ag-col > .cx-ag-now i { left: -5px; }
4947
+ .cx-ag-col > .cx-ag-now-past { opacity: .35; } /* the days already gone: the same hour, faint */
4948
+ /* the pill and the line are one: a short tail from the pill to the hour column's edge, where the first day's line starts */
4949
+ .cx-ag-nowtime::after { content: ""; position: absolute; left: 100%; top: 50%; width: 6px; border-top: 2px solid var(--destructive); transform: translateY(-1px); }
4883
4950
  .cx-ag-nowtime { position: absolute; right: 4px; z-index: 3; transform: translateY(-50%); padding: 1px 5px; border-radius: 6px; background: var(--destructive); color: var(--destructive-foreground, #fff); font-size: 10px; font-weight: 600; line-height: 1.4; white-space: nowrap; font-variant-numeric: tabular-nums; }
4951
+ /* «12:36 PM», «10:59 AM»: the longest hours are wider than the hour column; only they tighten, so they fit whole */
4952
+ .cx-ag-nowtime[data-long] { right: 2px; padding-inline: 3px; font-size: 9.5px; letter-spacing: -.02em; }
4884
4953
  /* the crossed-citas alert sits under the strip, full width, with its button */
4885
4954
  .cx-ag-top > [data-ag-alert] { margin: 0; }
4886
4955
  /* no view picked (a range is on): the tabs show none, not the first */
@@ -4926,7 +4995,7 @@ a.cx-bc-item:hover { color: var(--foreground); }
4926
4995
  .cx-pbar-cell[data-side="center"]::-webkit-scrollbar { display: none; }
4927
4996
  .cx-pbar-cell[data-side="right"] { justify-self: end; }
4928
4997
  .cx-pbar-cell:empty { visibility: hidden; }
4929
- .cx-pbar-btn { position: relative; flex: none; display: grid; place-items: center; width: 2.75rem; height: 2.75rem; padding: 0; border: 0; border-radius: .9rem; background: transparent; color: var(--muted-foreground); cursor: pointer; font: inherit; transition: transform .12s cubic-bezier(.22,1,.36,1), background-color .15s; }
4998
+ .cx-pbar-btn { position: relative; flex: none; display: grid; place-items: center; width: 2.75rem; height: 2.75rem; padding: 0; border: 0; border-radius: .9rem; background: transparent; color: var(--muted-foreground); cursor: pointer; font: inherit; transition: transform .12s var(--ease-out), background-color .15s; }
4930
4999
  .cx-pbar-btn .mu-icon, .cx-pbar-btn svg { font-size: 1.3rem; width: 1.3rem; height: 1.3rem; }
4931
5000
  .cx-pbar-btn:hover { background: color-mix(in oklab, var(--foreground) 6%, transparent); color: var(--foreground); }
4932
5001
  .cx-pbar-btn:active { transform: scale(.92); }
@@ -4946,25 +5015,43 @@ a.cx-bc-item:hover { color: var(--foreground); }
4946
5015
  /* THE FOLD GLIDES. Nothing pops and nothing moves sideways: the width shrinks (200 ms) to exactly the icon column
4947
5016
  (the inner padding, the row's padding, the 16 px icon, and back), and the words fade where they are. */
4948
5017
  .cx-sidebar { --sb-pad: 8px; }
4949
- .cx-sidebar[data-collapsed="true"] { width: 64px; }
4950
- .cx-sidebar .cx-sb-item, .cx-sidebar[data-collapsed="true"] .cx-sb-item { justify-content: flex-start; padding: 0 var(--sb-pad); transition: padding .2s cubic-bezier(.22, 1, .36, 1), background-color .15s ease; }
5018
+ /* exactly the icon column: 8 inner + 8 group + 8 row + 16 icon + 8 + 8 + 8, plus the 1 px border on the right, so the
5019
+ icon and its hover/current square sit on the rail's centre */
5020
+ .cx-sidebar[data-collapsed="true"] { width: 65px; }
5021
+ /* ANY PIECE GOES IN. Whatever sits in a row where the icon goes (an Avatar, a dot, an image, a Kbd) keeps its own size and
5022
+ never squeezes; an avatar there takes 20 px so the rows stay 32 high. Folded, what the header or footer holds keeps
5023
+ its width too (a Who, a button with words, a select) and the rail clips it at its edge, instead of crushing it into
5024
+ the 16 px column. */
5025
+ .cx-sb-item > :not(.cx-sb-label):not(.cx-sb-count) { flex: none; }
5026
+ .cx-sb-item > .cn-avatar { width: 20px; height: 20px; margin-inline: -2px; font-size: 10px; }
5027
+ .cx-sb-item > img { width: 16px; height: 16px; border-radius: 4px; object-fit: cover; }
5028
+ /* the header and footer keep the OPEN width in both states (248 less the inner and group padding and the border), so
5029
+ folding or unfolding never rewraps their words: the rail only shows more or less of them, and the words fade */
5030
+ .cx-sidebar :is(.cx-sb-head, .cx-sb-foot) > .cx-who { flex: none; width: 215px; max-width: none; } /* only the name block: a button there (the fold toggle) keeps its own size and stays in the icon column */
5031
+ .cx-sidebar .cx-who-t { min-width: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; transition: opacity .16s ease; }
5032
+ .cx-sidebar[data-collapsed="true"] .cx-who-t { opacity: 0; }
5033
+ .cx-sidebar .cx-sb-item, .cx-sidebar[data-collapsed="true"] .cx-sb-item { justify-content: flex-start; padding: 0 var(--sb-pad); transition: padding .2s var(--ease-out); }
4951
5034
  .cx-sb-label, .cx-sb-glabel, .cx-sb-count { transition: opacity .16s ease; }
5035
+ /* unfolding, the words wait for the rail (it grows in 200 ms) and then fade in whole, instead of being uncovered a few
5036
+ letters at a time; folding, they go at once */
5037
+ .cx-sidebar:not([data-collapsed="true"]) :is(.cx-sb-label, .cx-sb-count, .cx-who-t) { transition: opacity .14s ease .14s; }
5038
+ .cx-sidebar:not([data-collapsed="true"]) .cx-sb-glabel { transition: color .14s ease .14s, height .2s var(--ease-out), padding .2s var(--ease-out); }
4952
5039
  .cx-sb-label { white-space: nowrap; overflow: hidden; }
4953
5040
  .cx-sidebar[data-collapsed="true"] .cx-sb-label, .cx-sidebar[data-collapsed="true"] .cx-sb-glabel { display: block; opacity: 0; pointer-events: none; }
4954
5041
  .cx-sidebar[data-collapsed="true"] .cx-sb-count:not(:empty) { display: inline-grid; opacity: 0; }
4955
5042
  /* FOLDED, A SECTION'S TITLE BECOMES A SHORT LINE between its icons and the ones above: its words fade where they are and
4956
5043
  its height closes with the fold (200 ms), so the icon column has no holes where the titles were. A group with no
4957
5044
  title (the first) takes no room at all. */
4958
- .cx-sidebar .cx-sb-glabel { position: relative; transition: opacity .16s ease, height .2s cubic-bezier(.22, 1, .36, 1), padding .2s cubic-bezier(.22, 1, .36, 1); }
5045
+ .cx-sidebar .cx-sb-glabel { position: relative; transition: opacity .16s ease, height .2s var(--ease-out), padding .2s var(--ease-out); }
4959
5046
  .cx-sidebar[data-collapsed="true"] .cx-sb-glabel { height: 17px; padding-top: 0; padding-bottom: 0; overflow: hidden; color: transparent; opacity: 1; }
4960
5047
  .cx-sidebar[data-collapsed="true"] .cx-sb-glabel::after { content: ""; position: absolute; left: 50%; top: 8px; width: 20px; height: 1px; margin-left: -10px; background: var(--border); }
4961
5048
  .cx-sidebar[data-collapsed="true"] .cx-sb-glabel:empty { display: none; }
4962
- .cx-sidebar .cx-sb-group { transition: padding .2s cubic-bezier(.22, 1, .36, 1); }
5049
+ .cx-sidebar .cx-sb-group { transition: padding .2s var(--ease-out); }
4963
5050
  .cx-sidebar[data-collapsed="true"] .cx-sb-group { padding-top: 2px; padding-bottom: 2px; }
4964
5051
  /* A SECTION THAT LOADS: while its page is on its way (the router marks the link with data-loading), the row's icon
4965
5052
  turns into a small ring that spins, and turns back when the page is there. */
4966
5053
  @keyframes cx-sb-spin { to { transform: rotate(360deg); } }
4967
- .cx-sb-item > .mu-icon { transition: opacity .15s ease, transform .2s cubic-bezier(.22, 1, .36, 1); }
5054
+ .cx-sb-item > .mu-icon { transition: opacity .15s ease, transform .2s var(--ease-out); }
4968
5055
  .cx-sb-item[data-loading] > .mu-icon { opacity: 0; transform: scale(.4) rotate(-90deg); }
4969
5056
  .cx-sb-item[data-loading]::before { content: ""; position: absolute; left: var(--sb-pad, 8px); top: 50%; width: 16px; height: 16px; margin-top: -8px; box-sizing: border-box; border: 2px solid currentColor; border-right-color: transparent; border-radius: 50%; animation: cx-sb-spin .7s linear infinite; }
4970
5057
  @media (prefers-reduced-motion: reduce) {
@@ -5059,18 +5146,24 @@ a.cx-bc-item:hover { color: var(--foreground); }
5059
5146
  .mu-chart-s6 { --series: oklch(0.62 0.05 260); }
5060
5147
  .mu-chart-s7 { --series: oklch(0.8 0.1 120); }
5061
5148
  [data-tone="brand"] { --series: var(--selected, var(--primary)); }
5149
+ /* the status tones are colours too (a Progress, the password's strength bars): without these a tone left no colour */
5150
+ [data-tone="ok"] { --series: var(--success); }
5151
+ [data-tone="wait"] { --series: var(--warning); }
5152
+ [data-tone="bad"] { --series: var(--destructive); }
5153
+ [data-tone="info"] { --series: var(--info, var(--primary)); }
5154
+ [data-tone="note"] { --series: var(--selected, var(--primary)); }
5062
5155
  :is(.mu-chart-bar, .mu-chart-dot, .mu-chart-slice)[class*="mu-chart-s"] { fill: var(--series); }
5063
5156
  .mu-chart-legend { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: row; flex-wrap: wrap; justify-content: center; gap: 6px 18px; font-size: 13px; color: var(--muted-foreground); }
5064
5157
  .mu-chart-legend-item { display: flex; flex-direction: row; align-items: center; gap: 7px; }
5065
5158
  .mu-chart-swatch { width: 10px; height: 10px; border-radius: 3px; background: var(--series); flex: none; }
5066
5159
 
5067
5160
  /* Progress with a tone: the bar takes the series colour */
5068
- .cn-progress[data-tone]:not([data-tone=""]) > .cn-progress-indicator { background: var(--series); }
5161
+ .cn-progress[data-tone]:not([data-tone=""]) > .cn-progress-indicator { background: var(--series, var(--primary)); }
5069
5162
 
5070
5163
  /* ShareBar (share-bar.muten): one whole cut into its parts, each part's value and name under it */
5071
5164
  .cx-split { display: flex; flex-direction: column; gap: 14px; width: 100%; min-width: 0; }
5072
5165
  .cx-split-bar { display: flex; flex-direction: row; gap: 3px; height: 12px; border-radius: 999px; overflow: hidden; background: var(--muted); }
5073
- .cx-split-seg { flex: var(--f, 0) 1 0; min-width: 0; background: var(--series, var(--primary)); transition: flex-grow .5s cubic-bezier(.22, 1, .36, 1); }
5166
+ .cx-split-seg { flex: var(--f, 0) 1 0; min-width: 0; background: var(--series, var(--primary)); transition: flex-grow calc(var(--t-move) * 2) var(--ease-out); }
5074
5167
  .cx-split-seg[style*="--f: 0;"], .cx-split-seg[style*="--f:0;"] { display: none; }
5075
5168
  .cx-split-keys { display: flex; flex-direction: row; flex-wrap: wrap; gap: 10px 32px; }
5076
5169
  .cx-split-key { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
@@ -5112,7 +5205,7 @@ a.cx-bc-item:hover { color: var(--foreground); }
5112
5205
  .cx-stb-bar { height: 100%; display: flex; flex-direction: column; justify-content: flex-end; padding: 0; border: 0; background: none; cursor: pointer; border-radius: 6px; }
5113
5206
  .cx-stb-bar:disabled { cursor: default; }
5114
5207
  .cx-stb-bar:focus-visible { outline: 2px solid var(--ring); outline-offset: 3px; }
5115
- .cx-stb-stack { display: flex; flex-direction: column-reverse; gap: 2px; border-radius: 6px 6px 3px 3px; overflow: hidden; transform-origin: bottom; opacity: .55; transition: height .5s cubic-bezier(.22, 1, .36, 1), opacity .2s; }
5208
+ .cx-stb-stack { display: flex; flex-direction: column-reverse; gap: 2px; border-radius: 6px 6px 3px 3px; overflow: hidden; transform-origin: bottom; opacity: .55; transition: height .5s var(--ease-out), opacity .2s; }
5116
5209
  .cx-stb-bars:not(:has([aria-pressed="true"])) .cx-stb-stack, .cx-stb-bar[aria-pressed="true"] .cx-stb-stack, .cx-stb-bar:not(:disabled):hover .cx-stb-stack { opacity: 1; }
5117
5210
  .cx-stb-bar:disabled { pointer-events: none; }
5118
5211
  .cx-stb-seg { display: block; flex: 1 1 0; min-height: 2px; background: var(--series); }
@@ -5235,7 +5328,9 @@ a.cx-bc-item:hover { color: var(--foreground); }
5235
5328
  .cx-ag-ev { position: absolute; }
5236
5329
  .cx-ag-evprice { position: absolute; top: 5px; right: 7px; font-size: 11.5px; font-weight: 650; font-variant-numeric: tabular-nums; opacity: .85; }
5237
5330
  .cx-ag-dots { display: flex; flex-direction: row; justify-content: center; gap: 3px; min-height: 6px; }
5238
- .cx-ag-dots > i { width: 6px; height: 6px; border-radius: 99px; flex: none; }
5331
+ /* ONE dot: «this day has appointments»; how many is in the day's name for a screen reader, and on the day itself */
5332
+ .cx-ag-dots > i { width: 6px; height: 6px; border-radius: 99px; flex: none; background: var(--selected, var(--primary)); }
5333
+ .cx-ag-day[aria-pressed="true"] .cx-ag-dots > i { background: currentColor; }
5239
5334
  .cx-ag-ev:has(> .cx-ag-evprice) { padding-right: 62px; }
5240
5335
  /* a narrow column (the week on a laptop) keeps the client's name: the price shows only where there is room for both */
5241
5336
  .cx-ag-col { container-type: inline-size; }
@@ -5297,3 +5392,130 @@ a.cx-bc-item:hover { color: var(--foreground); }
5297
5392
  /* ChatPlay(face: "host"): an empty face slot the page fills with its own face (a brand mascot, say). The kit sends
5298
5393
  cx-cp:think / cx-cp:answer / cx-cp:rest on it on the play's clock, so that face can act along with the chat. */
5299
5394
  .cx-cp-face.cx-cp-face-host { position: relative; background: none; overflow: visible; }
5395
+
5396
+ /* ═════ Button & ButtonGroup · RTL, menus and selects inside a group ═════ */
5397
+ /* right to left: a block (or the page, with dir="rtl") flows the other way; flex rows, icon sides and groups follow.
5398
+ An icon that points somewhere (an arrow) takes cx-flip and mirrors itself. */
5399
+ .cx-rtl { direction: rtl; }
5400
+ :is([dir="rtl"], .cx-rtl) .cx-flip { scale: -1 1; }
5401
+ /* a horizontal group in RTL: Nova cuts the left/right corners by side; here they are cut by order instead */
5402
+ :is([dir="rtl"], .cx-rtl) .cn-button-group-orientation-horizontal.cn-button-group-orientation-horizontal > * { border-radius: var(--radius-lg, .5rem); border-left-width: 1px; border-right-width: 1px; }
5403
+ :is([dir="rtl"], .cx-rtl) .cn-button-group-orientation-horizontal.cn-button-group-orientation-horizontal > *:not(:first-child) { border-top-right-radius: 0; border-bottom-right-radius: 0; border-right-width: 0; }
5404
+ :is([dir="rtl"], .cx-rtl) .cn-button-group-orientation-horizontal.cn-button-group-orientation-horizontal > *:not(:last-child) { border-top-left-radius: 0; border-bottom-left-radius: 0; }
5405
+ /* Nova rounds the last segment's right side with !important (its outer edge left to right); right to left the outer
5406
+ edge of the last one is its left */
5407
+ :is([dir="rtl"], .cx-rtl) .cn-button-group-orientation-horizontal > [data-slot]:not(:has(~ [data-slot])):not(:first-child) { border-top-right-radius: 0 !important; border-bottom-right-radius: 0 !important; border-top-left-radius: var(--radius-lg, .5rem) !important; border-bottom-left-radius: var(--radius-lg, .5rem) !important; }
5408
+ /* a DropdownMenu in a vertical group: its trigger joins the button above (the horizontal case is in the 2026-10-10 audit block) */
5409
+ .cn-button-group-orientation-vertical > .cx-ov:not(:first-child) .cx-ov-trigger > .cn-button { border-top-left-radius: 0; border-top-right-radius: 0; border-top-width: 0; }
5410
+ .cn-button-group-orientation-vertical > .cx-ov:not(:last-child) .cx-ov-trigger > .cn-button { border-bottom-left-radius: 0; border-bottom-right-radius: 0; }
5411
+ /* a native select as a group member (muten's Select with class cx-select): an outline button with its chevron */
5412
+ .cx-select { appearance: none; height: 32px; padding: 0 30px 0 10px; border: 1px solid var(--border); border-radius: var(--radius-lg, .5rem); background: var(--background) url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='14' height='14' viewBox='0 0 24 24' fill='none' stroke='%23888' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E") no-repeat right 9px center; color: var(--foreground); font: 500 14px var(--font-sans); cursor: pointer; outline: none; }
5413
+ .cx-select:hover { background-color: var(--muted); }
5414
+ .cx-select:focus-visible { border-color: var(--ring); box-shadow: 0 0 0 3px color-mix(in srgb, var(--ring) 50%, transparent); position: relative; z-index: 1; }
5415
+ :is([dir="rtl"], .cx-rtl) .cx-select { padding: 0 10px 0 30px; background-position: left 9px center; }
5416
+
5417
+
5418
+ /* ═════ Motion · the pieces that did not move (tokens in :root, docs in AGENTS.md «Motion») ═════ */
5419
+ /* Switch: the track's colour and the thumb travel together; pressed, the thumb stretches toward where it will go */
5420
+ .style-nova .cn-switch { transition: background-color var(--t-move) var(--ease-out); }
5421
+ /* its colour changes with the track, not ahead of it (in dark it flipped at once and blinked) */
5422
+ .style-nova .cn-switch-thumb { transition: translate var(--t-move) var(--ease-out), transform var(--t-move) var(--ease-out), width var(--t-micro) var(--ease-out), margin var(--t-micro) var(--ease-out), background-color var(--t-move) var(--ease-out); }
5423
+ /* PRESSED, THE THUMB WIDENS 4 px TOWARD WHERE IT WILL GO (as the reference does), with its width and margin: never a
5424
+ scale with a transform-origin that flips with the state, which on release threw the thumb 2.5 px outside the
5425
+ track for a frame. Checked, its position is calc(100% - 2px) of its own width, so the 4 px it gains move it right
5426
+ by 4 more: a -8 px margin keeps its right edge where it was. */
5427
+ .style-nova .cn-switch:active:not(:disabled) .cn-switch-thumb { width: calc(1rem + 4px); }
5428
+ .style-nova .cn-switch[data-size="sm"]:active:not(:disabled) .cn-switch-thumb { width: calc(.75rem + 4px); }
5429
+ .style-nova .cn-switch[data-checked]:not([data-checked="false"]):active:not(:disabled) .cn-switch-thumb { margin-left: -8px; }
5430
+ /* Checkbox: the box fills and the check grows in from its middle; it gives a little under the press */
5431
+ /* a transition, not an animation: it runs only when the box is ticked, never on the first paint nor when its row moves */
5432
+ .cx-checkbox > input[type="checkbox"] { background-size: 4px; transition: background-color var(--t-micro) var(--ease-out), border-color var(--t-micro) var(--ease-out), background-size var(--t-micro) var(--ease-out), scale var(--t-press) var(--ease-out); }
5433
+ .cx-checkbox > input[type="checkbox"]:checked { background-size: 12px; }
5434
+ /* Tab panels: once the person has switched tabs (not on the first paint), the new panel comes in from the side they
5435
+ went toward, with a short blur that joins the two states. TabsBehavior sets data-moved and data-dir on the root. */
5436
+ [data-tabs-moved] .cx-tab-panel:not(.hidden) { animation: cx-panel-in var(--t-move) var(--ease-out); }
5437
+ [data-tabs-moved][data-tabs-dir="back"] .cx-tab-panel:not(.hidden) { --panel-dx: -8px; }
5438
+ @keyframes cx-panel-in { from { opacity: 0; translate: var(--panel-dx, 8px) 0; filter: blur(2px); } }
5439
+
5440
+ /* Btn loading: the button keeps its width (nothing beside it moves); its content fades where it is and the spinner
5441
+ comes in centred on top of it */
5442
+ /* only while loading, and only if the button is not placed already: every Btn carries data-loading ("false"), and a
5443
+ blanket position: relative pulled the dialogs' absolute close button into the flow */
5444
+ .cn-button[data-loading="true"]:not(.absolute):not([class*="close"]) { position: relative; }
5445
+ .cn-button[data-loading="true"] > :not(.cn-spinner) { transition: opacity var(--t-micro) var(--ease-out); }
5446
+ .cn-button[data-loading="true"] > :not(.cn-spinner) { opacity: 0; }
5447
+ .cn-button[data-loading="true"] > .cn-spinner { position: absolute; left: 50%; top: 50%; translate: -50% -50%; margin: 0; animation: pg-spin 1s linear infinite, cx-fade var(--t-micro) var(--ease-out); }
5448
+ /* SaveButton: «Guardando…» and «Guardado» come in with a short blur (the width is fixed already) */
5449
+ .cx-save:is([data-status="saving"], [data-status="saved"]) .cx-btn-label { animation: cx-label-in var(--t-micro) var(--ease-out); }
5450
+ @keyframes cx-label-in { from { opacity: 0; filter: blur(2px); translate: 0 4px; } }
5451
+
5452
+ /* A label or icon that changes to say what happened (Copiar → Copiado, the copy icon → its check) swaps in: the new
5453
+ one grows from its middle out of a short blur, so the change reads as one thing turning into another */
5454
+ .cx-swap-in { display: inline-flex; align-items: center; gap: inherit; animation: cx-swap-in var(--t-micro) var(--ease-out); }
5455
+ @keyframes cx-swap-in { from { opacity: 0; scale: .6; filter: blur(2px); } }
5456
+
5457
+ /* CountUp: digits that roll. Every character is a 1em box on one line; a digit is a 0-9 column that slides to its
5458
+ value (only the ones that change move). The plain text is for screen readers. */
5459
+ .cx-countup { display: inline-flex; }
5460
+ .cx-roll { display: inline-flex; align-items: flex-start; font-variant-numeric: tabular-nums; line-height: 1; height: 1em; }
5461
+ .cx-roll-d { display: inline-block; height: 1em; overflow: hidden; }
5462
+ .cx-roll-d > span { display: flex; flex-direction: column; transition: translate calc(var(--t-move) * 2) var(--ease-out); }
5463
+ .cx-roll-d em, .cx-roll-s { font-style: normal; display: block; height: 1em; line-height: 1; white-space: pre; }
5464
+ .cx-roll-sr { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }
5465
+ .cx-countup { position: relative; }
5466
+
5467
+ /* List rows (ListMotion, inside every ItemGroup): a new row opens its place and fades in; a leaving row closes its
5468
+ gap. The height goes from/to its own size (interpolate-size; where a browser lacks it, the row only fades). */
5469
+ :root { interpolate-size: allow-keywords; }
5470
+ .cx-list-motion { display: none; }
5471
+ .cx-row-enter { animation: cx-row-in var(--t-move) var(--ease-out); overflow: clip; }
5472
+ @keyframes cx-row-in { from { opacity: 0; height: 0; padding-block: 0; margin-block: 0; translate: 0 -4px; } }
5473
+ .cx-row-leave { animation: cx-row-out calc(var(--t-move) * .75) var(--ease-out) forwards; overflow: clip; pointer-events: none; }
5474
+ @keyframes cx-row-out { from { height: var(--mu-h, auto); } to { opacity: 0; height: 0; padding-block: 0; margin-block: 0; border-width: 0; } }
5475
+
5476
+ /* Entrances after the first paint (core.js sets data-kit-live once the page has painted): an Alert that appears
5477
+ opens to its height and fades in; one taken away by a `when` closes its gap (muten's .mu-leave, --mu-h). */
5478
+ .cn-alert { transition: opacity var(--t-move) var(--ease-out), height var(--t-move) var(--ease-out), translate var(--t-move) var(--ease-out); }
5479
+ :root[data-kit-live] .cn-alert { @starting-style { opacity: 0; height: 0; translate: 0 -4px; } }
5480
+ .cn-alert.mu-leave { animation: cx-row-out calc(var(--t-move) * .75) var(--ease-out) forwards; overflow: clip; }
5481
+
5482
+ /* Calendar: a month (or a year) changed by its arrow slides in from that side; the title stays put */
5483
+ .cx-cal-months[data-slide] .cx-cal-month > :not(.cx-cal-head), .cx-cal-picker[data-slide] > :not(.cx-cal-head) { animation: cx-cal-in var(--t-move) var(--ease-out); }
5484
+ .cx-cal-months[data-slide="prev"], .cx-cal-picker[data-slide="prev"] { --cal-dx: -12px; }
5485
+ @keyframes cx-cal-in { from { opacity: 0; translate: var(--cal-dx, 12px) 0; } }
5486
+ .cx-row-swap { animation: cx-fade var(--t-move) var(--ease-out); }
5487
+ .cx-app-page[data-in] { animation: cx-fade var(--t-micro) var(--ease-out); } /* a section opened from the menu: a short fade, no slide */
5488
+
5489
+ /* Toggle: the hover stays instant (no trails across a toggle group), but turning it ON fades in; turning it off is
5490
+ instant like the hover. Same for a pressed ToggleGroup item. */
5491
+ .style-nova .cn-toggle[aria-pressed="true"], .style-nova .cn-toggle[data-state="on"] { transition-property: background-color, color, box-shadow; transition-duration: var(--t-micro); transition-timing-function: var(--ease-out); }
5492
+
5493
+ /* SidebarTrigger: in the icon column (its 32 px square sits where the rows' icons sit), folded or open */
5494
+ .cx-sb-trigger { align-self: flex-start; flex: none; margin-left: 0; }
5495
+ .cx-sidebar[data-collapsed="true"] .cx-sb-trigger { align-self: flex-start; }
5496
+
5497
+ /* Sheet: its content arrives a moment after the panel, one row after another; leaving, it goes with the panel */
5498
+ .cx-modal[data-mode="sheet"] .cx-modal-body > * { transition: opacity var(--t-pop) var(--ease-out), translate calc(var(--t-sheet) * .8) var(--ease-out); }
5499
+ .cx-modal-root:not([data-open="true"]) > .cx-modal[data-mode="sheet"] .cx-modal-body > * { opacity: 0; translate: 12px 0; transition-duration: 0s; transition-delay: calc(var(--t-sheet) * .7); } /* reset only once the panel is gone */
5500
+ .cx-modal-root[data-open="true"] > .cx-modal[data-mode="sheet"] .cx-modal-body > :nth-child(1) { transition-delay: 60ms; }
5501
+ .cx-modal-root[data-open="true"] > .cx-modal[data-mode="sheet"] .cx-modal-body > :nth-child(2) { transition-delay: 90ms; }
5502
+ .cx-modal-root[data-open="true"] > .cx-modal[data-mode="sheet"] .cx-modal-body > :nth-child(3) { transition-delay: 120ms; }
5503
+ .cx-modal-root[data-open="true"] > .cx-modal[data-mode="sheet"] .cx-modal-body > :nth-child(n+4) { transition-delay: 150ms; }
5504
+ /* Command palette: opened from the keyboard (⌘K) a hundred times a day, so it opens and closes with no animation */
5505
+ .cx-modal-root.cx-palette > :is(.cx-modal, .cx-overlay), .cx-modal-root:has(.cx-cmd) > :is(.cx-modal, .cx-overlay) { transition: none !important; }
5506
+ /* Timeline and the vertical Stepper: a step that becomes the current one changes its dot on the move token */
5507
+ .cx-tl-item::before, .cx-tl-item { transition: background-color var(--t-move) var(--ease-out), box-shadow var(--t-move) var(--ease-out), opacity var(--t-move) var(--ease-out); }
5508
+ .cx-stp-dot, .cx-stp[data-orientation="vertical"] .cx-stp-step::after { transition: background-color var(--t-move) var(--ease-out), border-color var(--t-move) var(--ease-out), color var(--t-move) var(--ease-out); }
5509
+ /* Heatmap: a cell takes its new value's colour on the move token */
5510
+ .cx-heat-c { transition: background-color var(--t-move) var(--ease-out); }
5511
+ /* A field that turns invalid shakes once, where it is (FieldBehavior sets data-invalid when the check fails) */
5512
+ .cn-field[data-invalid] :is(.cn-input-group, .cn-input) { animation: cx-shake calc(var(--t-move) * 1.35) var(--ease-out); }
5513
+
5514
+ /* NavigationMenu / Menubar: switching menus in the same bar swaps the panel in place; the old one goes at once and the
5515
+ new one only fades in (no scale-in, no close animation crossing it) */
5516
+ .cx-ov-content[data-open][data-swap] { animation: cx-fade calc(var(--t-pop) * .8) var(--ease-out); }
5517
+ .cx-ov-content[data-closed][data-swap] { animation: none; }
5518
+
5519
+ /* LangScope: a plain block; its host draws nothing */
5520
+ .cx-lang-scope { display: contents; }
5521
+ .cx-lang-host { display: none; }