premium-ds 0.1.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 (257) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +113 -0
  3. package/dist/alert.d.ts +31 -0
  4. package/dist/alert.js +6 -0
  5. package/dist/alert.js.map +1 -0
  6. package/dist/avatar-group.d.ts +13 -0
  7. package/dist/avatar-group.js +3 -0
  8. package/dist/avatar-group.js.map +1 -0
  9. package/dist/avatar.d.ts +25 -0
  10. package/dist/avatar.js +3 -0
  11. package/dist/avatar.js.map +1 -0
  12. package/dist/badge.d.ts +23 -0
  13. package/dist/badge.js +3 -0
  14. package/dist/badge.js.map +1 -0
  15. package/dist/button.d.ts +20 -0
  16. package/dist/button.js +3 -0
  17. package/dist/button.js.map +1 -0
  18. package/dist/checkbox.d.ts +25 -0
  19. package/dist/checkbox.js +3 -0
  20. package/dist/checkbox.js.map +1 -0
  21. package/dist/chunk-2OWHZ4JT.js +36 -0
  22. package/dist/chunk-2OWHZ4JT.js.map +1 -0
  23. package/dist/chunk-34SIXSYL.js +64 -0
  24. package/dist/chunk-34SIXSYL.js.map +1 -0
  25. package/dist/chunk-37O2ZXD6.js +55 -0
  26. package/dist/chunk-37O2ZXD6.js.map +1 -0
  27. package/dist/chunk-4AZL76UJ.js +89 -0
  28. package/dist/chunk-4AZL76UJ.js.map +1 -0
  29. package/dist/chunk-4HSCN5TZ.js +86 -0
  30. package/dist/chunk-4HSCN5TZ.js.map +1 -0
  31. package/dist/chunk-5DDOOT33.js +258 -0
  32. package/dist/chunk-5DDOOT33.js.map +1 -0
  33. package/dist/chunk-5FVHWIMY.js +117 -0
  34. package/dist/chunk-5FVHWIMY.js.map +1 -0
  35. package/dist/chunk-5K6KRJGX.js +147 -0
  36. package/dist/chunk-5K6KRJGX.js.map +1 -0
  37. package/dist/chunk-5PQMQBQC.js +74 -0
  38. package/dist/chunk-5PQMQBQC.js.map +1 -0
  39. package/dist/chunk-7OCTVQ7C.js +95 -0
  40. package/dist/chunk-7OCTVQ7C.js.map +1 -0
  41. package/dist/chunk-7OPMOET7.js +39 -0
  42. package/dist/chunk-7OPMOET7.js.map +1 -0
  43. package/dist/chunk-BXXS7YRC.js +270 -0
  44. package/dist/chunk-BXXS7YRC.js.map +1 -0
  45. package/dist/chunk-CV2Q4YXX.js +272 -0
  46. package/dist/chunk-CV2Q4YXX.js.map +1 -0
  47. package/dist/chunk-EIMMDWIW.js +282 -0
  48. package/dist/chunk-EIMMDWIW.js.map +1 -0
  49. package/dist/chunk-EZ2CWTBE.js +230 -0
  50. package/dist/chunk-EZ2CWTBE.js.map +1 -0
  51. package/dist/chunk-FGHDG3Y4.js +89 -0
  52. package/dist/chunk-FGHDG3Y4.js.map +1 -0
  53. package/dist/chunk-FPP2XLKX.js +127 -0
  54. package/dist/chunk-FPP2XLKX.js.map +1 -0
  55. package/dist/chunk-G6OY35DI.js +295 -0
  56. package/dist/chunk-G6OY35DI.js.map +1 -0
  57. package/dist/chunk-H6KWJNOE.js +65 -0
  58. package/dist/chunk-H6KWJNOE.js.map +1 -0
  59. package/dist/chunk-HGILYGY3.js +45 -0
  60. package/dist/chunk-HGILYGY3.js.map +1 -0
  61. package/dist/chunk-I3BCB4Z5.js +88 -0
  62. package/dist/chunk-I3BCB4Z5.js.map +1 -0
  63. package/dist/chunk-KBWNUUWM.js +582 -0
  64. package/dist/chunk-KBWNUUWM.js.map +1 -0
  65. package/dist/chunk-KN7JFAZ6.js +113 -0
  66. package/dist/chunk-KN7JFAZ6.js.map +1 -0
  67. package/dist/chunk-MEF7PI6U.js +16 -0
  68. package/dist/chunk-MEF7PI6U.js.map +1 -0
  69. package/dist/chunk-NKGMQL6I.js +310 -0
  70. package/dist/chunk-NKGMQL6I.js.map +1 -0
  71. package/dist/chunk-NMFQRGLL.js +127 -0
  72. package/dist/chunk-NMFQRGLL.js.map +1 -0
  73. package/dist/chunk-OUBWD6CX.js +433 -0
  74. package/dist/chunk-OUBWD6CX.js.map +1 -0
  75. package/dist/chunk-PFNXVBLU.js +96 -0
  76. package/dist/chunk-PFNXVBLU.js.map +1 -0
  77. package/dist/chunk-PUPZ4HME.js +165 -0
  78. package/dist/chunk-PUPZ4HME.js.map +1 -0
  79. package/dist/chunk-QFS52OK5.js +690 -0
  80. package/dist/chunk-QFS52OK5.js.map +1 -0
  81. package/dist/chunk-QNC6O3PG.js +45 -0
  82. package/dist/chunk-QNC6O3PG.js.map +1 -0
  83. package/dist/chunk-QUHOXWBK.js +82 -0
  84. package/dist/chunk-QUHOXWBK.js.map +1 -0
  85. package/dist/chunk-UIQGSTBJ.js +106 -0
  86. package/dist/chunk-UIQGSTBJ.js.map +1 -0
  87. package/dist/chunk-UJQKVP6V.js +193 -0
  88. package/dist/chunk-UJQKVP6V.js.map +1 -0
  89. package/dist/chunk-VVPGEAC6.js +11 -0
  90. package/dist/chunk-VVPGEAC6.js.map +1 -0
  91. package/dist/chunk-XA3T5KWA.js +58 -0
  92. package/dist/chunk-XA3T5KWA.js.map +1 -0
  93. package/dist/chunk-YSHJHSJM.js +19 -0
  94. package/dist/chunk-YSHJHSJM.js.map +1 -0
  95. package/dist/chunk-YVHOAVSM.js +182 -0
  96. package/dist/chunk-YVHOAVSM.js.map +1 -0
  97. package/dist/collapse.d.ts +16 -0
  98. package/dist/collapse.js +3 -0
  99. package/dist/collapse.js.map +1 -0
  100. package/dist/count-badge.d.ts +11 -0
  101. package/dist/count-badge.js +4 -0
  102. package/dist/count-badge.js.map +1 -0
  103. package/dist/date-field.d.ts +39 -0
  104. package/dist/date-field.js +8 -0
  105. package/dist/date-field.js.map +1 -0
  106. package/dist/date-range-field.d.ts +30 -0
  107. package/dist/date-range-field.js +8 -0
  108. package/dist/date-range-field.js.map +1 -0
  109. package/dist/datetime-field.d.ts +28 -0
  110. package/dist/datetime-field.js +10 -0
  111. package/dist/datetime-field.js.map +1 -0
  112. package/dist/dialog.d.ts +26 -0
  113. package/dist/dialog.js +7 -0
  114. package/dist/dialog.js.map +1 -0
  115. package/dist/index.d.ts +35 -0
  116. package/dist/index.js +40 -0
  117. package/dist/index.js.map +1 -0
  118. package/dist/motion-tokens.d.ts +29 -0
  119. package/dist/motion-tokens.js +3 -0
  120. package/dist/motion-tokens.js.map +1 -0
  121. package/dist/multi-select.d.ts +25 -0
  122. package/dist/multi-select.js +7 -0
  123. package/dist/multi-select.js.map +1 -0
  124. package/dist/number-field.d.ts +24 -0
  125. package/dist/number-field.js +4 -0
  126. package/dist/number-field.js.map +1 -0
  127. package/dist/otp-field.d.ts +20 -0
  128. package/dist/otp-field.js +3 -0
  129. package/dist/otp-field.js.map +1 -0
  130. package/dist/overlay.d.ts +31 -0
  131. package/dist/overlay.js +4 -0
  132. package/dist/overlay.js.map +1 -0
  133. package/dist/pagination.d.ts +24 -0
  134. package/dist/pagination.js +5 -0
  135. package/dist/pagination.js.map +1 -0
  136. package/dist/radio-group.d.ts +46 -0
  137. package/dist/radio-group.js +6 -0
  138. package/dist/radio-group.js.map +1 -0
  139. package/dist/select-core-SAyS-8w0.d.ts +16 -0
  140. package/dist/select.d.ts +27 -0
  141. package/dist/select.js +7 -0
  142. package/dist/select.js.map +1 -0
  143. package/dist/status-badge.d.ts +17 -0
  144. package/dist/status-badge.js +5 -0
  145. package/dist/status-badge.js.map +1 -0
  146. package/dist/table.d.ts +65 -0
  147. package/dist/table.js +5 -0
  148. package/dist/table.js.map +1 -0
  149. package/dist/tabs.d.ts +44 -0
  150. package/dist/tabs.js +5 -0
  151. package/dist/tabs.js.map +1 -0
  152. package/dist/tag.d.ts +28 -0
  153. package/dist/tag.js +5 -0
  154. package/dist/tag.js.map +1 -0
  155. package/dist/text-field.d.ts +30 -0
  156. package/dist/text-field.js +6 -0
  157. package/dist/text-field.js.map +1 -0
  158. package/dist/textarea.d.ts +33 -0
  159. package/dist/textarea.js +5 -0
  160. package/dist/textarea.js.map +1 -0
  161. package/dist/time-field.d.ts +27 -0
  162. package/dist/time-field.js +6 -0
  163. package/dist/time-field.js.map +1 -0
  164. package/dist/toast-store.d.ts +75 -0
  165. package/dist/toast-store.js +3 -0
  166. package/dist/toast-store.js.map +1 -0
  167. package/dist/toast.d.ts +3 -0
  168. package/dist/toast.js +6 -0
  169. package/dist/toast.js.map +1 -0
  170. package/dist/toggle-tag.d.ts +24 -0
  171. package/dist/toggle-tag.js +4 -0
  172. package/dist/toggle-tag.js.map +1 -0
  173. package/dist/toggle.d.ts +21 -0
  174. package/dist/toggle.js +3 -0
  175. package/dist/toggle.js.map +1 -0
  176. package/dist/tooltip.d.ts +27 -0
  177. package/dist/tooltip.js +4 -0
  178. package/dist/tooltip.js.map +1 -0
  179. package/llms.txt +165 -0
  180. package/package.json +205 -0
  181. package/src/components/alert/Alert.tsx +118 -0
  182. package/src/components/alert/alert.css +136 -0
  183. package/src/components/avatar/Avatar.tsx +128 -0
  184. package/src/components/avatar/AvatarGroup.tsx +50 -0
  185. package/src/components/avatar/avatar.css +200 -0
  186. package/src/components/badge/Badge.tsx +66 -0
  187. package/src/components/badge/CountBadge.tsx +46 -0
  188. package/src/components/badge/StatusBadge.tsx +132 -0
  189. package/src/components/badge/badge.css +243 -0
  190. package/src/components/button/Button.tsx +68 -0
  191. package/src/components/button/button.css +222 -0
  192. package/src/components/checkbox/Checkbox.tsx +90 -0
  193. package/src/components/checkbox/checkbox.css +179 -0
  194. package/src/components/date-picker/DateField.tsx +362 -0
  195. package/src/components/date-picker/DateRangeField.tsx +533 -0
  196. package/src/components/date-picker/DateTimeField.tsx +177 -0
  197. package/src/components/date-picker/TimeField.tsx +100 -0
  198. package/src/components/date-picker/date-picker.css +591 -0
  199. package/src/components/date-picker/date-utils.ts +55 -0
  200. package/src/components/date-picker/field-shell.tsx +78 -0
  201. package/src/components/date-picker/glide-pill.tsx +81 -0
  202. package/src/components/date-picker/time-core.tsx +305 -0
  203. package/src/components/dialog/Dialog.tsx +181 -0
  204. package/src/components/dialog/dialog.css +170 -0
  205. package/src/components/glass/glass.css +100 -0
  206. package/src/components/icon/Icon.tsx +76 -0
  207. package/src/components/icon/IconSlot.tsx +11 -0
  208. package/src/components/icon/icon.css +33 -0
  209. package/src/components/input/NumberField.tsx +117 -0
  210. package/src/components/input/OtpField.tsx +118 -0
  211. package/src/components/input/TextField.tsx +123 -0
  212. package/src/components/input/input.css +335 -0
  213. package/src/components/motion/Collapse.tsx +33 -0
  214. package/src/components/motion/collapse.css +41 -0
  215. package/src/components/overlay/Overlay.tsx +239 -0
  216. package/src/components/overlay/overlay-core.tsx +565 -0
  217. package/src/components/overlay/overlay.css +119 -0
  218. package/src/components/overlay/sheet-drag.tsx +146 -0
  219. package/src/components/pagination/Pagination.tsx +140 -0
  220. package/src/components/pagination/pagination.css +48 -0
  221. package/src/components/radio-group/RadioGroup.tsx +182 -0
  222. package/src/components/radio-group/radio-group.css +277 -0
  223. package/src/components/select/MultiSelect.tsx +251 -0
  224. package/src/components/select/Select.tsx +235 -0
  225. package/src/components/select/select-core.tsx +417 -0
  226. package/src/components/select/select.css +386 -0
  227. package/src/components/table/Table.tsx +433 -0
  228. package/src/components/table/table.css +348 -0
  229. package/src/components/tabs/Tabs.tsx +371 -0
  230. package/src/components/tabs/tabs.css +228 -0
  231. package/src/components/tag/Tag.tsx +145 -0
  232. package/src/components/tag/ToggleTag.tsx +125 -0
  233. package/src/components/tag/tag.css +248 -0
  234. package/src/components/textarea/Textarea.tsx +197 -0
  235. package/src/components/textarea/textarea.css +219 -0
  236. package/src/components/toast/Toast.tsx +349 -0
  237. package/src/components/toast/toast-store.ts +266 -0
  238. package/src/components/toast/toast.css +233 -0
  239. package/src/components/toggle/Toggle.tsx +94 -0
  240. package/src/components/toggle/toggle.css +152 -0
  241. package/src/components/tooltip/Tooltip.tsx +365 -0
  242. package/src/components/tooltip/tooltip.css +86 -0
  243. package/src/index.ts +42 -0
  244. package/src/styles.css +39 -0
  245. package/src/tokens/avatar.css +20 -0
  246. package/src/tokens/color.css +56 -0
  247. package/src/tokens/elevation.css +20 -0
  248. package/src/tokens/fonts.css +3 -0
  249. package/src/tokens/glass.css +21 -0
  250. package/src/tokens/icons.css +7 -0
  251. package/src/tokens/layers.css +6 -0
  252. package/src/tokens/motion-tokens.ts +72 -0
  253. package/src/tokens/motion.css +49 -0
  254. package/src/tokens/radius.css +11 -0
  255. package/src/tokens/semantic.css +75 -0
  256. package/src/tokens/spacing.css +26 -0
  257. package/src/tokens/typography.css +54 -0
