@eifi1/ui-kit 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (229) hide show
  1. package/README.md +219 -0
  2. package/dist/components/account-settings.d.ts +71 -0
  3. package/dist/components/account-settings.js +159 -0
  4. package/dist/components/account-settings.js.map +1 -0
  5. package/dist/components/alert-banner.d.ts +20 -0
  6. package/dist/components/alert-banner.js +39 -0
  7. package/dist/components/alert-banner.js.map +1 -0
  8. package/dist/components/amount-input.d.ts +117 -0
  9. package/dist/components/amount-input.js +243 -0
  10. package/dist/components/amount-input.js.map +1 -0
  11. package/dist/components/calculator.d.ts +42 -0
  12. package/dist/components/calculator.js +161 -0
  13. package/dist/components/calculator.js.map +1 -0
  14. package/dist/components/chart.d.ts +58 -0
  15. package/dist/components/chart.js +158 -0
  16. package/dist/components/chart.js.map +1 -0
  17. package/dist/components/combobox-core.d.ts +77 -0
  18. package/dist/components/combobox-core.js +263 -0
  19. package/dist/components/combobox-core.js.map +1 -0
  20. package/dist/components/combobox.d.ts +141 -0
  21. package/dist/components/combobox.js +550 -0
  22. package/dist/components/combobox.js.map +1 -0
  23. package/dist/components/currency-select.d.ts +37 -0
  24. package/dist/components/currency-select.js +131 -0
  25. package/dist/components/currency-select.js.map +1 -0
  26. package/dist/components/data-table-filter-popover.d.ts +28 -0
  27. package/dist/components/data-table-filter-popover.js +201 -0
  28. package/dist/components/data-table-filter-popover.js.map +1 -0
  29. package/dist/components/data-table-filters.d.ts +5 -0
  30. package/dist/components/data-table-filters.js +118 -0
  31. package/dist/components/data-table-filters.js.map +1 -0
  32. package/dist/components/data-table-labels.d.ts +33 -0
  33. package/dist/components/data-table-labels.js +53 -0
  34. package/dist/components/data-table-labels.js.map +1 -0
  35. package/dist/components/data-table-pagination.d.ts +18 -0
  36. package/dist/components/data-table-pagination.js +92 -0
  37. package/dist/components/data-table-pagination.js.map +1 -0
  38. package/dist/components/data-table-sort.d.ts +23 -0
  39. package/dist/components/data-table-sort.js +55 -0
  40. package/dist/components/data-table-sort.js.map +1 -0
  41. package/dist/components/data-table.d.ts +5 -0
  42. package/dist/components/data-table.js +926 -0
  43. package/dist/components/data-table.js.map +1 -0
  44. package/dist/components/date-picker.d.ts +85 -0
  45. package/dist/components/date-picker.js +253 -0
  46. package/dist/components/date-picker.js.map +1 -0
  47. package/dist/components/dropdown.d.ts +98 -0
  48. package/dist/components/dropdown.js +122 -0
  49. package/dist/components/dropdown.js.map +1 -0
  50. package/dist/components/entity-combobox.d.ts +49 -0
  51. package/dist/components/entity-combobox.js +115 -0
  52. package/dist/components/entity-combobox.js.map +1 -0
  53. package/dist/components/file-dropzone.d.ts +18 -0
  54. package/dist/components/file-dropzone.js +101 -0
  55. package/dist/components/file-dropzone.js.map +1 -0
  56. package/dist/components/full-bleed-dialog.d.ts +57 -0
  57. package/dist/components/full-bleed-dialog.js +68 -0
  58. package/dist/components/full-bleed-dialog.js.map +1 -0
  59. package/dist/components/grouped-picker.d.ts +37 -0
  60. package/dist/components/grouped-picker.js +87 -0
  61. package/dist/components/grouped-picker.js.map +1 -0
  62. package/dist/components/hover-menu.d.ts +16 -0
  63. package/dist/components/hover-menu.js +113 -0
  64. package/dist/components/hover-menu.js.map +1 -0
  65. package/dist/components/mini-calendar.d.ts +33 -0
  66. package/dist/components/mini-calendar.js +133 -0
  67. package/dist/components/mini-calendar.js.map +1 -0
  68. package/dist/components/modal.d.ts +76 -0
  69. package/dist/components/modal.js +156 -0
  70. package/dist/components/modal.js.map +1 -0
  71. package/dist/components/multi-entity-combobox.d.ts +47 -0
  72. package/dist/components/multi-entity-combobox.js +116 -0
  73. package/dist/components/multi-entity-combobox.js.map +1 -0
  74. package/dist/components/multi-select.d.ts +39 -0
  75. package/dist/components/multi-select.js +132 -0
  76. package/dist/components/multi-select.js.map +1 -0
  77. package/dist/components/number-input.d.ts +74 -0
  78. package/dist/components/number-input.js +114 -0
  79. package/dist/components/number-input.js.map +1 -0
  80. package/dist/components/numpad-sheet.d.ts +45 -0
  81. package/dist/components/numpad-sheet.js +102 -0
  82. package/dist/components/numpad-sheet.js.map +1 -0
  83. package/dist/components/picker-sheet.d.ts +44 -0
  84. package/dist/components/picker-sheet.js +78 -0
  85. package/dist/components/picker-sheet.js.map +1 -0
  86. package/dist/components/popover.d.ts +20 -0
  87. package/dist/components/popover.js +46 -0
  88. package/dist/components/popover.js.map +1 -0
  89. package/dist/components/search-field.d.ts +52 -0
  90. package/dist/components/search-field.js +64 -0
  91. package/dist/components/search-field.js.map +1 -0
  92. package/dist/components/settings-fields.d.ts +39 -0
  93. package/dist/components/settings-fields.js +17 -0
  94. package/dist/components/settings-fields.js.map +1 -0
  95. package/dist/components/swipeable-row.d.ts +60 -0
  96. package/dist/components/swipeable-row.js +115 -0
  97. package/dist/components/swipeable-row.js.map +1 -0
  98. package/dist/components/toggle-group.d.ts +34 -0
  99. package/dist/components/toggle-group.js +90 -0
  100. package/dist/components/toggle-group.js.map +1 -0
  101. package/dist/components/tooltip.d.ts +86 -0
  102. package/dist/components/tooltip.js +171 -0
  103. package/dist/components/tooltip.js.map +1 -0
  104. package/dist/components/ui.d.ts +239 -0
  105. package/dist/components/ui.js +512 -0
  106. package/dist/components/ui.js.map +1 -0
  107. package/dist/components/use-mobile-reveal.d.ts +31 -0
  108. package/dist/components/use-mobile-reveal.js +33 -0
  109. package/dist/components/use-mobile-reveal.js.map +1 -0
  110. package/dist/components/use-table-state.d.ts +54 -0
  111. package/dist/components/use-table-state.js +153 -0
  112. package/dist/components/use-table-state.js.map +1 -0
  113. package/dist/components/user-avatar.d.ts +23 -0
  114. package/dist/components/user-avatar.js +33 -0
  115. package/dist/components/user-avatar.js.map +1 -0
  116. package/dist/components/wizard-stepper.d.ts +14 -0
  117. package/dist/components/wizard-stepper.js +27 -0
  118. package/dist/components/wizard-stepper.js.map +1 -0
  119. package/dist/data-table-filters-aXyf0Xub.d.ts +261 -0
  120. package/dist/feedback/feedback-attachment.d.ts +63 -0
  121. package/dist/feedback/feedback-attachment.js +160 -0
  122. package/dist/feedback/feedback-attachment.js.map +1 -0
  123. package/dist/feedback/feedback-dialog.d.ts +72 -0
  124. package/dist/feedback/feedback-dialog.js +109 -0
  125. package/dist/feedback/feedback-dialog.js.map +1 -0
  126. package/dist/feedback/feedback-inbox.d.ts +226 -0
  127. package/dist/feedback/feedback-inbox.js +315 -0
  128. package/dist/feedback/feedback-inbox.js.map +1 -0
  129. package/dist/hooks/use-anchored-panel.d.ts +80 -0
  130. package/dist/hooks/use-anchored-panel.js +71 -0
  131. package/dist/hooks/use-anchored-panel.js.map +1 -0
  132. package/dist/hooks/use-anchored-rect.d.ts +24 -0
  133. package/dist/hooks/use-anchored-rect.js +40 -0
  134. package/dist/hooks/use-anchored-rect.js.map +1 -0
  135. package/dist/hooks/use-body-scroll-lock.d.ts +9 -0
  136. package/dist/hooks/use-body-scroll-lock.js +41 -0
  137. package/dist/hooks/use-body-scroll-lock.js.map +1 -0
  138. package/dist/hooks/use-close-transition.d.ts +41 -0
  139. package/dist/hooks/use-close-transition.js +36 -0
  140. package/dist/hooks/use-close-transition.js.map +1 -0
  141. package/dist/hooks/use-dismiss.d.ts +34 -0
  142. package/dist/hooks/use-dismiss.js +41 -0
  143. package/dist/hooks/use-dismiss.js.map +1 -0
  144. package/dist/hooks/use-media-query.d.ts +8 -0
  145. package/dist/hooks/use-media-query.js +18 -0
  146. package/dist/hooks/use-media-query.js.map +1 -0
  147. package/dist/hooks/use-overlay-history.d.ts +10 -0
  148. package/dist/hooks/use-overlay-history.js +99 -0
  149. package/dist/hooks/use-overlay-history.js.map +1 -0
  150. package/dist/hooks/use-row-swipe.d.ts +30 -0
  151. package/dist/hooks/use-row-swipe.js +128 -0
  152. package/dist/hooks/use-row-swipe.js.map +1 -0
  153. package/dist/index.d.ts +75 -0
  154. package/dist/index.js +90 -0
  155. package/dist/index.js.map +1 -0
  156. package/dist/lib/calc.d.ts +89 -0
  157. package/dist/lib/calc.js +180 -0
  158. package/dist/lib/calc.js.map +1 -0
  159. package/dist/lib/cn.d.ts +6 -0
  160. package/dist/lib/cn.js +7 -0
  161. package/dist/lib/cn.js.map +1 -0
  162. package/dist/lib/dates.d.ts +84 -0
  163. package/dist/lib/dates.js +108 -0
  164. package/dist/lib/dates.js.map +1 -0
  165. package/dist/lib/logger.d.ts +17 -0
  166. package/dist/lib/logger.js +30 -0
  167. package/dist/lib/logger.js.map +1 -0
  168. package/dist/lib/safe-storage.d.ts +23 -0
  169. package/dist/lib/safe-storage.js +20 -0
  170. package/dist/lib/safe-storage.js.map +1 -0
  171. package/dist/search/command-palette.d.ts +71 -0
  172. package/dist/search/command-palette.js +198 -0
  173. package/dist/search/command-palette.js.map +1 -0
  174. package/dist/shell/app-shell.d.ts +64 -0
  175. package/dist/shell/app-shell.js +237 -0
  176. package/dist/shell/app-shell.js.map +1 -0
  177. package/dist/shell/option-switcher-menu.d.ts +24 -0
  178. package/dist/shell/option-switcher-menu.js +44 -0
  179. package/dist/shell/option-switcher-menu.js.map +1 -0
  180. package/dist/shell/role-switcher.d.ts +19 -0
  181. package/dist/shell/role-switcher.js +28 -0
  182. package/dist/shell/role-switcher.js.map +1 -0
  183. package/dist/shell/top-bar.d.ts +15 -0
  184. package/dist/shell/top-bar.js +29 -0
  185. package/dist/shell/top-bar.js.map +1 -0
  186. package/dist/shell/topbar-action-menu.d.ts +44 -0
  187. package/dist/shell/topbar-action-menu.js +49 -0
  188. package/dist/shell/topbar-action-menu.js.map +1 -0
  189. package/dist/shell/topbar-controls.d.ts +54 -0
  190. package/dist/shell/topbar-controls.js +152 -0
  191. package/dist/shell/topbar-controls.js.map +1 -0
  192. package/dist/theme/chart-palette.d.ts +60 -0
  193. package/dist/theme/chart-palette.js +79 -0
  194. package/dist/theme/chart-palette.js.map +1 -0
  195. package/dist/theme/palette-presets.d.ts +39 -0
  196. package/dist/theme/palette-presets.js +440 -0
  197. package/dist/theme/palette-presets.js.map +1 -0
  198. package/dist/theme/palette-store.d.ts +45 -0
  199. package/dist/theme/palette-store.js +52 -0
  200. package/dist/theme/palette-store.js.map +1 -0
  201. package/dist/theme/theme-store.d.ts +57 -0
  202. package/dist/theme/theme-store.js +96 -0
  203. package/dist/theme/theme-store.js.map +1 -0
  204. package/dist/tour/tour.d.ts +104 -0
  205. package/dist/tour/tour.js +351 -0
  206. package/dist/tour/tour.js.map +1 -0
  207. package/dist/wizard/stepper-nav.d.ts +30 -0
  208. package/dist/wizard/stepper-nav.js +146 -0
  209. package/dist/wizard/stepper-nav.js.map +1 -0
  210. package/dist/wizard/types.d.ts +124 -0
  211. package/dist/wizard/types.js +24 -0
  212. package/dist/wizard/types.js.map +1 -0
  213. package/dist/wizard/use-wizard.d.ts +6 -0
  214. package/dist/wizard/use-wizard.js +222 -0
  215. package/dist/wizard/use-wizard.js.map +1 -0
  216. package/dist/wizard/validation.d.ts +23 -0
  217. package/dist/wizard/validation.js +13 -0
  218. package/dist/wizard/validation.js.map +1 -0
  219. package/dist/wizard/wizard-context.d.ts +19 -0
  220. package/dist/wizard/wizard-context.js +15 -0
  221. package/dist/wizard/wizard-context.js.map +1 -0
  222. package/dist/wizard/wizard-step.d.ts +11 -0
  223. package/dist/wizard/wizard-step.js +12 -0
  224. package/dist/wizard/wizard-step.js.map +1 -0
  225. package/dist/wizard/wizard-summary.d.ts +18 -0
  226. package/dist/wizard/wizard-summary.js +41 -0
  227. package/dist/wizard/wizard-summary.js.map +1 -0
  228. package/package.json +87 -0
  229. package/tokens.css +254 -0
