@crievo/omni 0.1.3 → 0.1.4

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 (96) hide show
  1. package/package.json +2 -1
  2. package/reference/learnings.md +12 -0
  3. package/studio/api/app.ts +2 -2
  4. package/studio/api/routes/sound.ts +22 -3
  5. package/studio/api/services/sound.ts +45 -0
  6. package/studio/studio.ts +1 -0
  7. package/studio/web/components/AppShell.tsx +3 -1
  8. package/studio/web/components/CloneVoiceDialog/RecordStep.tsx +3 -0
  9. package/studio/web/components/CloneVoiceDialog/RecorderBar.tsx +37 -20
  10. package/studio/web/components/CloneVoiceDialog/useCloneVoice.ts +39 -12
  11. package/studio/web/components/MissingDmsPanel/BatchSend.tsx +13 -4
  12. package/studio/web/components/Omni/OmniWidget.tsx +14 -5
  13. package/studio/web/components/Omni/PendingActions.tsx +25 -6
  14. package/studio/web/components/OmnichatRulePanel/RuleConfig.tsx +13 -3
  15. package/studio/web/components/OmnichatRulePanel/RuleEnableConfirm.tsx +14 -4
  16. package/studio/web/components/ResultMessage.tsx +12 -3
  17. package/studio/web/components/Sidebar.tsx +63 -24
  18. package/studio/web/components/StageStepper.tsx +105 -34
  19. package/studio/web/components/Toaster.tsx +25 -0
  20. package/studio/web/components/VoiceCarousel.tsx +19 -16
  21. package/studio/web/components/VoiceProfilesSettings.tsx +8 -3
  22. package/studio/web/components/bencho/ActionNode.tsx +456 -0
  23. package/studio/web/components/bencho/AssigneePicker.tsx +246 -0
  24. package/studio/web/components/bencho/BenchoScope.tsx +8 -0
  25. package/studio/web/components/bencho/Checklist.tsx +421 -0
  26. package/studio/web/components/bencho/CreateMenu.tsx +258 -0
  27. package/studio/web/components/bencho/GenerateImage.tsx +290 -0
  28. package/studio/web/components/bencho/ImageAccordion.tsx +273 -0
  29. package/studio/web/components/bencho/LiquidToggle.tsx +289 -0
  30. package/studio/web/components/bencho/MagnifyDock.tsx +200 -0
  31. package/studio/web/components/bencho/NowPlaying.tsx +403 -0
  32. package/studio/web/components/bencho/OneTimeCode.tsx +374 -0
  33. package/studio/web/components/bencho/PullToRefresh.tsx +527 -0
  34. package/studio/web/components/bencho/SlideToConfirm.tsx +385 -0
  35. package/studio/web/components/bencho/SloshSlider.tsx +394 -0
  36. package/studio/web/components/bencho/StackedBars.tsx +342 -0
  37. package/studio/web/components/bencho/ToastStack.tsx +263 -0
  38. package/studio/web/components/bencho/UploadDropzone.tsx +394 -0
  39. package/studio/web/components/bencho/VoiceNote.tsx +705 -0
  40. package/studio/web/components/icons.tsx +27 -0
  41. package/studio/web/components/ui/slider.tsx +34 -1
  42. package/studio/web/components/ui/switch.tsx +18 -5
  43. package/studio/web/index.html +1 -1
  44. package/studio/web/lib/omni-panel.ts +4 -1
  45. package/studio/web/lib/toast.ts +196 -0
  46. package/studio/web/lib/upload.ts +24 -0
  47. package/studio/web/pages/BenchoPage/index.tsx +74 -0
  48. package/studio/web/pages/BenchoPage/registry.ts +174 -0
  49. package/studio/web/pages/NewVideoPage/index.tsx +6 -2
  50. package/studio/web/pages/ReferencesPage/index.tsx +4 -1
  51. package/studio/web/pages/VideoPage/components/ChangedVoices.tsx +14 -17
  52. package/studio/web/pages/VideoPage/components/LineTextEditor.tsx +1 -1
  53. package/studio/web/pages/VideoPage/components/PublishForm.tsx +24 -17
  54. package/studio/web/pages/VideoPage/components/ScheduledInfo.tsx +2 -1
  55. package/studio/web/pages/VideoPage/components/SoundTimeline/AddSound.tsx +12 -14
  56. package/studio/web/pages/VideoPage/components/SoundTimeline/BedRow.tsx +27 -11
  57. package/studio/web/pages/VideoPage/components/SoundTimeline/CaptionSaveBar.tsx +22 -18
  58. package/studio/web/pages/VideoPage/components/SoundTimeline/TimelineFooter.tsx +3 -4
  59. package/studio/web/pages/VideoPage/components/SoundTimeline/UploadTrack.tsx +59 -0
  60. package/studio/web/pages/VideoPage/components/SoundTimeline/useSoundTimeline.ts +1 -0
  61. package/studio/web/pages/VideoPage/components/VoicePauseBanner.tsx +4 -6
  62. package/studio/web/pages/VideoPage/index.tsx +4 -0
  63. package/studio/web/pages/VideosPage/components/VideoRow.tsx +2 -4
  64. package/studio/web/router.tsx +8 -0
  65. package/studio/web/styles/components/bencho/action-node.css +227 -0
  66. package/studio/web/styles/components/bencho/checklist.css +182 -0
  67. package/studio/web/styles/components/bencho/dock.css +188 -0
  68. package/studio/web/styles/components/bencho/gallery.css +109 -0
  69. package/studio/web/styles/components/bencho/generate.css +151 -0
  70. package/studio/web/styles/components/bencho/image-accordion.css +37 -0
  71. package/studio/web/styles/components/bencho/liq-create.css +279 -0
  72. package/studio/web/styles/components/bencho/liq-toggle.css +106 -0
  73. package/studio/web/styles/components/bencho/one-time-code.css +148 -0
  74. package/studio/web/styles/components/bencho/picker.css +204 -0
  75. package/studio/web/styles/components/bencho/pull.css +313 -0
  76. package/studio/web/styles/components/bencho/scope.css +42 -0
  77. package/studio/web/styles/components/bencho/slide-confirm.css +139 -0
  78. package/studio/web/styles/components/bencho/slosh.css +137 -0
  79. package/studio/web/styles/components/bencho/sound.css +260 -0
  80. package/studio/web/styles/components/bencho/stacked-bars.css +334 -0
  81. package/studio/web/styles/components/bencho/toast-stack.css +192 -0
  82. package/studio/web/styles/components/bencho/tokens.css +243 -0
  83. package/studio/web/styles/components/bencho/upload-dropzone.css +352 -0
  84. package/studio/web/styles/components/bencho/voice-note.css +337 -0
  85. package/studio/web/styles/components/clone-voice.css +12 -2
  86. package/studio/web/styles/components/omni.css +6 -1
  87. package/studio/web/styles/components/stepper.css +123 -7
  88. package/studio/web/styles/components/toaster.css +10 -0
  89. package/studio/web/styles/components/ui/slider.css +6 -16
  90. package/studio/web/styles/components/ui/switch.css +2 -41
  91. package/studio/web/styles/components/voice-carousel.css +46 -4
  92. package/studio/web/styles/index.css +23 -0
  93. package/studio/web/styles/pages/video/layout.css +1 -4
  94. package/studio/web/styles/pages/video/sound-timeline.css +8 -0
  95. package/studio/web/styles/theme/identity/shell.css +10 -26
  96. package/tools/sound.mjs +67 -3
