@dumiflex/wp-kit 0.5.0 → 0.7.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 (89) hide show
  1. package/CHANGELOG.md +47 -0
  2. package/README.md +5 -0
  3. package/package.json +4 -3
  4. package/src/Avatar.vue +1 -1
  5. package/src/Banner.vue +4 -4
  6. package/src/BundlePreview.vue +254 -0
  7. package/src/Button.vue +73 -44
  8. package/src/Checkbox.vue +201 -63
  9. package/src/Chip.vue +5 -2
  10. package/src/CodeBlock.vue +1 -1
  11. package/src/ColorField.vue +60 -6
  12. package/src/CombinePreview.vue +150 -0
  13. package/src/Combobox.vue +10 -14
  14. package/src/ConfirmModal.vue +12 -22
  15. package/src/ConstraintMatrixPreview.vue +6 -22
  16. package/src/ConstraintPreview.vue +259 -0
  17. package/src/ContextMenu.vue +11 -30
  18. package/src/CopyButton.vue +1 -1
  19. package/src/DataTable.vue +0 -2
  20. package/src/DatePicker.vue +1 -1
  21. package/src/DerivationCondition.vue +68 -0
  22. package/src/DerivationPreview.vue +345 -0
  23. package/src/Disclosure.vue +2 -1
  24. package/src/Drawer.vue +2 -2
  25. package/src/DropZone.vue +2 -2
  26. package/src/FixedValuesPreview.vue +184 -0
  27. package/src/HsvPicker.vue +2 -2
  28. package/src/IconPicker.vue +32 -103
  29. package/src/IconPickerPanel.vue +132 -0
  30. package/src/ImageGrid.vue +2 -2
  31. package/src/Lightbox.vue +2 -2
  32. package/src/LoadingMark.vue +6 -61
  33. package/src/Modal.vue +109 -44
  34. package/src/ModalShell.vue +26 -5
  35. package/src/Pagination.vue +4 -4
  36. package/src/PayloadPreview.vue +154 -0
  37. package/src/Popover.vue +68 -12
  38. package/src/PostDetailSkeleton.vue +65 -0
  39. package/src/PostGridSkeleton.vue +61 -0
  40. package/src/PreviewGroup.vue +75 -0
  41. package/src/ProfileSkeleton.vue +73 -0
  42. package/src/RadioGroup.vue +5 -4
  43. package/src/RichText.vue +61 -0
  44. package/src/SearchInput.vue +1 -1
  45. package/src/Select.vue +53 -158
  46. package/src/SelectionBar.vue +90 -0
  47. package/src/SettingGroup.vue +57 -0
  48. package/src/SettingRow.vue +127 -0
  49. package/src/Skeleton.vue +1 -1
  50. package/src/Slider.vue +166 -55
  51. package/src/SortableList.vue +1 -1
  52. package/src/TagInput.vue +1 -1
  53. package/src/Timeline.vue +2 -2
  54. package/src/WildcardPreview.vue +607 -0
  55. package/src/WorkingLine.vue +234 -0
  56. package/src/WpIconButton.vue +3 -2
  57. package/src/WpImageZoom.vue +7 -7
  58. package/src/WpSegmented.vue +3 -1
  59. package/src/WpSwitch.vue +1 -1
  60. package/src/WpTabs.vue +1 -1
  61. package/src/_modal-motion.css +1 -1
  62. package/src/button.css +8 -6
  63. package/src/canvas-motion.ts +251 -0
  64. package/src/floating.ts +5 -0
  65. package/src/hsv.ts +1 -1
  66. package/src/kind-colour.ts +24 -1
  67. package/src/linkify.ts +142 -0
  68. package/src/loading-mark-motion.ts +12 -155
  69. package/src/matrix-axis.ts +28 -0
  70. package/src/menu.css +51 -0
  71. package/src/motion.css +73 -0
  72. package/src/pi-icons.ts +51 -0
  73. package/src/preview-readers.ts +401 -0
  74. package/src/preview.css +194 -0
  75. package/src/slider-math.ts +45 -1
  76. package/src/theme/looks.css +6 -19
  77. package/src/theme/tokens.css +12 -1108
  78. package/src/tokens.ts +15 -4
  79. package/src/tooltip.css +8 -5
  80. package/src/useDialogFocus.ts +11 -2
  81. package/src/working-line-motion.ts +135 -0
  82. package/src/CloseButton.vue +0 -69
  83. package/src/ColorPicker.vue +0 -201
  84. package/src/ConfirmDialog.vue +0 -165
  85. package/src/RangeSlider.vue +0 -183
  86. package/src/Toggle.vue +0 -36
  87. package/src/WpButton.vue +0 -75
  88. package/src/WpCheck.vue +0 -104
  89. package/src/_skeleton.css +0 -50
