dference 0.1.0__py3-none-any.whl

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.
@@ -0,0 +1,952 @@
1
+ /* dference – quiet table look like marimo.ui.table. Works in light & dark mode
2
+ because surfaces are translucent tints over whatever background surrounds it.
3
+ Colours: Okabe–Ito palette (colour-blind safe). Each side has one colour and one
4
+ chip (its short name); a row on one side only takes the colour of that side. */
5
+ .dfd {
6
+ --dfd-line: rgba(127, 127, 127, 0.24);
7
+ --dfd-soft: rgba(127, 127, 127, 0.07);
8
+ --dfd-muted: rgba(127, 127, 127, 0.95);
9
+ /* every body row is as high as a difference (two values): the table height is
10
+ then header + rows per page × row height and does not jump when filtering */
11
+ --dfd-row-h: 48px;
12
+ --side-l: #0072b2; /* blue – left */
13
+ --side-r: #cc79a7; /* magenta – right */
14
+ --st-equal: #009e73; /* bluish green */
15
+ --st-mismatch: #e69f00; /* amber */
16
+ --st-missing_left: var(--side-r); /* row only in right */
17
+ --st-missing_right: var(--side-l); /* row only in left */
18
+ --dfd-danger: #d55e00; /* vermillion – errors, unrelated to the sides */
19
+ font-family: var(--marimo-text-font, ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif);
20
+ font-size: 13px;
21
+ line-height: 1.4;
22
+ color: inherit;
23
+ display: flex;
24
+ flex-direction: column;
25
+ gap: 10px;
26
+ min-width: 0;
27
+ }
28
+ .dfd * {
29
+ box-sizing: border-box;
30
+ }
31
+ .dfd button {
32
+ font: inherit;
33
+ color: inherit;
34
+ cursor: pointer;
35
+ }
36
+ .dfd code {
37
+ font-family: var(--marimo-monospace-font, ui-monospace, SFMono-Regular, Menlo, monospace);
38
+ font-size: 12px;
39
+ }
40
+ .dfd :focus-visible {
41
+ outline: 2px solid currentColor;
42
+ outline-offset: 1px;
43
+ }
44
+ .dfd-spacer {
45
+ flex: 1;
46
+ }
47
+
48
+ .dfd .st-equal {
49
+ --c: var(--st-equal);
50
+ }
51
+ .dfd .st-mismatch {
52
+ --c: var(--st-mismatch);
53
+ }
54
+ .dfd .st-missing_left {
55
+ --c: var(--st-missing_left);
56
+ }
57
+ .dfd .st-missing_right {
58
+ --c: var(--st-missing_right);
59
+ }
60
+
61
+ /* Status badge: coloured square + symbol, so status never relies on hue alone */
62
+ .dfd-badge {
63
+ display: inline-flex;
64
+ align-items: center;
65
+ justify-content: center;
66
+ min-width: 20px;
67
+ height: 18px;
68
+ padding: 0 3px;
69
+ border-radius: 4px;
70
+ background: var(--c);
71
+ color: #fff;
72
+ font-size: 11px;
73
+ font-weight: 700;
74
+ line-height: 1;
75
+ font-variant-numeric: tabular-nums;
76
+ flex: none;
77
+ }
78
+ .dfd-badge.st-mismatch {
79
+ color: #3b2800;
80
+ }
81
+
82
+ /* ---------- overview ---------- */
83
+ .dfd-overview {
84
+ display: flex;
85
+ flex-direction: column;
86
+ gap: 8px;
87
+ }
88
+ /* Both bars share one scale: no flex gap (it would shift the second bar);
89
+ segments are separated by an inset line drawn in the background colour. */
90
+ .dfd-bars {
91
+ display: flex;
92
+ flex-direction: column;
93
+ gap: 3px;
94
+ }
95
+ .dfd-dist {
96
+ display: flex;
97
+ height: 8px;
98
+ border-radius: 4px;
99
+ overflow: hidden;
100
+ }
101
+ .dfd-dist span {
102
+ background: var(--c);
103
+ transition: opacity 0.15s;
104
+ }
105
+ .dfd-dist span:not(:last-child) {
106
+ box-shadow: inset -2px 0 0 var(--dfd-bg, Canvas);
107
+ }
108
+ .dfd-dist span.off {
109
+ opacity: 0.18;
110
+ }
111
+ .dfd .g-found {
112
+ background: color-mix(in srgb, currentColor 55%, transparent);
113
+ }
114
+ .dfd .g-notfound {
115
+ background: repeating-linear-gradient(
116
+ 135deg,
117
+ color-mix(in srgb, currentColor 55%, transparent) 0 2px,
118
+ color-mix(in srgb, currentColor 18%, transparent) 2px 4px
119
+ );
120
+ }
121
+ .dfd-swatch {
122
+ width: 20px;
123
+ height: 10px;
124
+ border-radius: 3px;
125
+ flex: none;
126
+ }
127
+ .dfd-stats {
128
+ display: flex;
129
+ flex-wrap: wrap;
130
+ gap: 6px 18px;
131
+ }
132
+ .dfd-stat {
133
+ display: inline-flex;
134
+ align-items: center;
135
+ gap: 6px;
136
+ transition: opacity 0.15s;
137
+ }
138
+ .dfd-stat.off {
139
+ opacity: 0.4;
140
+ }
141
+ .dfd-stat b {
142
+ font-variant-numeric: tabular-nums;
143
+ font-weight: 600;
144
+ }
145
+ .dfd-stat small {
146
+ opacity: 0.65;
147
+ font-variant-numeric: tabular-nums;
148
+ }
149
+ .dfd-meta {
150
+ display: flex;
151
+ flex-wrap: wrap;
152
+ gap: 4px 16px;
153
+ color: var(--dfd-muted);
154
+ font-size: 12px;
155
+ }
156
+ .dfd-meta b {
157
+ font-weight: 600;
158
+ }
159
+ .dfd-link {
160
+ border: 0;
161
+ background: none;
162
+ padding: 2px 4px;
163
+ text-decoration: underline;
164
+ text-underline-offset: 2px;
165
+ opacity: 0.8;
166
+ }
167
+
168
+ /* ---------- toolbar ---------- */
169
+ .dfd-toolbar {
170
+ display: flex;
171
+ flex-wrap: wrap;
172
+ align-items: center;
173
+ gap: 8px 14px;
174
+ }
175
+ .dfd-btn {
176
+ display: inline-flex;
177
+ align-items: center;
178
+ gap: 6px;
179
+ height: 30px;
180
+ padding: 0 12px;
181
+ border-radius: 6px;
182
+ border: 1px solid var(--dfd-line);
183
+ background: transparent;
184
+ }
185
+ .dfd-btn:hover {
186
+ background: var(--dfd-soft);
187
+ }
188
+ .dfd-search {
189
+ display: inline-flex;
190
+ align-items: center;
191
+ gap: 6px;
192
+ padding: 0 8px;
193
+ border: 1px solid var(--dfd-line);
194
+ border-radius: 6px;
195
+ height: 30px;
196
+ min-width: 200px;
197
+ }
198
+ .dfd-search svg {
199
+ width: 14px;
200
+ height: 14px;
201
+ fill: none;
202
+ stroke: currentColor;
203
+ stroke-width: 1.5;
204
+ opacity: 0.6;
205
+ }
206
+ .dfd-search input {
207
+ border: 0;
208
+ outline: 0;
209
+ background: transparent;
210
+ color: inherit;
211
+ font: inherit;
212
+ flex: 1;
213
+ min-width: 0;
214
+ }
215
+ .dfd-toggle {
216
+ display: inline-flex;
217
+ align-items: center;
218
+ gap: 6px;
219
+ cursor: pointer;
220
+ }
221
+ .dfd-toolbar-dyn {
222
+ display: inline-flex;
223
+ gap: 6px;
224
+ flex-wrap: wrap;
225
+ }
226
+ .dfd-pillfilter {
227
+ display: inline-flex;
228
+ align-items: center;
229
+ gap: 4px;
230
+ padding: 2px 4px 2px 8px;
231
+ border-radius: 6px;
232
+ background: color-mix(in srgb, var(--st-mismatch) 16%, transparent);
233
+ font-size: 12px;
234
+ }
235
+ .dfd-pillfilter.sel {
236
+ background: var(--dfd-soft);
237
+ border: 1px solid var(--dfd-line);
238
+ }
239
+ .dfd-pillfilter button {
240
+ border: 0;
241
+ background: none;
242
+ padding: 0 4px;
243
+ font-size: 14px;
244
+ line-height: 1;
245
+ opacity: 0.7;
246
+ }
247
+
248
+ /* ---------- status menu (popover of the status column) ---------- */
249
+ .dfd-colmenu.status {
250
+ width: min(340px, 100%);
251
+ }
252
+ .dfd-presets {
253
+ display: flex;
254
+ gap: 4px;
255
+ padding: 2px 2px 6px;
256
+ border-bottom: 1px solid var(--dfd-line);
257
+ margin-bottom: 4px;
258
+ flex-wrap: wrap;
259
+ }
260
+ .dfd-presets button {
261
+ border: 1px solid var(--dfd-line);
262
+ background: transparent;
263
+ border-radius: 5px;
264
+ padding: 2px 8px;
265
+ font-size: 12px;
266
+ }
267
+ .dfd-presets button:hover {
268
+ background: var(--dfd-soft);
269
+ }
270
+ .dfd-opt {
271
+ display: flex;
272
+ align-items: center;
273
+ gap: 8px;
274
+ padding: 6px;
275
+ border-radius: 6px;
276
+ cursor: pointer;
277
+ }
278
+ .dfd-opt:hover {
279
+ background: var(--dfd-soft);
280
+ }
281
+ .dfd-opt-text {
282
+ display: flex;
283
+ flex-direction: column;
284
+ flex: 1;
285
+ min-width: 0;
286
+ }
287
+ .dfd-opt-text small {
288
+ color: var(--dfd-muted);
289
+ font-size: 11px;
290
+ }
291
+ .dfd-opt b {
292
+ font-variant-numeric: tabular-nums;
293
+ font-weight: 600;
294
+ }
295
+ .dfd-only {
296
+ border: 0;
297
+ background: none;
298
+ font-size: 11px;
299
+ padding: 2px 4px;
300
+ opacity: 0;
301
+ text-decoration: underline;
302
+ text-underline-offset: 2px;
303
+ }
304
+ .dfd-opt:hover .dfd-only,
305
+ .dfd-only:focus-visible {
306
+ opacity: 0.8;
307
+ }
308
+ @media (hover: none) {
309
+ .dfd-only {
310
+ opacity: 0.8;
311
+ }
312
+ }
313
+
314
+ /* ---------- table ---------- */
315
+ .dfd-scroll {
316
+ overflow: auto;
317
+ border: 1px solid var(--dfd-line);
318
+ border-radius: 8px;
319
+ }
320
+ .dfd table {
321
+ border-collapse: separate;
322
+ border-spacing: 0;
323
+ width: 100%;
324
+ }
325
+ .dfd-scroll thead th {
326
+ position: sticky;
327
+ top: 0;
328
+ z-index: 1;
329
+ text-align: left;
330
+ vertical-align: top;
331
+ background: var(--dfd-bg, Canvas);
332
+ background-image: linear-gradient(var(--dfd-soft), var(--dfd-soft));
333
+ border-bottom: 1px solid var(--dfd-line);
334
+ padding: 6px 10px;
335
+ font-weight: 500;
336
+ white-space: nowrap;
337
+ }
338
+ .dfd-sort {
339
+ border: 0;
340
+ background: none;
341
+ padding: 0;
342
+ font-weight: 600;
343
+ display: inline-flex;
344
+ gap: 4px;
345
+ }
346
+ .dfd-arrow {
347
+ opacity: 0.7;
348
+ min-width: 0.6em;
349
+ }
350
+ .dfd-colmeta {
351
+ display: flex;
352
+ align-items: center;
353
+ gap: 6px;
354
+ margin-top: 3px;
355
+ font-size: 11px;
356
+ font-weight: 400;
357
+ }
358
+ .dfd-dtype {
359
+ color: var(--dfd-muted);
360
+ font-family: var(--marimo-monospace-font, ui-monospace, monospace);
361
+ }
362
+ .dfd-tag {
363
+ padding: 0 5px;
364
+ border-radius: 4px;
365
+ background: var(--dfd-soft);
366
+ border: 1px solid var(--dfd-line);
367
+ }
368
+ .dfd-muted {
369
+ color: var(--dfd-muted);
370
+ }
371
+ .dfd-delta {
372
+ display: inline-flex;
373
+ align-items: center;
374
+ gap: 5px;
375
+ border: 0;
376
+ background: none;
377
+ padding: 0;
378
+ font-weight: 600;
379
+ font-variant-numeric: tabular-nums;
380
+ }
381
+ .dfd-delta.on {
382
+ text-decoration: underline;
383
+ text-underline-offset: 2px;
384
+ }
385
+ /* "=" reads as the quieter share next to "≠" until it is the active filter */
386
+ .dfd-delta.eq {
387
+ color: var(--dfd-muted);
388
+ font-weight: 400;
389
+ }
390
+ .dfd-delta.eq:hover,
391
+ .dfd-delta.eq.on {
392
+ color: inherit;
393
+ }
394
+
395
+ .dfd-scroll tbody td {
396
+ padding: 5px 10px;
397
+ border-bottom: 1px solid var(--dfd-line);
398
+ white-space: nowrap;
399
+ /* a row with a difference is two lines high: single values sit in the middle */
400
+ vertical-align: middle;
401
+ }
402
+ /* a full page ends on the frame of the scroll box: no second line there */
403
+ .dfd-scroll table.full tbody tr:last-child td {
404
+ border-bottom: 0;
405
+ }
406
+ .dfd-scroll tbody tr[data-id] {
407
+ height: var(--dfd-row-h);
408
+ }
409
+ .dfd-scroll tbody tr[data-id] {
410
+ cursor: pointer;
411
+ }
412
+ /* row identity: a status stripe on every row, a full tint on missing rows */
413
+ .dfd-scroll tbody tr[data-id] td.cb {
414
+ box-shadow: inset 4px 0 0 var(--c);
415
+ }
416
+ .dfd-scroll tbody tr.st-missing_left td,
417
+ .dfd-scroll tbody tr.st-missing_right td {
418
+ background-color: color-mix(in srgb, var(--c) 9%, transparent);
419
+ }
420
+ .dfd-scroll tbody tr[data-id]:hover td {
421
+ background-image: linear-gradient(var(--dfd-soft), var(--dfd-soft));
422
+ }
423
+ .dfd-scroll tbody tr[data-id].sel td {
424
+ background-image: linear-gradient(rgba(127, 127, 127, 0.12), rgba(127, 127, 127, 0.12));
425
+ }
426
+ .dfd-scroll tbody tr[data-id].active td {
427
+ background-image: linear-gradient(rgba(127, 127, 127, 0.2), rgba(127, 127, 127, 0.2));
428
+ }
429
+ .dfd td.cb,
430
+ .dfd th.cb {
431
+ width: 34px;
432
+ padding-right: 0;
433
+ }
434
+ .dfd td.cb {
435
+ padding-left: 12px;
436
+ }
437
+ .dfd td.num,
438
+ .dfd th.num {
439
+ text-align: right;
440
+ font-variant-numeric: tabular-nums;
441
+ }
442
+ .dfd th.num .dfd-colmeta {
443
+ justify-content: flex-end;
444
+ }
445
+ .dfd td.key {
446
+ font-weight: 600;
447
+ }
448
+ .dfd td.absent {
449
+ color: var(--dfd-muted);
450
+ opacity: 0.5;
451
+ }
452
+ /* 1px frame that neighbouring differences share: bottom = the cell border, top and
453
+ left sit on the neighbour's edge, right inside the cell – so adjacent frames overlap
454
+ instead of doubling or leaving the grey grid line between them */
455
+ .dfd-scroll td.diff {
456
+ --dfd-frame: var(--st-mismatch);
457
+ background-color: color-mix(in srgb, var(--st-mismatch) 20%, transparent);
458
+ border-bottom-color: var(--dfd-frame);
459
+ box-shadow:
460
+ 0 -1px 0 var(--dfd-frame),
461
+ -1px 0 0 var(--dfd-frame),
462
+ -1px -1px 0 var(--dfd-frame),
463
+ inset -1px 0 0 var(--dfd-frame);
464
+ }
465
+ /* first row: the sticky header covers the line above; last row of a full page: no
466
+ bottom border */
467
+ .dfd-scroll tbody tr:first-child td.diff {
468
+ box-shadow:
469
+ inset 0 1px 0 var(--dfd-frame),
470
+ -1px 0 0 var(--dfd-frame),
471
+ inset -1px 0 0 var(--dfd-frame);
472
+ }
473
+ .dfd-scroll table.full tbody tr:last-child td.diff {
474
+ box-shadow:
475
+ 0 -1px 0 var(--dfd-frame),
476
+ -1px 0 0 var(--dfd-frame),
477
+ -1px -1px 0 var(--dfd-frame),
478
+ inset -1px 0 0 var(--dfd-frame),
479
+ inset 0 -1px 0 var(--dfd-frame);
480
+ }
481
+ .dfd-scroll table.full tbody tr:only-child td.diff {
482
+ box-shadow:
483
+ inset 0 1px 0 var(--dfd-frame),
484
+ -1px 0 0 var(--dfd-frame),
485
+ inset -1px 0 0 var(--dfd-frame),
486
+ inset 0 -1px 0 var(--dfd-frame);
487
+ }
488
+ /* both sides of a difference carry equal weight – only the side marker tells them apart */
489
+ /* 2 × 18px values + 5px separator + 2 × 3px padding + 1px border = --dfd-row-h */
490
+ .dfd-scroll td.diff {
491
+ padding-top: 3px;
492
+ padding-bottom: 3px;
493
+ }
494
+ .dfd-val {
495
+ display: flex;
496
+ align-items: baseline;
497
+ gap: 6px;
498
+ line-height: 18px;
499
+ }
500
+ .dfd-val:first-child {
501
+ padding-bottom: 2px;
502
+ margin-bottom: 2px;
503
+ border-bottom: 1px dashed color-mix(in srgb, var(--st-mismatch) 55%, transparent);
504
+ }
505
+ td.num .dfd-v {
506
+ flex: 1;
507
+ text-align: right;
508
+ }
509
+ .dfd-val .dfd-side {
510
+ margin-left: auto;
511
+ }
512
+ .dfd-scroll td.status,
513
+ .dfd-scroll th.status {
514
+ width: 1%;
515
+ text-align: center;
516
+ }
517
+ .dfd-sr {
518
+ position: absolute;
519
+ width: 1px;
520
+ height: 1px;
521
+ overflow: hidden;
522
+ clip: rect(0 0 0 0);
523
+ white-space: nowrap;
524
+ }
525
+ .dfd-side {
526
+ display: inline-flex;
527
+ align-items: center;
528
+ justify-content: center;
529
+ flex: none;
530
+ min-width: 15px;
531
+ height: 15px;
532
+ padding: 0 2px;
533
+ border-radius: 3px;
534
+ background: var(--side);
535
+ color: #fff;
536
+ font-size: 9px;
537
+ font-weight: 700;
538
+ line-height: 1;
539
+ align-self: center;
540
+ }
541
+ .dfd-side.l {
542
+ --side: var(--side-l);
543
+ }
544
+ .dfd-side.r {
545
+ --side: var(--side-r);
546
+ }
547
+ /* chip followed by the side's name */
548
+ .dfd-sidename {
549
+ display: inline-flex;
550
+ align-items: center;
551
+ gap: 4px;
552
+ }
553
+ /* invisible characters: plain grey glyphs, no box */
554
+ .dfd-inv {
555
+ color: rgba(127, 127, 127, 0.9);
556
+ font-weight: 400;
557
+ margin: 0 0.5px;
558
+ }
559
+ .dfd-inv.code {
560
+ font-size: 9px;
561
+ font-weight: 700;
562
+ letter-spacing: 0.02em;
563
+ vertical-align: 1px;
564
+ }
565
+ .dfd-null {
566
+ color: var(--dfd-muted);
567
+ font-style: italic;
568
+ opacity: 0.7;
569
+ }
570
+ /* one row high like every other row: an empty diff has room for exactly one */
571
+ .dfd-scroll td.dfd-empty {
572
+ height: var(--dfd-row-h);
573
+ text-align: center;
574
+ padding: 0 10px;
575
+ color: var(--dfd-muted);
576
+ }
577
+ .dfd-pill {
578
+ display: inline-flex;
579
+ align-items: center;
580
+ gap: 6px;
581
+ font-size: 12px;
582
+ white-space: nowrap;
583
+ }
584
+
585
+ /* ---------- footer ---------- */
586
+ .dfd-footer {
587
+ display: flex;
588
+ flex-wrap: wrap;
589
+ align-items: center;
590
+ gap: 8px 16px;
591
+ color: var(--dfd-muted);
592
+ font-size: 12px;
593
+ }
594
+ .dfd-footer select {
595
+ font: inherit;
596
+ color: inherit;
597
+ background: transparent;
598
+ border: 1px solid var(--dfd-line);
599
+ border-radius: 4px;
600
+ margin-left: 6px;
601
+ padding: 1px 4px;
602
+ }
603
+ .dfd-pager {
604
+ display: inline-flex;
605
+ align-items: center;
606
+ gap: 4px;
607
+ font-variant-numeric: tabular-nums;
608
+ }
609
+ .dfd-pager button {
610
+ border: 1px solid var(--dfd-line);
611
+ background: transparent;
612
+ border-radius: 4px;
613
+ width: 26px;
614
+ height: 24px;
615
+ }
616
+ .dfd-pager button:disabled {
617
+ opacity: 0.35;
618
+ cursor: default;
619
+ }
620
+ .dfd-pager span {
621
+ padding: 0 6px;
622
+ }
623
+
624
+ /* ---------- detail ---------- */
625
+ .dfd-detail {
626
+ border: 1px solid var(--dfd-line);
627
+ border-left: 4px solid var(--c);
628
+ border-radius: 8px;
629
+ overflow: hidden;
630
+ }
631
+ .dfd-detail header {
632
+ display: flex;
633
+ flex-wrap: wrap;
634
+ align-items: center;
635
+ gap: 8px 12px;
636
+ padding: 8px 12px;
637
+ background: color-mix(in srgb, var(--c) 10%, transparent);
638
+ border-bottom: 1px solid var(--dfd-line);
639
+ }
640
+ .dfd-detail-key {
641
+ display: inline-flex;
642
+ flex-wrap: wrap;
643
+ gap: 6px;
644
+ }
645
+ .dfd-close {
646
+ border: 0;
647
+ background: none;
648
+ font-size: 18px;
649
+ line-height: 1;
650
+ padding: 0 4px;
651
+ opacity: 0.7;
652
+ }
653
+ .dfd-detail-scroll {
654
+ overflow-x: auto;
655
+ max-height: 360px;
656
+ }
657
+ .dfd-detail table th,
658
+ .dfd-detail table td {
659
+ padding: 4px 12px;
660
+ border-bottom: 1px solid var(--dfd-line);
661
+ text-align: left;
662
+ white-space: nowrap;
663
+ }
664
+ .dfd-detail table td.num {
665
+ text-align: right;
666
+ }
667
+ .dfd-detail thead th {
668
+ font-weight: 600;
669
+ font-size: 12px;
670
+ }
671
+ .dfd-detail tbody th {
672
+ font-weight: 500;
673
+ width: 1%;
674
+ }
675
+ .dfd-detail tbody tr:last-child > * {
676
+ border-bottom: 0;
677
+ }
678
+ .dfd-detail tr.diff > * {
679
+ background-color: color-mix(in srgb, var(--st-mismatch) 20%, transparent);
680
+ }
681
+ .dfd-detail td.mark {
682
+ color: var(--dfd-muted);
683
+ font-variant-numeric: tabular-nums;
684
+ }
685
+ .dfd-detail tr.diff td.mark {
686
+ color: inherit;
687
+ font-weight: 600;
688
+ }
689
+ .dfd-absent {
690
+ opacity: 0.4;
691
+ }
692
+
693
+ /* ---------- column menu (sort & filter) ---------- */
694
+ .dfd {
695
+ position: relative;
696
+ }
697
+ .dfd-th-top {
698
+ display: flex;
699
+ align-items: center;
700
+ gap: 4px;
701
+ }
702
+ th.num .dfd-th-top {
703
+ justify-content: flex-end;
704
+ }
705
+ th.status .dfd-th-top {
706
+ justify-content: center;
707
+ }
708
+ .dfd-colbtn {
709
+ display: inline-flex;
710
+ align-items: center;
711
+ justify-content: center;
712
+ width: 20px;
713
+ height: 20px;
714
+ border-radius: 4px;
715
+ border: 0;
716
+ background: none;
717
+ padding: 0;
718
+ opacity: 0.35;
719
+ transition:
720
+ opacity 0.12s,
721
+ background 0.12s;
722
+ }
723
+ .dfd-colbtn svg {
724
+ width: 12px;
725
+ height: 12px;
726
+ fill: none;
727
+ stroke: currentColor;
728
+ stroke-width: 1.4;
729
+ stroke-linejoin: round;
730
+ }
731
+ th:hover .dfd-colbtn,
732
+ .dfd-colbtn:focus-visible,
733
+ .dfd-colbtn.open {
734
+ opacity: 0.85;
735
+ }
736
+ .dfd-colbtn:hover,
737
+ .dfd-colbtn.open {
738
+ background: var(--dfd-soft);
739
+ }
740
+ .dfd-colbtn.on {
741
+ opacity: 1;
742
+ }
743
+ .dfd-colbtn.on svg {
744
+ fill: currentColor;
745
+ }
746
+ @media (hover: none) {
747
+ .dfd-colbtn {
748
+ opacity: 0.6;
749
+ }
750
+ }
751
+
752
+ .dfd-colmenu {
753
+ position: absolute;
754
+ z-index: 6;
755
+ width: min(290px, 100%);
756
+ background: var(--dfd-bg, Canvas);
757
+ border: 1px solid var(--dfd-line);
758
+ border-radius: 8px;
759
+ box-shadow: 0 8px 24px rgba(0, 0, 0, 0.18);
760
+ padding: 8px;
761
+ display: flex;
762
+ flex-direction: column;
763
+ gap: 8px;
764
+ font-weight: 400;
765
+ }
766
+ .dfd-cm-title {
767
+ display: flex;
768
+ align-items: baseline;
769
+ gap: 8px;
770
+ padding: 0 2px;
771
+ }
772
+ .dfd-cm-sort {
773
+ display: flex;
774
+ flex-direction: column;
775
+ border-top: 1px solid var(--dfd-line);
776
+ border-bottom: 1px solid var(--dfd-line);
777
+ padding: 4px 0;
778
+ }
779
+ .dfd-cm-sort button {
780
+ border: 0;
781
+ background: none;
782
+ text-align: left;
783
+ padding: 5px 6px;
784
+ border-radius: 5px;
785
+ }
786
+ .dfd-cm-sort button:hover {
787
+ background: var(--dfd-soft);
788
+ }
789
+ .dfd-cm-sort button.on {
790
+ font-weight: 600;
791
+ }
792
+ .dfd-cm-filter {
793
+ display: flex;
794
+ flex-direction: column;
795
+ gap: 6px;
796
+ }
797
+ .dfd-cm-label {
798
+ display: flex;
799
+ align-items: center;
800
+ justify-content: space-between;
801
+ gap: 8px;
802
+ font-size: 12px;
803
+ color: var(--dfd-muted);
804
+ }
805
+ .dfd-colmenu select,
806
+ .dfd-colmenu input:not([type="checkbox"]) {
807
+ font: inherit;
808
+ color: inherit;
809
+ background: transparent;
810
+ border: 1px solid var(--dfd-line);
811
+ border-radius: 5px;
812
+ padding: 4px 6px;
813
+ min-width: 0;
814
+ }
815
+ .dfd-colmenu select {
816
+ flex: 1;
817
+ max-width: 170px;
818
+ color: inherit;
819
+ }
820
+ .dfd-colmenu select option {
821
+ color: initial;
822
+ }
823
+ .dfd-cm-values {
824
+ display: flex;
825
+ align-items: center;
826
+ gap: 6px;
827
+ }
828
+ .dfd-cm-values input {
829
+ flex: 1;
830
+ width: 100%;
831
+ }
832
+ .dfd-cm-and,
833
+ .dfd-cm-values input[data-f="b"] {
834
+ display: none;
835
+ }
836
+ .dfd-cm-filter.two .dfd-cm-and,
837
+ .dfd-cm-filter.two input[data-f="b"] {
838
+ display: initial;
839
+ }
840
+ .dfd-cm-and {
841
+ font-size: 12px;
842
+ color: var(--dfd-muted);
843
+ }
844
+ .dfd-cm-filter.novalue .dfd-cm-values {
845
+ display: none;
846
+ }
847
+ .dfd-cm-hint {
848
+ margin: 0;
849
+ font-size: 11px;
850
+ color: var(--dfd-muted);
851
+ }
852
+ .dfd-cm-actions {
853
+ display: flex;
854
+ justify-content: flex-end;
855
+ gap: 6px;
856
+ }
857
+ .dfd-cm-actions button {
858
+ border: 1px solid var(--dfd-line);
859
+ background: transparent;
860
+ border-radius: 5px;
861
+ padding: 4px 10px;
862
+ }
863
+ .dfd-cm-actions button:disabled {
864
+ opacity: 0.4;
865
+ cursor: default;
866
+ }
867
+ .dfd-cm-actions button.primary {
868
+ background: var(--dfd-soft);
869
+ border-color: currentColor;
870
+ font-weight: 600;
871
+ }
872
+
873
+ .dfd-pillfilter.col {
874
+ background: var(--dfd-soft);
875
+ border: 1px solid var(--dfd-line);
876
+ }
877
+ .dfd-pill-edit {
878
+ border: 0;
879
+ background: none;
880
+ padding: 0;
881
+ font-size: 12px;
882
+ }
883
+ .dfd-pill-edit b {
884
+ font-weight: 600;
885
+ }
886
+
887
+ /* ---------- per-column match stats ---------- */
888
+ .dfd-colstats {
889
+ display: flex;
890
+ align-items: center;
891
+ gap: 6px;
892
+ margin-top: 4px;
893
+ font-size: 11px;
894
+ font-weight: 400;
895
+ font-variant-numeric: tabular-nums;
896
+ }
897
+ th.num .dfd-colstats {
898
+ justify-content: flex-end;
899
+ }
900
+ .dfd-bar2 {
901
+ display: flex;
902
+ width: 48px;
903
+ height: 5px;
904
+ border-radius: 3px;
905
+ overflow: hidden;
906
+ gap: 1px;
907
+ flex: none;
908
+ }
909
+ .dfd-bar2 .eq {
910
+ background: var(--st-equal);
911
+ }
912
+ .dfd-bar2 .mm {
913
+ background: var(--st-mismatch);
914
+ }
915
+ .dfd-colstats .dfd-delta {
916
+ font-size: 11px;
917
+ }
918
+
919
+ /* ---------- loading & errors ---------- */
920
+ .dfd .dfd-scroll,
921
+ .dfd .dfd-footer {
922
+ transition: opacity 0.15s;
923
+ }
924
+ .dfd.loading .dfd-scroll,
925
+ .dfd.loading .dfd-footer {
926
+ opacity: 0.55;
927
+ }
928
+ .dfd-error {
929
+ padding: 8px 12px;
930
+ border-radius: 6px;
931
+ font-size: 12px;
932
+ background: color-mix(in srgb, var(--dfd-danger) 14%, transparent);
933
+ border: 1px solid color-mix(in srgb, var(--dfd-danger) 45%, transparent);
934
+ }
935
+ .dfd-error[hidden] {
936
+ display: none;
937
+ }
938
+ .dfd button:disabled {
939
+ cursor: default;
940
+ }
941
+
942
+ /* ---------- reduced motion ----------
943
+ Last in the file and !important on purpose: the user's preference must win
944
+ over every transition declared above, whatever its specificity. */
945
+ @media (prefers-reduced-motion: reduce) {
946
+ .dfd * {
947
+ /* biome-ignore lint/complexity/noImportantStyles: user preference must override all transitions */
948
+ transition: none !important;
949
+ /* biome-ignore lint/complexity/noImportantStyles: user preference must override smooth scrolling */
950
+ scroll-behavior: auto !important;
951
+ }
952
+ }