@@ -0,0 +1,243 @@
1
+ /* Bencho's own palette, kept as it is on bencho.dev so the ported components keep their colors until the owner decides
2
+ whether the studio's tokens replace them. Two scopes:
3
+ - .bencho: the /bencho gallery page; `data-theme` picks the page palette, `data-fill` on a stage the card color
4
+ every component draws with (--fill-slab / --fill-on); `data-surface="glass"` adds the glass tokens.
5
+ - .bn-scope: wraps one ported component inside a real studio screen. It carries the light palette with a white fill
6
+ and follows the system theme (the studio reads prefers-color-scheme, not a class) for the dark fill.
7
+ Nothing here reaches the rest of the studio, which has its own --ok, --surface-2… */
8
+
9
+ .bencho,
10
+ .bn-scope {
11
+ --glass: 100;
12
+ --wash: 0.06;
13
+ --ink-rgb: 23, 24, 26;
14
+ --surface-rgb: 247, 247, 246;
15
+ --elev-rgb: 255, 255, 255;
16
+ --glass-rgb: 255, 255, 255;
17
+ --shadow-rgb: 23, 24, 26;
18
+ --bg: #fff;
19
+ --surface: #f7f7f6;
20
+ --surface-2: #f1f1f0;
21
+ --surface-3: #ecebe7;
22
+ --board: #fff;
23
+ --canvas-bg: #f7f7f6;
24
+ --pick: #0d99ff;
25
+ --pick-rgb: 13, 153, 255;
26
+ --guide: #ff3b6b;
27
+ --guide-on: #fff;
28
+ --bar-slot: 38px;
29
+ --bar-pad: 6px;
30
+ --bar-gap: 2px;
31
+ --card: #f7f7f6;
32
+ --solid: #0e0f11;
33
+ --solid-ink: #f4f3f1;
34
+ --pill-thumb: #fff;
35
+ --ink: #17181a;
36
+ --ink-2: #3c3b37;
37
+ --ink-3: #5c5b56;
38
+ --ink-4: #6f6e68;
39
+ --ink-5: #85847e;
40
+ --lock: #adaca6;
41
+ --on-ink: #fff;
42
+ --on-ink-rgb: 255, 255, 255;
43
+ --slab: var(--ink);
44
+ --on-slab: var(--on-ink);
45
+ --on-slab-rgb: var(--on-ink-rgb);
46
+ --glass-a: 0.35;
47
+ --glass-edge-a: 0.4;
48
+ --edge-hi: 0.75;
49
+ --edge-lo: 0.18;
50
+ --edge-far: 0.42;
51
+ --slab-dark: #0e0f11;
52
+ --spec-max: 0.35;
53
+ --ring-max: 0.4;
54
+ --lift-max: 0.06;
55
+ --bright-max: 0;
56
+ --pane: rgba(var(--glass-rgb), var(--glass-a));
57
+ --pane-edge: rgba(var(--glass-rgb), var(--glass-edge-a));
58
+ --pane-thumb: #ffffffd1;
59
+ --inlay: #ffffff8c;
60
+ --inlay-hi: #ffffffc7;
61
+ --ok: #15803d;
62
+ --paper: #dcd9cf;
63
+ --paper-2: #e9e7df;
64
+ --rule: #17181a29;
65
+ --signal: #2231dd;
66
+ --ember: #b8431c;
67
+ --font-head: "Google Sans", "Inter Head", var(--font-ui);
68
+ --font-ui:
69
+ "Inter", "Maison Neue", "MaisonNeue-Book", "Instrument Sans", "Helvetica Neue", Helvetica, Arial, sans-serif;
70
+ --font-mono: var(--font-ui);
71
+ --font-num: var(--font-ui);
72
+ --font-code: ui-monospace, "SF Mono", SFMono-Regular, Menlo, Consolas, monospace;
73
+ }
74
+ .bencho {
75
+ color-scheme: light;
76
+ }
77
+ .bencho[data-theme="dark"] {
78
+ color-scheme: dark;
79
+ --ink-rgb: 255, 255, 255;
80
+ --surface-rgb: 15, 15, 15;
81
+ --elev-rgb: 32, 32, 32;
82
+ --glass-rgb: 255, 255, 255;
83
+ --shadow-rgb: 0, 0, 0;
84
+ --bg: #000;
85
+ --surface: #0f0f0f;
86
+ --surface-2: #181818;
87
+ --surface-3: #202020;
88
+ --board: #1a1a1a;
89
+ --canvas-bg: #000;
90
+ --pick: #3aa9ff;
91
+ --guide: #ff5c84;
92
+ --guide-on: #fff;
93
+ --pick-rgb: 58, 169, 255;
94
+ --card: #0a0a0a;
95
+ --solid: #000;
96
+ --solid-ink: #fff;
97
+ --pill-thumb: #ffffff29;
98
+ --ink: #fff;
99
+ --ink-2: #b4b4b4;
100
+ --ink-3: #9a9a9a;
101
+ --ink-4: #828282;
102
+ --ink-5: #6b6b6b;
103
+ --lock: #525252;
104
+ --on-ink: #000;
105
+ --on-ink-rgb: 0, 0, 0;
106
+ --slab: var(--board);
107
+ --on-slab: var(--ink);
108
+ --on-slab-rgb: var(--ink-rgb);
109
+ --glass-a: 0.16;
110
+ --glass-edge-a: 0.2;
111
+ --edge-hi: 0.38;
112
+ --edge-lo: 0.06;
113
+ --edge-far: 0.2;
114
+ --slab-dark: #262626;
115
+ --spec-max: 0.15;
116
+ --ring-max: 0.14;
117
+ --lift-max: 0.5;
118
+ --bright-max: 22;
119
+ --pane-thumb: #ffffff21;
120
+ --inlay: #ffffff12;
121
+ --inlay-hi: #ffffff1f;
122
+ --wash: 0.09;
123
+ --ok: #34d17a;
124
+ }
125
+ .bencho [data-fill="light"],
126
+ .bn-scope {
127
+ --fill-slab: #fff;
128
+ --fill-on: #17181a;
129
+ --fill-on-rgb: 23, 24, 26;
130
+ --ink: #17181a;
131
+ --ink-rgb: 23, 24, 26;
132
+ --ink-2: #3c3b37;
133
+ --ink-3: #5c5b56;
134
+ --ink-4: #6f6e68;
135
+ --ink-5: #85847e;
136
+ --on-ink: #fff;
137
+ --on-ink-rgb: 255, 255, 255;
138
+ --board: #fff;
139
+ --card: #f7f7f6;
140
+ --surface: #f7f7f6;
141
+ --surface-2: #f1f1f0;
142
+ --surface-3: #ecebe7;
143
+ --elev-rgb: 255, 255, 255;
144
+ --glass-rgb: 255, 255, 255;
145
+ --pill-thumb: #fff;
146
+ --inlay: #ffffff8c;
147
+ --slab-btn: #fff;
148
+ }
149
+ .bencho [data-fill="dark"] {
150
+ --fill-slab: var(--slab-dark);
151
+ --fill-on: #fff;
152
+ --fill-on-rgb: 255, 255, 255;
153
+ --ink: #fff;
154
+ --ink-rgb: 255, 255, 255;
155
+ --ink-2: #b4b4b4;
156
+ --ink-3: #9a9a9a;
157
+ --ink-4: #828282;
158
+ --ink-5: #6b6b6b;
159
+ --on-ink: #000;
160
+ --on-ink-rgb: 0, 0, 0;
161
+ --board: #1a1a1a;
162
+ --card: #0a0a0a;
163
+ --surface: #0f0f0f;
164
+ --surface-2: #181818;
165
+ --surface-3: #202020;
166
+ --elev-rgb: 32, 32, 32;
167
+ --glass-rgb: 255, 255, 255;
168
+ --pill-thumb: #ffffff29;
169
+ --inlay: #ffffff1a;
170
+ --slab-btn: var(--slab-dark);
171
+ }
172
+ .bencho [data-surface="glass"],
173
+ .bn-scope {
174
+ --g: calc(var(--glass, 100) * 1%);
175
+ --pane: color-mix(in srgb, rgba(var(--glass-rgb), var(--glass-a)) var(--g), var(--fill-slab, var(--board)));
176
+ --pane-edge: color-mix(in srgb, rgba(var(--glass-rgb), var(--glass-edge-a)) var(--g), rgba(var(--ink-rgb), 0.08));
177
+ --pane-thumb: color-mix(in srgb, #ffffffd1 var(--g), rgba(var(--ink-rgb), 0.07));
178
+ --inlay: color-mix(in srgb, #ffffff8c var(--g), rgba(var(--ink-rgb), 0.05));
179
+ --inlay-hi: color-mix(in srgb, #ffffffc7 var(--g), rgba(var(--ink-rgb), 0.09));
180
+ --k: calc(var(--glass, 100) / 100);
181
+ --g-blur: calc(var(--glass, 100) * 0.25px);
182
+ --g-sat: calc(100% + var(--glass, 100) * 0.9%);
183
+ --g-bright: calc(100% + var(--bright-max) * var(--glass, 100) * 0.01%);
184
+ --g-spec: calc(var(--spec-max) * var(--k));
185
+ --g-ring: calc(var(--ring-max) * var(--k));
186
+ --g-lift: calc(var(--lift-max) * var(--k));
187
+ --g-edge-hi: calc(var(--edge-hi) * var(--k));
188
+ --g-edge-lo: calc(var(--edge-lo) * var(--k));
189
+ --g-edge-far: calc(var(--edge-far) * var(--k));
190
+ }
191
+ @media (prefers-color-scheme: dark) {
192
+ .bn-scope {
193
+ --surface-rgb: 15, 15, 15;
194
+ --shadow-rgb: 0, 0, 0;
195
+ --bg: #000;
196
+ --canvas-bg: #000;
197
+ --pick: #3aa9ff;
198
+ --guide: #ff5c84;
199
+ --guide-on: #fff;
200
+ --pick-rgb: 58, 169, 255;
201
+ --solid: #000;
202
+ --solid-ink: #fff;
203
+ --lock: #525252;
204
+ --slab: var(--board);
205
+ --on-slab: var(--ink);
206
+ --on-slab-rgb: var(--ink-rgb);
207
+ --glass-a: 0.16;
208
+ --glass-edge-a: 0.2;
209
+ --edge-hi: 0.38;
210
+ --edge-lo: 0.06;
211
+ --edge-far: 0.2;
212
+ --slab-dark: #262626;
213
+ --spec-max: 0.15;
214
+ --ring-max: 0.14;
215
+ --lift-max: 0.5;
216
+ --bright-max: 22;
217
+ --pane-thumb: #ffffff21;
218
+ --inlay-hi: #ffffff1f;
219
+ --wash: 0.09;
220
+ --ok: #34d17a;
221
+ --fill-slab: var(--slab-dark);
222
+ --fill-on: #fff;
223
+ --fill-on-rgb: 255, 255, 255;
224
+ --ink: #fff;
225
+ --ink-rgb: 255, 255, 255;
226
+ --ink-2: #b4b4b4;
227
+ --ink-3: #9a9a9a;
228
+ --ink-4: #828282;
229
+ --ink-5: #6b6b6b;
230
+ --on-ink: #000;
231
+ --on-ink-rgb: 0, 0, 0;
232
+ --board: #1a1a1a;
233
+ --card: #0a0a0a;
234
+ --surface: #0f0f0f;
235
+ --surface-2: #181818;
236
+ --surface-3: #202020;
237
+ --elev-rgb: 32, 32, 32;
238
+ --glass-rgb: 255, 255, 255;
239
+ --pill-thumb: #ffffff29;
240
+ --inlay: #ffffff1a;
241
+ --slab-btn: var(--slab-dark);
242
+ }
243
+ }
@@ -0,0 +1,352 @@
1
+ /* ══ Upload dropzone ═════════════════════════════════════ */
2
+ .bn-upl {
3
+ display: flex;
4
+ flex-direction: column;
5
+ gap: 12px;
6
+ width: 300px;
7
+ font-family: var(--font-ui);
8
+ color: var(--fill-on, var(--ink));
9
+ user-select: none;
10
+ -webkit-user-select: none;
11
+ }
12
+
13
+ /* a slot of fixed size, so the box can close in round an upload
14
+ without moving anything below it */
15
+ .bn-upl-zone-wrap {
16
+ flex: none;
17
+ display: flex;
18
+ align-items: center;
19
+ justify-content: center;
20
+ height: 176px;
21
+ }
22
+
23
+ .bn-upl-zone {
24
+ position: relative;
25
+ display: flex;
26
+ flex-direction: column;
27
+ align-items: center;
28
+ justify-content: center;
29
+ gap: 12px;
30
+ width: 100%;
31
+ /* 176, up from 128: the drop target is the block, and a short
32
+ one read as a banner rather than a place to put something */
33
+ height: 176px;
34
+ padding: 0 16px;
35
+ overflow: hidden;
36
+ border-radius: var(--upl-r);
37
+ background: var(--fill-slab, var(--card));
38
+ /* a file over it and it grows, with a bounce; an upload and it
39
+ closes in round it */
40
+ transition:
41
+ scale 420ms cubic-bezier(0.24, 1.34, 0.38, 1),
42
+ width 420ms cubic-bezier(0.24, 1.34, 0.38, 1),
43
+ height 420ms cubic-bezier(0.24, 1.34, 0.38, 1),
44
+ background-color 220ms ease;
45
+ }
46
+
47
+ .bn-upl-zone[data-over] {
48
+ scale: 1.02;
49
+ }
50
+
51
+ /* the gulp: in a little as the file goes down, out past its size,
52
+ and settle */
53
+ .bn-upl-zone[data-gulp] {
54
+ animation: bn-upl-gulp 460ms cubic-bezier(0.3, 1.2, 0.4, 1);
55
+ }
56
+
57
+ .bn-upl-zone[data-gulp] .bn-upl-icon {
58
+ animation: bn-upl-open 460ms cubic-bezier(0.3, 1.4, 0.4, 1);
59
+ }
60
+
61
+ [data-stroke="on"] .bn-upl-zone {
62
+ box-shadow: 0 0 0 1px var(--pane-edge);
63
+ }
64
+
65
+ .bn-upl-icon {
66
+ display: grid;
67
+ place-items: center;
68
+ width: 38px;
69
+ height: 38px;
70
+ border-radius: 10px;
71
+ /* a light grey tile, no edge — the fill's own ink walked most
72
+ of the way to its slab, so it is a pale grey on the light fill
73
+ and a lifted grey on the dark one */
74
+ background: color-mix(in srgb, var(--fill-on, #17181a) 6%, var(--fill-slab, #ffffff));
75
+ color: color-mix(in srgb, var(--fill-on, #17181a) 72%, var(--fill-slab, #ffffff));
76
+ transition:
77
+ translate 420ms cubic-bezier(0.24, 1.34, 0.38, 1),
78
+ background-color 220ms ease,
79
+ color 220ms ease;
80
+ }
81
+
82
+ /* over the box the tile only lifts, and its arrow goes to full
83
+ ink — no colour of its own */
84
+ .bn-upl-zone[data-over] .bn-upl-icon {
85
+ translate: 0 -4px;
86
+ color: var(--fill-on, var(--ink));
87
+ }
88
+
89
+ .bn-upl-say {
90
+ display: flex;
91
+ flex-direction: column;
92
+ align-items: center;
93
+ gap: 4px;
94
+ font-size: 13px;
95
+ text-align: center;
96
+ letter-spacing: 0em;
97
+ }
98
+
99
+ .bn-upl-say b {
100
+ font-weight: 500;
101
+ }
102
+
103
+ .bn-upl-say span {
104
+ font-size: 12px;
105
+ color: color-mix(in srgb, var(--fill-on, #17181a) 52%, var(--fill-slab, #ffffff));
106
+ letter-spacing: 0em;
107
+ }
108
+
109
+ .bn-upl-zone[data-refuse] .bn-upl-say b {
110
+ color: #e5484d;
111
+ }
112
+
113
+ /* the file, arrived in the box */
114
+ .bn-upl-now {
115
+ display: flex;
116
+ align-items: center;
117
+ gap: 12px;
118
+ width: max-content;
119
+ flex: none;
120
+ animation: bn-upl-land 420ms var(--upl-spring) both;
121
+ }
122
+
123
+ .bn-upl-text {
124
+ display: flex;
125
+ flex-direction: column;
126
+ gap: 4px;
127
+ width: 150px;
128
+ }
129
+
130
+ .bn-upl-name {
131
+ overflow: hidden;
132
+ font-size: 13px;
133
+ font-weight: 500;
134
+ white-space: nowrap;
135
+ text-overflow: ellipsis;
136
+ letter-spacing: 0em;
137
+ }
138
+
139
+ .bn-upl-meta {
140
+ display: flex;
141
+ align-items: center;
142
+ gap: 4px;
143
+ height: 14px;
144
+ font-size: 12px;
145
+ font-variant-numeric: tabular-nums;
146
+ color: color-mix(in srgb, var(--fill-on, #17181a) 52%, var(--fill-slab, #ffffff));
147
+ letter-spacing: 0em;
148
+ }
149
+
150
+ .bn-upl-track {
151
+ position: relative;
152
+ height: 4px;
153
+ margin-top: 4px;
154
+ overflow: hidden;
155
+ border-radius: 2px;
156
+ background: color-mix(in srgb, var(--fill-on, #17181a) 6%, var(--fill-slab, #ffffff));
157
+ }
158
+
159
+ .bn-upl-bar {
160
+ position: absolute;
161
+ inset: 0;
162
+ border-radius: inherit;
163
+ background: var(--signal, #2231dd);
164
+ transform-origin: left center;
165
+ }
166
+
167
+ .bn-upl-roll {
168
+ display: inline-flex;
169
+ line-height: 1em;
170
+ height: 1em;
171
+ overflow: hidden;
172
+ }
173
+
174
+ .bn-upl-roll-col {
175
+ display: inline-block;
176
+ height: 1em;
177
+ overflow: hidden;
178
+ }
179
+
180
+ .bn-upl-roll-strip {
181
+ display: flex;
182
+ flex-direction: column;
183
+ transition: transform 220ms cubic-bezier(0.24, 1.34, 0.38, 1);
184
+ }
185
+
186
+ .bn-upl-roll-strip > span {
187
+ height: 1em;
188
+ }
189
+
190
+ .bn-upl-end {
191
+ display: grid;
192
+ place-items: center;
193
+ flex: none;
194
+ width: 22px;
195
+ height: 22px;
196
+ }
197
+
198
+ .bn-upl-tick {
199
+ display: grid;
200
+ place-items: center;
201
+ flex: none;
202
+ width: 22px;
203
+ height: 22px;
204
+ border-radius: 50%;
205
+ background: var(--ok, #15803d);
206
+ color: #fff;
207
+ animation: bn-upl-pop 380ms cubic-bezier(0.3, 1.6, 0.4, 1) both;
208
+ }
209
+
210
+ /* the tray: three files lying under the box */
211
+ .bn-upl-tray {
212
+ display: flex;
213
+ justify-content: center;
214
+ gap: 20px;
215
+ }
216
+
217
+ .bn-upl-slot {
218
+ position: relative;
219
+ width: 76px;
220
+ height: 75px;
221
+ }
222
+
223
+ .bn-upl-file {
224
+ position: relative;
225
+ z-index: 1;
226
+ display: flex;
227
+ flex-direction: column;
228
+ align-items: center;
229
+ gap: 8px;
230
+ padding-top: 4px;
231
+ cursor: grab;
232
+ touch-action: none;
233
+ outline: none;
234
+ /* home is a spring; the Bounce knob sets its overshoot */
235
+ transition:
236
+ transform 420ms var(--upl-spring),
237
+ opacity 220ms ease;
238
+ }
239
+
240
+ .bn-upl-file[data-held] {
241
+ z-index: 5;
242
+ cursor: grabbing;
243
+ transition: none;
244
+ }
245
+
246
+ .bn-upl-file[data-gone] {
247
+ opacity: 0;
248
+ pointer-events: none;
249
+ transition: none;
250
+ }
251
+
252
+ .bn-upl-file:not([data-gone]) {
253
+ animation: bn-upl-back 360ms var(--upl-spring) both;
254
+ }
255
+
256
+ .bn-upl-file:focus-visible .bn-upl-page {
257
+ outline: 2px solid var(--signal, #2231dd);
258
+ outline-offset: 3px;
259
+ border-radius: 6px;
260
+ }
261
+
262
+ .bn-upl-page {
263
+ overflow: visible;
264
+ }
265
+
266
+ .bn-upl-page-line {
267
+ stroke: color-mix(in srgb, var(--fill-on, #17181a) 32%, var(--fill-slab, #ffffff));
268
+ stroke-width: 1.5;
269
+ /* outline only: the page is drawn, not filled */
270
+ fill: none;
271
+ }
272
+
273
+ .bn-upl-page-ext {
274
+ fill: #fff;
275
+ font-family: var(--font-ui);
276
+ /* size is the <text>'s own fontSize, in the icon's units */
277
+ font-weight: 500;
278
+ letter-spacing: 0em;
279
+ }
280
+
281
+ .bn-upl-label {
282
+ max-width: 76px;
283
+ overflow: hidden;
284
+ font-size: 11px;
285
+ white-space: nowrap;
286
+ text-overflow: ellipsis;
287
+ color: color-mix(in srgb, var(--fill-on, #17181a) 72%, var(--fill-slab, #ffffff));
288
+ letter-spacing: 0em;
289
+ }
290
+
291
+ /* the tray sits on the STAGE, not on the block, so when Fill
292
+ takes the block the other way from the page its names would be
293
+ coloured for the wrong ground — light grey on a light stage.
294
+ Across that split they take the page's own ink instead. */
295
+ /* the page's outline goes with its name, the same colour */
296
+ :root:not([data-theme="dark"]) [data-fill="dark"] .bn-upl-label {
297
+ color: color-mix(in srgb, var(--fill-on, var(--ink)) 70%, #ffffff);
298
+ }
299
+
300
+ :root:not([data-theme="dark"]) [data-fill="dark"] .bn-upl-page-line {
301
+ stroke: color-mix(in srgb, var(--fill-on, var(--ink)) 70%, #ffffff);
302
+ }
303
+
304
+ :root[data-theme="dark"] [data-fill="light"] .bn-upl-label {
305
+ color: color-mix(in srgb, #f4f3f1 70%, var(--fill-on, var(--ink)));
306
+ }
307
+
308
+ :root[data-theme="dark"] [data-fill="light"] .bn-upl-page-line {
309
+ stroke: color-mix(in srgb, #f4f3f1 70%, var(--fill-on, var(--ink)));
310
+ }
311
+
312
+ @keyframes bn-upl-gulp {
313
+ 0% {
314
+ scale: 1.02;
315
+ }
316
+ 35% {
317
+ scale: 0.985;
318
+ }
319
+ 70% {
320
+ scale: 1.006;
321
+ }
322
+ 100% {
323
+ scale: 1;
324
+ }
325
+ }
326
+
327
+ @keyframes bn-upl-open {
328
+ 40% {
329
+ scale: 1.08;
330
+ }
331
+ }
332
+
333
+ @keyframes bn-upl-land {
334
+ from {
335
+ opacity: 0;
336
+ scale: 0.85;
337
+ translate: 0 10px;
338
+ }
339
+ }
340
+
341
+ @keyframes bn-upl-pop {
342
+ from {
343
+ scale: 0;
344
+ }
345
+ }
346
+
347
+ @keyframes bn-upl-back {
348
+ from {
349
+ scale: 0.7;
350
+ opacity: 0;
351
+ }
352
+ }