@@ -0,0 +1,100 @@
1
+ 'use client';
2
+
3
+ /* TimeField.tsx - standalone time field.
4
+ -------------------------------------------------------------------------
5
+ The segmented HH:MM machine (time-core.tsx) wearing the Input vocabulary -
6
+ usable anywhere a bare time is needed, without the calendar.
7
+
8
+ <TimeField
9
+ label="Send at"
10
+ value="09:30" // canonical 'HH:mm' (24h) | null
11
+ onChange={(t) => ...} // live - the instant both segments exist
12
+ format="12h" // display only; storage stays 24h
13
+ minuteStep={15} // ↑/↓ granularity (typing is exact)
14
+ min="09:00" max="17:30" // saturation bounds - clamp, never error
15
+ />
16
+
17
+ Primitives consumed (A8): the .fld Input vocabulary (label/message/error
18
+ chrome), TimeSegments (the machine), Icon. The box is a div wearing
19
+ .fld__input - clicking its empty area seats focus in the hours segment.
20
+ Buildless global was window.TimeField; a bundled app imports it. */
21
+
22
+ import type { PointerEvent } from 'react';
23
+ import { FieldShell, useControllable } from './field-shell';
24
+ import { TimeSegments } from './time-core';
25
+
26
+ export interface TimeFieldProps {
27
+ /** Controlled value, canonical 'HH:mm' (24h). */
28
+ value?: string | null;
29
+ defaultValue?: string | null;
30
+ /** Fires live - the instant both segments exist. */
31
+ onChange?: (value: string) => void;
32
+ label?: string;
33
+ /** Display only; storage stays 24h. Default '24h'. */
34
+ format?: '24h' | '12h';
35
+ /** ↑/↓ step granularity in minutes (typing is exact). Default 5. */
36
+ minuteStep?: number;
37
+ /** Lower bound 'HH:mm' - saturates, never errors. */
38
+ min?: string;
39
+ /** Upper bound 'HH:mm' - saturates, never errors. */
40
+ max?: string;
41
+ required?: boolean;
42
+ invalid?: boolean;
43
+ message?: string;
44
+ disabled?: boolean;
45
+ className?: string;
46
+ }
47
+
48
+ export function TimeField({
49
+ value, // controlled: 'HH:mm' | null
50
+ defaultValue = null,
51
+ onChange,
52
+ label,
53
+ format = '24h',
54
+ minuteStep = 5,
55
+ min,
56
+ max,
57
+ required = false,
58
+ invalid = false,
59
+ message,
60
+ disabled = false,
61
+ className = '',
62
+ }: TimeFieldProps) {
63
+ const [val, commit] = useControllable(value, defaultValue, onChange);
64
+
65
+ /* clicking the box (not a segment) seats focus where typing starts */
66
+ function onBoxPointerDown(e: PointerEvent<HTMLDivElement>) {
67
+ if (disabled || (e.target as HTMLElement).closest('.tsg__seg')) return;
68
+ e.preventDefault();
69
+ const seg = e.currentTarget.querySelector('.tsg__seg') as HTMLElement | null;
70
+ if (seg) seg.focus();
71
+ }
72
+
73
+ return (
74
+ <FieldShell
75
+ variant="tfd"
76
+ label={label}
77
+ required={required}
78
+ invalid={invalid}
79
+ message={message}
80
+ icon="clock"
81
+ className={className}
82
+ >
83
+ <div
84
+ className={'fld__input tfd__box' + (disabled ? ' is-disabled' : '')}
85
+ onPointerDown={onBoxPointerDown}
86
+ >
87
+ <TimeSegments
88
+ value={val}
89
+ onCommit={commit}
90
+ format={format}
91
+ minuteStep={minuteStep}
92
+ min={min}
93
+ max={max}
94
+ disabled={disabled}
95
+ ariaLabel={label || 'Time'}
96
+ />
97
+ </div>
98
+ </FieldShell>
99
+ );
100
+ }
@@ -0,0 +1,591 @@
1
+ /* date-picker domain - geometry + paint for DateField/DateTimeField (.dtp*), DateRangeField (.drp*), TimeField (.tfd*, .tsg*). */
2
+
3
+ .dtf__trigger {
4
+ display: flex;
5
+ align-items: center;
6
+ text-align: left;
7
+ cursor: pointer;
8
+ gap: var(--space-2);
9
+ }
10
+ .dtf__value {
11
+ font: var(--type-mono);
12
+ font-variant-numeric: tabular-nums;
13
+ color: var(--text-strong);
14
+ }
15
+ .dtf__placeholder {
16
+ color: var(--text-disabled);
17
+ }
18
+ .dtf__trigger:disabled .dtf__value {
19
+ color: var(--text-disabled);
20
+ }
21
+
22
+ /* open - focus moves into the panel, so the trigger holds the focus look itself while expanded. */
23
+ .dtf__trigger[aria-expanded='true']:not(:disabled) {
24
+ border-color: var(--accent);
25
+ background: var(--bg-surface);
26
+ box-shadow: var(--ring-accent);
27
+ }
28
+
29
+ .dtp {
30
+ --dtp-cell: var(--control-height);
31
+ background: var(--bg-surface-raised);
32
+ border: var(--border-hairline) solid var(--border-default);
33
+ border-radius: var(--radius-lg);
34
+ box-shadow: var(--shadow-lg);
35
+ overflow: hidden;
36
+ }
37
+
38
+ .dtp__cal {
39
+ padding: var(--space-3) var(--space-3) var(--space-2);
40
+ }
41
+
42
+ /* header - month flush-left (semibold sans), year as a quiet mono chip; carets + today-jump grouped right. */
43
+ .dtp__head {
44
+ display: flex;
45
+ align-items: center;
46
+ justify-content: space-between;
47
+ gap: var(--space-2);
48
+ margin-inline: calc(-1 * var(--space-3));
49
+ padding-inline: var(--space-3);
50
+ padding-bottom: var(--space-2);
51
+ border-bottom: var(--border-hairline) solid var(--border-subtle);
52
+ margin-bottom: var(--space-3);
53
+ }
54
+ .dtp__month {
55
+ padding-inline-start: var(--space-2); /* optical: toward the first numeral */
56
+ display: inline-flex;
57
+ align-items: center;
58
+ gap: var(--space-2);
59
+ font: var(--type-caption);
60
+ font-weight: var(--weight-semibold);
61
+ color: var(--text-strong);
62
+ }
63
+ .dtp__year {
64
+ font-family: var(--font-mono);
65
+ font-size: var(--size-micro);
66
+ line-height: 1;
67
+ font-weight: var(--weight-regular);
68
+ font-variant-numeric: tabular-nums;
69
+ color: var(--text-subtle);
70
+ background: var(--bg-muted);
71
+ padding: var(--space-1);
72
+ border-radius: var(--radius-sm);
73
+ }
74
+ .dtp__navs {
75
+ display: flex;
76
+ gap: var(--space-1);
77
+ }
78
+ .dtp__nav {
79
+ width: var(--control-height-sm);
80
+ height: var(--control-height-sm);
81
+ display: grid;
82
+ place-items: center;
83
+ border: 0;
84
+ background: transparent;
85
+ color: var(--text-muted);
86
+ border-radius: var(--radius-sm);
87
+ cursor: pointer;
88
+ transition: var(--transition-colors);
89
+ }
90
+ .dtp__nav:hover:not(:disabled) {
91
+ background: var(--bg-subtle);
92
+ color: var(--text-strong);
93
+ }
94
+ .dtp__nav:active:not(:disabled) {
95
+ background: var(--bg-muted);
96
+ }
97
+ .dtp__nav:focus-visible {
98
+ outline: none;
99
+ box-shadow: var(--focus-ring);
100
+ }
101
+ .dtp__nav:disabled {
102
+ color: var(--text-disabled);
103
+ cursor: default;
104
+ }
105
+
106
+ .dtp__dow {
107
+ display: grid;
108
+ grid-template-columns: repeat(7, var(--dtp-cell));
109
+ gap: var(--space-1);
110
+ padding-bottom: var(--space-3);
111
+ }
112
+ .dtp__dow span {
113
+ font: var(--type-micro);
114
+ color: var(--text-subtle);
115
+ text-align: center;
116
+ }
117
+
118
+ .dtp__days {
119
+ position: relative; /* containing block + measuring frame for the glide pill */
120
+ display: grid;
121
+ grid-template-columns: repeat(7, var(--dtp-cell));
122
+ gap: var(--space-1);
123
+ isolation: isolate; /* the hover pill's z:-1 must resolve here, above the panel bg, below cell content */
124
+ }
125
+ /* ARIA rows - no boxes; the buttons stay direct grid items */
126
+ .dtp__row {
127
+ display: contents;
128
+ }
129
+
130
+ /* day cell - the button must create no stacking context, so the pill (z0) / numeral (z1) resolve at grid level. */
131
+ .dtp__day {
132
+ position: relative;
133
+ width: var(--dtp-cell);
134
+ height: var(--dtp-cell);
135
+ display: grid;
136
+ place-items: center;
137
+ border: 0;
138
+ padding: 0;
139
+ background: transparent;
140
+ border-radius: var(--radius-md);
141
+ font-family: var(--font-mono);
142
+ font-size: var(--size-caption);
143
+ font-variant-numeric: tabular-nums;
144
+ color: var(--text-body);
145
+ cursor: pointer;
146
+ transition: var(--transition-colors);
147
+ }
148
+ .dtp__day:hover:not(:disabled) {
149
+ color: var(--text-strong);
150
+ } /* background comes from the shared glide pill, not per-cell */
151
+ .dtp__day:focus-visible {
152
+ outline: none;
153
+ box-shadow: var(--focus-ring);
154
+ }
155
+ .dtp__day.is-out {
156
+ color: var(--text-subtle);
157
+ }
158
+ .dtp__day:disabled {
159
+ color: var(--text-disabled);
160
+ cursor: default;
161
+ }
162
+
163
+ /* gliding hover pill (useGlide) - bg-muted (not -subtle, else ~ invisible on the raised surface); z:-1 under numerals + selection tint. */
164
+ .dtp__hover {
165
+ position: absolute;
166
+ top: 0;
167
+ left: 0;
168
+ z-index: -1;
169
+ border-radius: var(--radius-md);
170
+ background: var(--bg-muted);
171
+ will-change: transform, opacity;
172
+ }
173
+
174
+ /* selection - a quiet tint, not a solid fill (so it never outshouts Done); the layoutId node, so fill + border travel together. */
175
+ .dtp__pill {
176
+ position: absolute;
177
+ inset: 0;
178
+ z-index: 0;
179
+ border-radius: var(--radius-md);
180
+ background: var(--accent-subtle);
181
+ border: var(--border-hairline) solid var(--accent-border);
182
+ }
183
+ .dtp__num {
184
+ position: relative;
185
+ z-index: 1;
186
+ }
187
+ .dtp__day.is-selected .dtp__num {
188
+ color: var(--text-accent);
189
+ font-weight: var(--weight-semibold);
190
+ }
191
+
192
+ /* today - accent numeral + a short bar, never a fill (fill means "picked"); reads on the selection tint too. */
193
+ .dtp__day.is-today .dtp__num {
194
+ color: var(--text-accent);
195
+ font-weight: var(--weight-semibold);
196
+ }
197
+ .dtp__dot {
198
+ position: absolute;
199
+ bottom: var(--space-1);
200
+ left: 50%;
201
+ width: var(--space-2);
202
+ height: calc(var(--space-px) * 2);
203
+ margin-left: calc(-1 * var(--space-1));
204
+ border-radius: var(--space-px);
205
+ background: var(--accent);
206
+ z-index: 1;
207
+ }
208
+ .dtp__day:disabled .dtp__num {
209
+ color: var(--text-disabled);
210
+ }
211
+ .dtp__day:disabled .dtp__dot {
212
+ background: var(--text-disabled);
213
+ }
214
+
215
+ /* time row - DateTimeField's slot, between the grid and the footer */
216
+ .dtp__time {
217
+ display: flex;
218
+ align-items: center;
219
+ gap: var(--space-2);
220
+ padding: var(--space-2) var(--space-3);
221
+ border-top: var(--border-hairline) solid var(--border-subtle);
222
+ }
223
+ .dtp__timeLabel {
224
+ font: var(--type-caption);
225
+ font-weight: var(--weight-medium);
226
+ color: var(--text-muted);
227
+ margin-right: auto;
228
+ }
229
+
230
+ /* keyboard hint - shown only on focus-within; asymmetric easing (eases in, leaves fast). */
231
+ .dtp__timeHint {
232
+ display: inline-flex;
233
+ gap: var(--space-1);
234
+ opacity: 0;
235
+ transform: translateX(var(--space-1));
236
+ pointer-events: none;
237
+ transition:
238
+ opacity var(--duration-fast) var(--ease-exit),
239
+ transform var(--duration-fast) var(--ease-exit);
240
+ }
241
+ .dtp__time:focus-within .dtp__timeHint {
242
+ opacity: 1;
243
+ transform: none;
244
+ transition:
245
+ opacity var(--duration-base) var(--ease-entrance),
246
+ transform var(--duration-base) var(--ease-entrance);
247
+ }
248
+ .dtp__timeHint kbd {
249
+ font-family: var(--font-mono);
250
+ font-size: var(--size-micro);
251
+ line-height: 1;
252
+ color: var(--text-subtle);
253
+ background: var(--bg-subtle);
254
+ border: var(--border-hairline) solid var(--border-subtle);
255
+ border-radius: var(--radius-sm);
256
+ padding: var(--space-1);
257
+ }
258
+
259
+ .dtp__foot {
260
+ display: flex;
261
+ align-items: center;
262
+ gap: var(--space-3);
263
+ padding: var(--space-2) var(--space-3);
264
+ background: var(--bg-subtle);
265
+ border-top: var(--border-hairline) solid var(--border-subtle);
266
+ }
267
+ .dtp__tz {
268
+ font-family: var(--font-mono);
269
+ font-size: var(--size-caption);
270
+ font-variant-numeric: tabular-nums;
271
+ color: var(--text-subtle);
272
+ white-space: nowrap;
273
+ overflow: hidden;
274
+ text-overflow: ellipsis;
275
+ }
276
+ .dtp__footSpacer {
277
+ flex: 1 1 auto;
278
+ }
279
+
280
+ .drp {
281
+ --dtp-cell: var(
282
+ --control-height
283
+ ); /* the day grid reuses .dtp__days/.dtp__dow, which size columns off this var */
284
+ background: var(--bg-surface-raised);
285
+ border: var(--border-hairline) solid var(--border-default);
286
+ border-radius: var(--radius-lg);
287
+ box-shadow: var(--shadow-lg);
288
+ overflow: hidden;
289
+ }
290
+ .drp__body {
291
+ display: flex;
292
+ align-items: stretch;
293
+ }
294
+
295
+ .drp__presets {
296
+ flex: none;
297
+ width: max-content; /* sized by the longest preset label - no magic width number */
298
+ display: flex;
299
+ flex-direction: column;
300
+ gap: var(--space-px);
301
+ padding: var(--space-3) var(--space-2);
302
+ border-right: var(--border-hairline) solid var(--border-subtle);
303
+ background: var(--bg-subtle);
304
+ isolation: isolate; /* the glide pill's z:-1 resolves here */
305
+ }
306
+ .drp__preset {
307
+ position: relative;
308
+ appearance: none;
309
+ text-align: left;
310
+ border: 0;
311
+ background: transparent;
312
+ color: var(--text-body);
313
+ font: var(--type-caption);
314
+ padding: var(--space-2);
315
+ border-radius: var(--radius-md);
316
+ cursor: pointer;
317
+ transition: var(--transition-colors);
318
+ white-space: nowrap;
319
+ }
320
+ .drp__preset:hover {
321
+ color: var(--text-strong);
322
+ } /* bg comes from the glide pill */
323
+ .drp__preset:focus-visible {
324
+ outline: none;
325
+ box-shadow: var(--ring-accent);
326
+ }
327
+ .drp__preset.is-active {
328
+ background: var(--accent-subtle);
329
+ color: var(--text-accent);
330
+ font-weight: var(--weight-medium);
331
+ }
332
+ /* gliding hover indicator - one pill that glides between presets (see glide-pill); the active tint is separate. */
333
+ .drp__presetGlide {
334
+ position: absolute;
335
+ top: 0;
336
+ left: 0;
337
+ z-index: -1;
338
+ border-radius: var(--radius-md);
339
+ background: var(--bg-muted);
340
+ will-change: transform, opacity;
341
+ }
342
+
343
+ .drp__months {
344
+ position: relative; /* containing block + measuring frame for the glide pill spanning both grids */
345
+ isolation: isolate; /* contain the pill's z:-1 here, else it paints behind the panel surface */
346
+ display: flex;
347
+ }
348
+ .drp__months .dtp__cal {
349
+ padding: var(--space-3);
350
+ }
351
+ .drp__months .dtp__cal + .dtp__cal {
352
+ border-left: var(--border-hairline) solid var(--border-subtle);
353
+ }
354
+
355
+ /* directional month slide - CSS keyframe on the keyed grid remount (can't fight Motion's layoutId caps); gated on reduced-motion. */
356
+ @media (prefers-reduced-motion: no-preference) {
357
+ .drp .dtp__days[data-enter='1'] {
358
+ animation: drp-month-in-l var(--duration-base) var(--ease-entrance);
359
+ }
360
+ .drp .dtp__days[data-enter='-1'] {
361
+ animation: drp-month-in-r var(--duration-base) var(--ease-entrance);
362
+ }
363
+ }
364
+ @keyframes drp-month-in-l {
365
+ from {
366
+ opacity: 0;
367
+ transform: translateX(16px);
368
+ }
369
+ to {
370
+ opacity: 1;
371
+ transform: none;
372
+ }
373
+ }
374
+ @keyframes drp-month-in-r {
375
+ from {
376
+ opacity: 0;
377
+ transform: translateX(-16px);
378
+ }
379
+ to {
380
+ opacity: 1;
381
+ transform: none;
382
+ }
383
+ }
384
+
385
+ /* month header - prev caret hugs the left edge, next caret the right; the label centers between. */
386
+ .drp__mhead {
387
+ display: flex;
388
+ align-items: center;
389
+ gap: var(--space-2);
390
+ padding-bottom: var(--space-3);
391
+ margin-bottom: var(--space-3);
392
+ border-bottom: var(--border-hairline) solid var(--border-subtle);
393
+ margin-inline: calc(-1 * var(--space-3));
394
+ padding-inline: var(--space-3);
395
+ }
396
+ .drp__mhead .dtp__month {
397
+ flex: 1 1 auto;
398
+ text-align: center;
399
+ padding-inline-start: 0;
400
+ }
401
+ .drp__mhead--right {
402
+ justify-content: space-between;
403
+ }
404
+
405
+ /* range band - extends 1px into the 4px gap toward an in-range neighbour (kills the subpixel seam), rounds where it stops. */
406
+ .drp__band {
407
+ position: absolute;
408
+ inset: 0;
409
+ z-index: 0;
410
+ background: var(
411
+ --accent-subtle
412
+ ); /* opaque, so the 1px gap-bridge overlaps don't stack into darker seams between days */
413
+ }
414
+ .drp__band--extL {
415
+ left: calc(-1 * var(--space-1) - 1px);
416
+ }
417
+ .drp__band--extR {
418
+ right: calc(-1 * var(--space-1) - 1px);
419
+ }
420
+ .drp__band--roundL {
421
+ border-top-left-radius: var(--radius-md);
422
+ border-bottom-left-radius: var(--radius-md);
423
+ }
424
+ .drp__band--roundR {
425
+ border-top-right-radius: var(--radius-md);
426
+ border-bottom-right-radius: var(--radius-md);
427
+ }
428
+
429
+ /* endpoint cap - a Motion layoutId node that glides between cells; the ghost variant (outline, no fill) marks the tentative end. */
430
+ .drp__cap {
431
+ position: absolute;
432
+ inset: 0;
433
+ z-index: 1;
434
+ border-radius: var(--radius-md);
435
+ background: var(
436
+ --accent-border
437
+ ); /* more opaque than the band - a clear selection marker, not a heavy solid fill */
438
+ }
439
+ .drp__cap--ghost {
440
+ background: transparent;
441
+ border: var(--border-hairline) solid var(--accent);
442
+ }
443
+
444
+ /* numerals ride above caps (z2); selection reads strong accent, in-range a touch quieter. */
445
+ .drp .dtp__num {
446
+ z-index: 2;
447
+ }
448
+ .drp .dtp__day.is-in-range .dtp__num {
449
+ color: var(--text-accent);
450
+ }
451
+ .drp .dtp__day.is-cap .dtp__num,
452
+ .drp .dtp__day.is-cap-ghost .dtp__num {
453
+ color: var(--text-accent);
454
+ font-weight: var(--weight-semibold);
455
+ }
456
+
457
+ .drp .dtp__day.is-cap .dtp__dot,
458
+ .drp .dtp__day.is-cap-ghost .dtp__dot {
459
+ background: var(--accent);
460
+ }
461
+
462
+ .drp__foot {
463
+ display: flex;
464
+ align-items: center;
465
+ gap: var(--space-3);
466
+ padding: var(--space-2) var(--space-3);
467
+ background: var(--bg-subtle);
468
+ border-top: var(--border-hairline) solid var(--border-subtle);
469
+ }
470
+ .drp__readout {
471
+ font-family: var(--font-mono);
472
+ font-size: var(--size-caption);
473
+ font-variant-numeric: tabular-nums;
474
+ color: var(--text-body);
475
+ white-space: nowrap;
476
+ }
477
+ .drp__readout .drp__count {
478
+ color: var(--text-subtle);
479
+ }
480
+ .drp__readout.is-empty {
481
+ color: var(--text-disabled);
482
+ }
483
+ .drp__tz {
484
+ font-family: var(--font-mono);
485
+ font-size: var(--size-caption);
486
+ font-variant-numeric: tabular-nums;
487
+ color: var(--text-subtle);
488
+ white-space: nowrap;
489
+ }
490
+ .drp__footSpacer {
491
+ flex: 1 1 auto;
492
+ }
493
+
494
+ /* bottom-sheet skin (mobile) - sheds border/shadow (the sheet supplies elevation), rounds only top corners, one month. */
495
+ .drp--sheet {
496
+ --dtp-cell: var(--control-height-lg);
497
+ } /* 40px touch targets */
498
+ .drp--sheet {
499
+ width: 100vw;
500
+ max-width: 100%;
501
+ border: 0;
502
+ border-radius: var(--radius-xl) var(--radius-xl) 0 0;
503
+ box-shadow: none;
504
+ }
505
+ .drp--sheet .drp__body {
506
+ flex-direction: column;
507
+ }
508
+ .drp--sheet .drp__presets {
509
+ width: auto;
510
+ flex-direction: row;
511
+ overflow-x: auto;
512
+ gap: var(--space-1);
513
+ border-right: 0;
514
+ border-bottom: var(--border-hairline) solid var(--border-subtle);
515
+ scrollbar-width: none;
516
+ }
517
+ .drp--sheet .drp__presets::-webkit-scrollbar {
518
+ display: none;
519
+ }
520
+ .drp--sheet .drp__preset {
521
+ flex: none;
522
+ }
523
+ .drp--sheet .drp__months {
524
+ justify-content: center;
525
+ padding-block: var(--space-2);
526
+ }
527
+
528
+ .tsg {
529
+ display: inline-flex;
530
+ align-items: center;
531
+ font-family: var(--font-mono);
532
+ font-size: var(--size-caption);
533
+ font-variant-numeric: tabular-nums;
534
+ color: var(--text-strong);
535
+ }
536
+ .tsg__seg {
537
+ padding: var(--space-1);
538
+ border-radius: var(--radius-sm);
539
+ outline: none;
540
+ cursor: text;
541
+ user-select: none;
542
+ transition: var(--transition-colors);
543
+ }
544
+ /* :focus, not :focus-visible, on purpose - a clicked segment reads selected like keyboard entry. */
545
+ .tsg__seg:focus {
546
+ background: var(--accent-subtle);
547
+ color: var(--text-accent);
548
+ }
549
+ .tsg__seg.is-empty {
550
+ color: var(--text-disabled);
551
+ }
552
+ .tsg__seg.is-empty:focus {
553
+ color: var(--text-accent);
554
+ }
555
+ .tsg__sep {
556
+ color: var(--text-subtle);
557
+ }
558
+ .tsg__seg--mer {
559
+ margin-left: var(--space-1);
560
+ }
561
+
562
+ .tsg.is-disabled,
563
+ .tsg.is-disabled .tsg__seg {
564
+ color: var(--text-disabled);
565
+ cursor: not-allowed;
566
+ }
567
+
568
+ /* .tfd__box is a DIV wearing .fld__input chrome, so input's :focus can't reach it - re-stated as :focus-within, scoped under .tfd to win the cascade. */
569
+ .tfd__box {
570
+ display: inline-flex;
571
+ align-items: center;
572
+ cursor: text;
573
+ }
574
+ .tfd .tfd__box:focus-within {
575
+ border-color: var(--accent);
576
+ background: var(--bg-surface);
577
+ box-shadow: var(--ring-accent);
578
+ }
579
+ .tfd.is-error .tfd__box {
580
+ border-color: var(--danger);
581
+ }
582
+ .tfd.is-error .tfd__box:hover:not(.is-disabled):not(:focus-within) {
583
+ border-color: var(--danger-text);
584
+ }
585
+ .tfd.is-error .tfd__box:focus-within {
586
+ box-shadow: var(--ring-danger);
587
+ }
588
+ .tfd .tfd__box.is-disabled {
589
+ background: var(--bg-muted);
590
+ cursor: not-allowed;
591
+ }