@@ -0,0 +1,607 @@
1
+ <script setup lang="ts">
2
+ /**
3
+ * Wildcard preview built for big pools: a stats strip, search + filters,
4
+ * tag facets with counts, and options as table rows (chance, tags,
5
+ * negative) grouped by one axis at a time. Groups past the first two start
6
+ * closed and each open group shows a page of rows behind "Show N more", so
7
+ * a 200-option wildcard stays a screen or two tall.
8
+ */
9
+ import { computed, ref } from "vue";
10
+ import TokenizedValue from "./TokenizedValue.vue";
11
+ import {
12
+ scanText,
13
+ wildcardAxes,
14
+ wildcardOptions,
15
+ type Obj,
16
+ type WildcardOption,
17
+ } from "./preview-readers";
18
+ import WpSegmented, { type SegmentedOption } from "./WpSegmented.vue";
19
+ import SearchInput from "./SearchInput.vue";
20
+ import Button from "./Button.vue";
21
+ import ListRow from "./ListRow.vue";
22
+ import Chip from "./Chip.vue";
23
+ import PreviewGroup from "./PreviewGroup.vue";
24
+
25
+ const props = defineProps<{
26
+ inner: Obj | null;
27
+ refMap: ReadonlyMap<string, string>;
28
+ }>();
29
+
30
+ const OPEN_GROUPS = 2;
31
+ const PAGE = 8;
32
+ const LONG_CHARS = 90;
33
+ const FACET_PAGE = 6;
34
+
35
+ const options = computed(() => wildcardOptions(props.inner));
36
+ const axes = computed(() => wildcardAxes(props.inner));
37
+ const totalWeight = computed(() =>
38
+ options.value.reduce((n, o) => n + Math.max(0, o.weight), 0),
39
+ );
40
+ const maxWeight = computed(() => Math.max(0, ...options.value.map((o) => o.weight)));
41
+ const refCount = computed(() => {
42
+ let n = 0;
43
+ for (const o of options.value) {
44
+ const s = scanText(o.value);
45
+ if (s.refs || s.picks) n++;
46
+ }
47
+ return n;
48
+ });
49
+ const negCount = computed(() => options.value.filter((o) => o.negative).length);
50
+ const weighted = computed(() => options.value.some((o) => o.weight !== 1));
51
+ const tagTotal = computed(() => new Set(axes.value.flatMap((a) => a.tags)).size);
52
+ const weightRange = computed(() => {
53
+ const ws = options.value.map((o) => o.weight);
54
+ const lo = Math.min(...ws);
55
+ const hi = Math.max(...ws);
56
+ return lo === hi ? null : `${fmt(lo)}–${fmt(hi)}×`;
57
+ });
58
+ function fmt(n: number): string {
59
+ return Number.isInteger(n) ? String(n) : n.toFixed(2).replace(/\.?0+$/, "");
60
+ }
61
+
62
+ // ─── filters ───
63
+ const search = ref("");
64
+ const onlyNeg = ref(false);
65
+ const onlyWeighted = ref(false);
66
+ const onlyRefs = ref(false);
67
+ /** Selected facet tags per axis. OR within an axis, AND across axes. */
68
+ const picked = ref<Record<string, string[]>>({});
69
+ function togglePick(axis: string, tag: string): void {
70
+ const cur = picked.value[axis] ?? [];
71
+ const next = cur.includes(tag) ? cur.filter((t) => t !== tag) : [...cur, tag];
72
+ picked.value = { ...picked.value, [axis]: next };
73
+ }
74
+ function isPicked(axis: string, tag: string): boolean {
75
+ return (picked.value[axis] ?? []).includes(tag);
76
+ }
77
+ const pickCount = computed(() =>
78
+ Object.values(picked.value).reduce((n, t) => n + t.length, 0),
79
+ );
80
+ const filtering = computed(
81
+ () =>
82
+ search.value.trim() !== "" ||
83
+ onlyNeg.value ||
84
+ onlyWeighted.value ||
85
+ onlyRefs.value ||
86
+ pickCount.value > 0,
87
+ );
88
+ function clearFilters(): void {
89
+ search.value = "";
90
+ onlyNeg.value = false;
91
+ onlyWeighted.value = false;
92
+ onlyRefs.value = false;
93
+ picked.value = {};
94
+ }
95
+ function passes(o: WildcardOption): boolean {
96
+ const q = search.value.trim().toLowerCase();
97
+ if (
98
+ q &&
99
+ !o.value.toLowerCase().includes(q) &&
100
+ !o.negative.toLowerCase().includes(q) &&
101
+ !o.tags.some((t) => t.toLowerCase().includes(q))
102
+ )
103
+ return false;
104
+ if (onlyNeg.value && !o.negative) return false;
105
+ if (onlyWeighted.value && o.weight === 1) return false;
106
+ if (onlyRefs.value) {
107
+ const s = scanText(o.value);
108
+ if (!s.refs && !s.picks) return false;
109
+ }
110
+ for (const tags of Object.values(picked.value)) {
111
+ if (tags.length && !o.tags.some((t) => tags.includes(t))) return false;
112
+ }
113
+ return true;
114
+ }
115
+ const visible = computed(() => options.value.filter(passes));
116
+
117
+ // ─── facets ───
118
+ const facetOpen = ref(new Set<string>());
119
+ function facetTags(axis: { name: string; tags: string[] }): { tag: string; count: number }[] {
120
+ return axis.tags
121
+ .map((tag) => ({ tag, count: options.value.filter((o) => o.tags.includes(tag)).length }))
122
+ .filter((f) => f.count > 0);
123
+ }
124
+ function shownFacets(axis: { name: string; tags: string[] }): { tag: string; count: number }[] {
125
+ const all = facetTags(axis);
126
+ return facetOpen.value.has(axis.name) ? all : all.slice(0, FACET_PAGE);
127
+ }
128
+ function toggleFacetMore(name: string): void {
129
+ const next = new Set(facetOpen.value);
130
+ if (next.has(name)) next.delete(name);
131
+ else next.add(name);
132
+ facetOpen.value = next;
133
+ }
134
+ const showFacets = computed(() => axes.value.length > 0 && options.value.length >= 20);
135
+
136
+ // ─── grouping ───
137
+ const groupBy = ref<string>("");
138
+ const groupOptions = computed<SegmentedOption[]>(() => [
139
+ ...axes.value.map((a) => ({ value: a.name, label: a.name })),
140
+ { value: "none", label: "none" },
141
+ ]);
142
+ const effectiveAxis = computed(() =>
143
+ groupBy.value === "none" ? null : (axes.value.find((a) => a.name === groupBy.value) ?? axes.value[0] ?? null),
144
+ );
145
+ interface Group {
146
+ name: string;
147
+ options: WildcardOption[];
148
+ }
149
+ const groups = computed<Group[]>(() => {
150
+ const axis = effectiveAxis.value;
151
+ if (!axis) return visible.value.length ? [{ name: "", options: visible.value }] : [];
152
+ const buckets = new Map<string, WildcardOption[]>();
153
+ const untagged: WildcardOption[] = [];
154
+ for (const o of visible.value) {
155
+ // Each option lands ONCE: under the first of its tags this axis lists.
156
+ const tag = axis.tags.find((t) => o.tags.includes(t));
157
+ if (tag === undefined) untagged.push(o);
158
+ else buckets.set(tag, [...(buckets.get(tag) ?? []), o]);
159
+ }
160
+ const out: Group[] = [];
161
+ for (const tag of axis.tags) {
162
+ const opts = buckets.get(tag);
163
+ if (opts?.length) out.push({ name: tag, options: opts });
164
+ }
165
+ if (untagged.length) out.push({ name: "(untagged)", options: untagged });
166
+ return out;
167
+ });
168
+
169
+ /** Toggled groups flip their default (open for the first few; every group
170
+ * opens while a filter is on). */
171
+ const toggled = ref(new Set<string>());
172
+ function flip(set: Set<string>, key: string): Set<string> {
173
+ const next = new Set(set);
174
+ if (next.has(key)) next.delete(key);
175
+ else next.add(key);
176
+ return next;
177
+ }
178
+ function isOpen(name: string, index: number): boolean {
179
+ if (!name) return true;
180
+ const byDefault = filtering.value || index < OPEN_GROUPS;
181
+ return toggled.value.has(name) ? !byDefault : byDefault;
182
+ }
183
+ const fullGroups = ref(new Set<string>());
184
+ function rowsOf(g: Group): WildcardOption[] {
185
+ return fullGroups.value.has(g.name) ? g.options : g.options.slice(0, PAGE);
186
+ }
187
+ function share(g: Group): string {
188
+ if (!totalWeight.value) return "";
189
+ const w = g.options.reduce((n, o) => n + Math.max(0, o.weight), 0);
190
+ return `${pct(w)} of draws`;
191
+ }
192
+ function pct(w: number): string {
193
+ const p = (w / totalWeight.value) * 100;
194
+ if (p > 0 && p < 0.1) return "<0.1%";
195
+ return `${p < 10 ? p.toFixed(1) : p.toFixed(0)}%`;
196
+ }
197
+
198
+ // ─── rows ───
199
+ const view = ref<"list" | "chips">("list");
200
+ const VIEW_OPTIONS: SegmentedOption<"list" | "chips">[] = [
201
+ { value: "list", label: "List" },
202
+ { value: "chips", label: "Chips" },
203
+ ];
204
+ const expanded = ref(new Set<string>());
205
+ function isLong(o: WildcardOption): boolean {
206
+ return o.value.length > LONG_CHARS;
207
+ }
208
+ </script>
209
+
210
+ <template>
211
+ <div class="wp-pv wp-wc">
212
+ <div class="wp-pv-stats">
213
+ <div class="wp-pv-stat">
214
+ <b>{{ options.length }}</b><span>option{{ options.length === 1 ? "" : "s" }}</span>
215
+ </div>
216
+ <div
217
+ v-if="axes.length"
218
+ class="wp-pv-stat"
219
+ >
220
+ <b>{{ axes.length }}</b><span>tag ax{{ axes.length === 1 ? "is" : "es" }} · {{ tagTotal }} tags</span>
221
+ </div>
222
+ <div
223
+ v-if="negCount"
224
+ class="wp-pv-stat"
225
+ >
226
+ <b>{{ negCount }}</b><span>with a negative</span>
227
+ </div>
228
+ <div
229
+ v-if="weightRange"
230
+ class="wp-pv-stat"
231
+ >
232
+ <b>{{ weightRange }}</b><span>weight range</span>
233
+ </div>
234
+ <div
235
+ v-if="refCount"
236
+ class="wp-pv-stat"
237
+ >
238
+ <b>{{ refCount }}</b><span>use picks / @refs</span>
239
+ </div>
240
+ </div>
241
+
242
+ <div class="wp-pv-tool">
243
+ <SearchInput
244
+ v-if="options.length > 8"
245
+ v-model="search"
246
+ :placeholder="`Filter ${options.length} options…`"
247
+ data-test="wildcard-search"
248
+ class="wp-pv-search"
249
+ />
250
+ <template v-if="axes.length">
251
+ <span class="wp-pv-label">Group by</span>
252
+ <WpSegmented
253
+ :model-value="effectiveAxis?.name ?? 'none'"
254
+ :options="groupOptions"
255
+ size="sm"
256
+ aria-label="Group by"
257
+ test-prefix="groupby"
258
+ @update:model-value="(v) => (groupBy = v)"
259
+ />
260
+ </template>
261
+ <Chip
262
+ v-if="negCount"
263
+ size="sm"
264
+ color="var(--wp-danger)"
265
+ :pressed="onlyNeg"
266
+ data-test="filter-negative"
267
+ @click="onlyNeg = !onlyNeg"
268
+ >Has negative</Chip>
269
+ <Chip
270
+ v-if="weighted"
271
+ size="sm"
272
+ :pressed="onlyWeighted"
273
+ @click="onlyWeighted = !onlyWeighted"
274
+ >Weighted</Chip>
275
+ <Chip
276
+ v-if="refCount"
277
+ size="sm"
278
+ :pressed="onlyRefs"
279
+ @click="onlyRefs = !onlyRefs"
280
+ >Uses picks / refs</Chip>
281
+ <span
282
+ v-if="filtering"
283
+ class="wp-pv-count"
284
+ data-test="wildcard-matches"
285
+ >
286
+ {{ visible.length }} of {{ options.length }}
287
+ <Button
288
+ variant="link"
289
+ size="sm"
290
+ @click="clearFilters"
291
+ >clear</Button>
292
+ </span>
293
+ <WpSegmented
294
+ v-model="view"
295
+ class="wp-pv-tool__end"
296
+ :options="VIEW_OPTIONS"
297
+ size="sm"
298
+ aria-label="Show as"
299
+ test-prefix="view"
300
+ />
301
+ </div>
302
+
303
+ <div
304
+ class="wp-wc__split"
305
+ :data-facets="showFacets || null"
306
+ >
307
+ <aside
308
+ v-if="showFacets"
309
+ class="wp-wc__facets wp-pv-hide-narrow"
310
+ >
311
+ <div
312
+ v-for="a in axes"
313
+ :key="a.name"
314
+ class="wp-wc__facet"
315
+ >
316
+ <h5>{{ a.name }}</h5>
317
+ <ListRow
318
+ v-for="f in shownFacets(a)"
319
+ :key="f.tag"
320
+ size="sm"
321
+ toggle
322
+ class="wp-wc__facet-row"
323
+ :selected="isPicked(a.name, f.tag)"
324
+ :count="f.count"
325
+ :data-test="`facet-${f.tag}`"
326
+ @click="togglePick(a.name, f.tag)"
327
+ >
328
+ {{ f.tag }}
329
+ </ListRow>
330
+ <Button
331
+ v-if="facetTags(a).length > FACET_PAGE"
332
+ variant="link"
333
+ size="sm"
334
+ class="wp-wc__facet-more"
335
+ @click="toggleFacetMore(a.name)"
336
+ >
337
+ {{ facetOpen.has(a.name) ? "fewer" : `+ ${facetTags(a).length - FACET_PAGE} more` }}
338
+ </Button>
339
+ </div>
340
+ </aside>
341
+
342
+ <div class="wp-wildcard-groups">
343
+ <p
344
+ v-if="!groups.length"
345
+ class="wp-pv-empty"
346
+ >
347
+ No options match these filters.
348
+ </p>
349
+ <PreviewGroup
350
+ v-for="(g, gidx) in groups"
351
+ :key="g.name || '_'"
352
+ class="wp-wildcard-group"
353
+ :name="g.name"
354
+ :open="isOpen(g.name, gidx)"
355
+ :count="g.options.length"
356
+ :aside="share(g)"
357
+ :test-id="`group-${g.name}`"
358
+ @update:open="toggled = flip(toggled, g.name)"
359
+ >
360
+ <table
361
+ v-if="view === 'list'"
362
+ class="wp-pv-table"
363
+ >
364
+ <colgroup>
365
+ <col class="wp-pv-col-n">
366
+ <col>
367
+ <col class="wp-wc__col-chance">
368
+ <col
369
+ v-if="axes.length"
370
+ class="wp-pv-hide-narrow"
371
+ style="width: 22%"
372
+ >
373
+ <col
374
+ v-if="negCount"
375
+ style="width: 26%"
376
+ >
377
+ </colgroup>
378
+ <tbody>
379
+ <tr
380
+ v-for="(o, oidx) in rowsOf(g)"
381
+ :key="oidx"
382
+ class="wp-wildcard-option"
383
+ >
384
+ <td class="wp-pv-n">
385
+ {{ oidx + 1 }}
386
+ </td>
387
+ <td>
388
+ <div
389
+ :class="{ 'wp-pv-clamp': isLong(o) && !expanded.has(`${g.name}|${oidx}`) }"
390
+ class="wp-wildcard-option__value"
391
+ :data-long="isLong(o) || null"
392
+ >
393
+ <TokenizedValue
394
+ :value="o.value"
395
+ :uuid-to-name="refMap"
396
+ />
397
+ </div>
398
+ <Button
399
+ v-if="isLong(o)"
400
+ variant="link"
401
+ size="sm"
402
+ @click="expanded = flip(expanded, `${g.name}|${oidx}`)"
403
+ >{{ expanded.has(`${g.name}|${oidx}`) ? "Show less" : "Show all" }}</Button>
404
+ </td>
405
+ <td class="wp-wc__chance">
406
+ <span>{{ totalWeight ? pct(Math.max(0, o.weight)) : "—" }}<template v-if="o.weight !== 1"> · ×{{ fmt(o.weight) }}</template></span>
407
+ <span
408
+ v-if="o.fallback"
409
+ class="wp-pv-fbtag"
410
+ data-test="option-fallback"
411
+ title="Rolls normally, and is also used when nothing else is left to pick."
412
+ >fallback</span>
413
+ <div class="wp-wc__bar">
414
+ <b :style="{ width: `${maxWeight ? (Math.max(0, o.weight) / maxWeight) * 100 : 0}%` }" />
415
+ </div>
416
+ </td>
417
+ <td
418
+ v-if="axes.length"
419
+ class="wp-pv-hide-narrow"
420
+ >
421
+ <span
422
+ v-for="t in o.tags"
423
+ :key="t"
424
+ class="wp-wc__tag"
425
+ >{{ t }}</span>
426
+ </td>
427
+ <td
428
+ v-if="negCount"
429
+ class="wp-pv-neg-cell"
430
+ >
431
+ <span
432
+ v-if="o.negative"
433
+ data-test="option-negative"
434
+ >
435
+ <span class="wp-pv-negtag">NEG</span>
436
+ <TokenizedValue
437
+ :value="o.negative"
438
+ :uuid-to-name="refMap"
439
+ />
440
+ </span>
441
+ </td>
442
+ </tr>
443
+ </tbody>
444
+ </table>
445
+ <ul
446
+ v-else
447
+ class="wp-wc__chips"
448
+ >
449
+ <li
450
+ v-for="(o, oidx) in rowsOf(g)"
451
+ :key="oidx"
452
+ class="wp-wildcard-option"
453
+ :title="o.tags.join(' · ')"
454
+ >
455
+ <span :class="{ 'wp-pv-clamp': isLong(o) }">
456
+ <TokenizedValue
457
+ :value="o.value"
458
+ :uuid-to-name="refMap"
459
+ />
460
+ </span>
461
+ <span
462
+ v-if="o.negative"
463
+ class="wp-wc__chipneg"
464
+ data-test="option-negative"
465
+ >
466
+ <span class="wp-pv-negtag">NEG</span>
467
+ <TokenizedValue
468
+ :value="o.negative"
469
+ :uuid-to-name="refMap"
470
+ />
471
+ </span>
472
+ <span
473
+ v-if="o.fallback"
474
+ class="wp-pv-fbtag"
475
+ data-test="option-fallback"
476
+ title="Rolls normally, and is also used when nothing else is left to pick."
477
+ >fallback</span>
478
+ <span
479
+ v-if="o.weight !== 1"
480
+ class="wp-wc__w"
481
+ >×{{ fmt(o.weight) }}</span>
482
+ </li>
483
+ </ul>
484
+ <div
485
+ v-if="g.options.length > PAGE"
486
+ class="wp-pv-more"
487
+ >
488
+ <Button
489
+ variant="link"
490
+ size="sm"
491
+ :data-test="`more-${g.name || '_'}`"
492
+ @click="fullGroups = flip(fullGroups, g.name)"
493
+ >
494
+ {{
495
+ fullGroups.has(g.name)
496
+ ? "Show fewer"
497
+ : `Show ${g.options.length - PAGE} more${g.name ? ` in ${g.name}` : ""}`
498
+ }}
499
+ </Button>
500
+ </div>
501
+ </PreviewGroup>
502
+ </div>
503
+ </div>
504
+ </div>
505
+ </template>
506
+
507
+ <style scoped src="./preview.css"></style>
508
+ <style scoped>
509
+ .wp-wc__split[data-facets] {
510
+ display: grid;
511
+ grid-template-columns: 190px minmax(0, 1fr);
512
+ }
513
+ @container (max-width: 640px) {
514
+ .wp-wc__split[data-facets] {
515
+ grid-template-columns: minmax(0, 1fr);
516
+ }
517
+ }
518
+ .wp-wc__facets {
519
+ border-right: 1px solid var(--wp-border);
520
+ padding: 6px 0 12px;
521
+ }
522
+ .wp-wc__facet h5 {
523
+ margin: 10px 16px 4px;
524
+ font-size: 10.5px;
525
+ font-weight: 600;
526
+ letter-spacing: 0.06em;
527
+ color: var(--wp-text-dim);
528
+ text-transform: uppercase;
529
+ }
530
+ .wp-wc__facet-more {
531
+ margin: 2px 12px 0;
532
+ }
533
+ .wp-wc__chance span {
534
+ font-family: var(--wp-font-mono);
535
+ font-size: 11px;
536
+ color: var(--wp-text-muted);
537
+ white-space: nowrap;
538
+ }
539
+ .wp-wc__chance .wp-pv-fbtag {
540
+ margin-left: 6px;
541
+ font-size: 10px;
542
+ color: var(--wp-accent-text);
543
+ }
544
+ .wp-wc__col-chance {
545
+ width: 112px;
546
+ }
547
+ @container (max-width: 640px) {
548
+ .wp-wc__col-chance {
549
+ width: 56px;
550
+ }
551
+ .wp-wc__bar {
552
+ display: none;
553
+ }
554
+ }
555
+ .wp-wc__bar {
556
+ height: 4px;
557
+ margin-top: 6px;
558
+ border-radius: min(2px, var(--wp-radius-cap, 999px));
559
+ background: var(--wp-bg-4);
560
+ }
561
+ .wp-wc__bar b {
562
+ display: block;
563
+ height: 4px;
564
+ border-radius: min(2px, var(--wp-radius-cap, 999px));
565
+ background: var(--wp-accent-500);
566
+ }
567
+ .wp-wc__tag {
568
+ display: inline-block;
569
+ margin: 0 3px 3px 0;
570
+ padding: 0 6px;
571
+ border-radius: min(4px, var(--wp-radius-cap, 999px));
572
+ background: var(--wp-bg-3);
573
+ color: var(--wp-text-muted);
574
+ font-size: 10.5px;
575
+ }
576
+ .wp-wc__chips {
577
+ list-style: none;
578
+ margin: 0;
579
+ padding: 10px 16px 12px;
580
+ display: flex;
581
+ flex-wrap: wrap;
582
+ gap: 6px;
583
+ border-bottom: 1px solid var(--wp-border);
584
+ }
585
+ .wp-wc__chips li {
586
+ display: inline-flex;
587
+ align-items: center;
588
+ gap: 6px;
589
+ max-width: 100%;
590
+ padding: 3px 10px;
591
+ border-radius: min(10px, var(--wp-radius-cap, 999px));
592
+ background: var(--wp-bg-3);
593
+ color: var(--wp-text);
594
+ font-size: 13px;
595
+ }
596
+ .wp-wc__chipneg {
597
+ padding-left: 6px;
598
+ border-left: 1px solid var(--wp-border);
599
+ color: var(--wp-danger-text, var(--wp-danger));
600
+ font-size: 12px;
601
+ }
602
+ .wp-wc__w {
603
+ font-family: var(--wp-font-mono);
604
+ font-size: 10.5px;
605
+ color: var(--wp-text-muted);
606
+ }
607
+ </style>