package/tokens.css ADDED
@@ -0,0 +1,254 @@
1
+ /* @hb/ui design tokens + semantic utilities.
2
+ *
3
+ * The single source of truth for the shared appearance layer: brand + data
4
+ * colours (theme-aware via `.dark`), the semantic money utilities, the brand
5
+ * accent for checkboxes/radios, and the global keyframes/scrollbar chrome.
6
+ *
7
+ * Consumers import this ONCE (after their own `@import "tailwindcss"`):
8
+ * @import "@hb/ui/tokens.css";
9
+ * and add the package to Tailwind's source scan so its class names are kept:
10
+ * @source "../node_modules/@hb/ui/src";
11
+ *
12
+ * NOTE: these :root/.dark values MIRROR DEFAULT_PRESET in the palette theme module,
13
+ * which is what actually paints them — the palette layer writes the active preset
14
+ * tokens inline on <html> at runtime (Tailwind v4 strips a root block that holds only
15
+ * custom properties, so this block is a documentation mirror, not the live source).
16
+ *
17
+ * Because it is inert, it drifts silently, and it had: the surfaces and text colour
18
+ * below still held the pre-#328 palette while DEFAULT_PRESET had moved to Solar Dusk.
19
+ * They were resynced when --text-secondary/--text-muted were added (the new tones are
20
+ * derived from these surfaces, so a stale mirror would have documented a contrast ratio
21
+ * that was not the shipped one). The MONEY TRIO and the nine chart hues below are still
22
+ * the older values and have not been touched — nothing reads them, but do not cite them
23
+ * as the default without checking DEFAULT_PRESET first. */
24
+
25
+ @custom-variant dark (&:where(.dark, .dark *));
26
+
27
+ :root {
28
+ --bg-page: #ede3cf; /* warm dim sand — low-glare light page */
29
+ --bg-surface: #f6ecd9; /* warm off-white card/panel (not pure white) */
30
+ --bg-surface-2: #f3ead6; /* inset/well surface */
31
+ --border: #e2d6bd; /* warm hairline border */
32
+ --text-primary: #463f33; /* warm dark grey — not pure black */
33
+ /* The two quieter text roles. Contrast against the WORST of the three surfaces
34
+ above: 7.0:1 and 4.8:1, so both clear WCAG AA for normal text on all of them —
35
+ which is the reason they are tokens and not `text-slate-500`, a cool grey that
36
+ ignores the palette and sat at 4.4:1 on this ground. */
37
+ --text-secondary: #50493c;
38
+ --text-muted: #696153;
39
+ --brand: #4f46e5; /* indigo-600 */
40
+ --brand-hover: #4338ca; /* indigo-700 */
41
+ --brand-contrast: #ffffff;
42
+ --money-income: #0f766e; /* teal-700 */
43
+ --money-expense: #b45309; /* amber-700 */
44
+ --money-net: #6d28d9; /* violet-700 */
45
+ --money-neutral: #6b6253; /* warm slate */
46
+ --chart-1: #332288;
47
+ --chart-2: #88ccee;
48
+ --chart-3: #44aa99;
49
+ --chart-4: #117733;
50
+ --chart-5: #999933;
51
+ --chart-6: #ddcc77;
52
+ --chart-7: #cc6677;
53
+ --chart-8: #882255;
54
+ --chart-9: #aa4499;
55
+ }
56
+
57
+ .dark {
58
+ --bg-page: #0e0f1c; /* indigo near-black */
59
+ --bg-surface: #181a2c;
60
+ --bg-surface-2: #21243a; /* inset/well surface */
61
+ --border: #2e3252;
62
+ --text-primary: #e6e8f4;
63
+ /* As in `:root` — 7.0:1 and 4.8:1 against the worst of the three dark surfaces. */
64
+ --text-secondary: #adafbe;
65
+ --text-muted: #8d90a0;
66
+ --brand: #818cf8; /* indigo-400 */
67
+ --brand-hover: #a5b4fc; /* indigo-300 */
68
+ --brand-contrast: #1e1b4b; /* indigo-950 */
69
+ --money-income: #2dd4bf; /* teal-400 */
70
+ /* Deliberately NOT amber-400 (#fbbf24). Every other colour on a dark surface
71
+ sits around OKLab L 0.68–0.74 (brand 0.68, net 0.70, neutral 0.71, income
72
+ 0.74); amber-400 lands at 0.84, so outflows — most rows in a register — shouted
73
+ a tenth of a lightness step louder than inflows carrying the same weight of
74
+ meaning. Same hue (84°) and chroma, pulled to L 0.785: still 8.9:1 on the card
75
+ surface, still far from income in CVD space (Keksdose dev#434). */
76
+ --money-expense: #e4b035;
77
+ --money-net: #a98fd6;
78
+ --money-neutral: #a1a1aa; /* zinc-400 */
79
+ --chart-1: #7e72d6;
80
+ --chart-2: #9fd8f2;
81
+ --chart-3: #5fc4b0;
82
+ --chart-4: #3fa45f;
83
+ --chart-5: #bfbf5e;
84
+ --chart-6: #e8dda0;
85
+ --chart-7: #e08c9a;
86
+ --chart-8: #c25a78;
87
+ --chart-9: #cc78be;
88
+ }
89
+
90
+ /* Semantic colour utilities backed by the tokens above. Unlayered so they win
91
+ over Tailwind's layered colour utilities, and theme-aware for free (the var
92
+ flips under .dark) — no dark: variant needed at the call site. */
93
+ .text-money-pos { color: var(--money-income); }
94
+ .text-money-neg { color: var(--money-expense); }
95
+ .text-money-net { color: var(--money-net); }
96
+ .text-money-pos-muted { color: var(--money-income); opacity: 0.72; }
97
+ .text-money-neg-muted { color: var(--money-expense); opacity: 0.72; }
98
+ .text-brand { color: var(--brand); }
99
+ .bg-brand { background-color: var(--brand); }
100
+ .bg-money-pos { background-color: var(--money-income); }
101
+ .bg-money-neg { background-color: var(--money-expense); }
102
+ /* "No money has moved" — the fill for markers on rows that are not real yet
103
+ (scheduled / future-dated). Deliberately NOT brand and NOT money-pos: those
104
+ two mean settled, and a future row wearing one of them reads as done. */
105
+ .bg-money-neutral { background-color: var(--money-neutral); }
106
+ .border-brand { border-color: var(--brand); }
107
+
108
+ html, body, #root {
109
+ height: 100%;
110
+ }
111
+
112
+ /* NOT a `scrollbar-gutter` on the DOCUMENT — measured, and it is the wrong instrument.
113
+ *
114
+ * Below `AppShell`'s md breakpoint the viewport is the scroll container (main is only
115
+ * `md:overflow-y-auto`), so nothing reserves a gutter down there and a classic
116
+ * scrollbar takes ~15px out of the content box the moment a page outgrows the window:
117
+ * Keksdose live #307's follow-up, reported as "resizes slightly horizontally".
118
+ *
119
+ * Reserving it on `html` fixes that and breaks something worse. `scrollbar-gutter` on
120
+ * the root shrinks the INITIAL CONTAINING BLOCK, which is what `position: fixed` is
121
+ * laid out against — so every full-bleed overlay in the app stops 15px short on each
122
+ * edge. Measured at a 406px viewport: the row editor's dialog went from x=0/w=406 to
123
+ * x=15/w=376, with live page showing through both strips and tappable. That is
124
+ * Keksdose feedback #32's failure, worse: #32's strip at least belonged to the
125
+ * backdrop, and a tap on this one reaches the register behind the form.
126
+ *
127
+ * The only fix without that side effect is to give the viewport's job to an ELEMENT —
128
+ * dropping the `md:` gate on main's own `overflow-y-auto` — which changes how a phone
129
+ * scrolls (the URL bar stops collapsing) for a bug phones do not have, since overlay
130
+ * scrollbars take no layout space. Left as a decision rather than a silent trade. */
131
+
132
+ /* Checkboxes/radios default to a visible brand accent. The native dark fill
133
+ blended into the dark UI, so a checked box was almost indistinguishable from
134
+ an unchecked one (feedback #219). Must live in the base layer: unlayered
135
+ styles beat Tailwind's layered utilities regardless of specificity, which
136
+ silently overrode deliberate `accent-*` utilities like the destructive rose
137
+ fresh-start checkbox (feedback #264). */
138
+ @layer base {
139
+ :where(input[type="checkbox"], input[type="radio"]) {
140
+ accent-color: var(--brand); /* unified indigo brand accent (theme-aware) */
141
+ }
142
+ }
143
+
144
+ body {
145
+ background-color: var(--bg-page);
146
+ color: var(--text-primary);
147
+ }
148
+
149
+ /* Indeterminate progress bar (e.g. long imports, feedback #270): a third-width
150
+ segment sweeping the track. */
151
+ @keyframes indeterminate-sweep {
152
+ 0% { transform: translateX(-100%); }
153
+ 100% { transform: translateX(300%); }
154
+ }
155
+ .animate-indeterminate {
156
+ animation: indeterminate-sweep 1.4s ease-in-out infinite;
157
+ }
158
+
159
+ /* Overlay motion (Keksdose live #320: *"Evaluate how much work it would be to have
160
+ nicer transitions for the mobile users when clicking on a row … for all hoc derived
161
+ tables"*).
162
+ *
163
+ * Two keyframes rather than a library. Every overlay in this package is bottom-anchored
164
+ * on a phone and centred from md up, so one pair covers the row sheet, the modal, the
165
+ * picker and the numpad — and every table in every consuming app gets it by getting
166
+ * them, which is what the row asked for.
167
+ *
168
+ * Enter AND exit since the #320 rework — *"Recognized the opening transition. Choose
169
+ * transition should be the same, only backwards"*. The first round shipped the enter
170
+ * alone on the argument that an exit needs the element to stay mounted past the state
171
+ * change; that is still true, and `useCloseTransition` is where that state machine now
172
+ * lives, once, for every overlay in this package.
173
+ *
174
+ * The exit is the same two moves read backwards, at the same durations, on the mirrored
175
+ * curve (`ease-in` against `ease-out`, and the sheet's cubic reversed): a close that
176
+ * eases OUT of the screen at the speed it eased in reads as the same object leaving.
177
+ *
178
+ * 180ms and an ease-out curve: long enough to read as movement, short enough that it
179
+ * never delays a screen whose data is already in memory — which most of these are. The
180
+ * exit is what that budget is really spent on: every millisecond here is a millisecond
181
+ * between a tap on "Close" and the list being usable again, which is why it does not
182
+ * get the slower, more cinematic curve a first attempt reaches for.
183
+ */
184
+ @keyframes overlay-fade-in {
185
+ from { opacity: 0; }
186
+ to { opacity: 1; }
187
+ }
188
+ @keyframes sheet-rise-in {
189
+ from { transform: translateY(100%); }
190
+ to { transform: none; }
191
+ }
192
+ @keyframes overlay-fade-out {
193
+ from { opacity: 1; }
194
+ to { opacity: 0; }
195
+ }
196
+ @keyframes sheet-lower-out {
197
+ from { transform: none; }
198
+ to { transform: translateY(100%); }
199
+ }
200
+ .animate-overlay { animation: overlay-fade-in 0.18s ease-out; }
201
+ .animate-sheet { animation: sheet-rise-in 0.22s cubic-bezier(0.32, 0.72, 0, 1); }
202
+ /* `forwards` on both: the element is unmounted by a timer, and without a retained end
203
+ state the last painted frame before that timer fires is the panel back at full
204
+ opacity in its opening position — a flash of the thing you just dismissed. */
205
+ .animate-overlay-out { animation: overlay-fade-out 0.18s ease-in forwards; }
206
+ .animate-sheet-out { animation: sheet-lower-out 0.22s cubic-bezier(1, 0, 0.68, 0.28) forwards; }
207
+
208
+ /* Motion is the first thing to drop here, not the last. The overlay still fades — a
209
+ backdrop appearing instantly is a flash, not a transition — but nothing travels.
210
+ The EXIT pair is not listed: `useCloseTransition` reads the same media query and
211
+ closes immediately under it, so these classes are never applied at all. */
212
+ @media (prefers-reduced-motion: reduce) {
213
+ .animate-sheet { animation: none; }
214
+ .animate-overlay { animation-duration: 0.01ms; }
215
+ }
216
+
217
+ /* Chart drilldown fan-out/-in (feedback #260 rework): the remounted chart eases
218
+ in instead of snapping. */
219
+ @keyframes drill-in {
220
+ from { opacity: 0; transform: scale(0.96); }
221
+ to { opacity: 1; transform: none; }
222
+ }
223
+ .animate-drill {
224
+ animation: drill-in 0.25s ease-out;
225
+ }
226
+
227
+ /* Scrollbars: keep light defaults; theme to slate when dark mode is active. */
228
+ .dark {
229
+ color-scheme: dark;
230
+ scrollbar-color: rgb(51 65 85) rgb(15 23 42); /* slate-700 thumb on slate-900 track */
231
+ }
232
+
233
+ .dark ::-webkit-scrollbar {
234
+ width: 12px;
235
+ height: 12px;
236
+ }
237
+
238
+ .dark ::-webkit-scrollbar-track {
239
+ background-color: rgb(15 23 42); /* slate-900 */
240
+ }
241
+
242
+ .dark ::-webkit-scrollbar-thumb {
243
+ background-color: rgb(51 65 85); /* slate-700 */
244
+ border-radius: 6px;
245
+ border: 2px solid rgb(15 23 42); /* slate-900 — creates inset padding */
246
+ }
247
+
248
+ .dark ::-webkit-scrollbar-thumb:hover {
249
+ background-color: rgb(71 85 105); /* slate-600 */
250
+ }
251
+
252
+ .dark ::-webkit-scrollbar-corner {
253
+ background-color: rgb(15 23 42); /* slate-900 */
254
+ }