@zvndev/yable-themes 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.
package/dist/base.css ADDED
@@ -0,0 +1,2706 @@
1
+ /* ============================================================================
2
+ @zvndev/yable-themes — Base Styles
3
+ Structural and visual CSS shared by all themes. Handles layout, ARIA,
4
+ foundational table mechanics, and premium default appearance.
5
+
6
+ Design direction: Swiss precision meets modern SaaS.
7
+ Clean, tight, functional — like Linear, Notion, or Vercel dashboards.
8
+ Every pixel intentional. Smooth transitions on all interactive elements.
9
+ ============================================================================ */
10
+
11
+ /* ── Table Container ─────────────────────────────────────────────────────── */
12
+
13
+ .yable {
14
+ position: relative;
15
+ width: 100%;
16
+ overflow: hidden;
17
+ border-radius: var(--yable-border-radius);
18
+ border: var(--yable-border-width) solid var(--yable-border-color);
19
+ background: var(--yable-bg);
20
+ font-family: var(--yable-font-family);
21
+ font-size: var(--yable-font-size);
22
+ line-height: var(--yable-line-height);
23
+ color: var(--yable-text-primary);
24
+ box-sizing: border-box;
25
+ box-shadow: var(--yable-shadow);
26
+ -webkit-font-smoothing: antialiased;
27
+ -moz-osx-font-smoothing: grayscale;
28
+ }
29
+
30
+ .yable *,
31
+ .yable *::before,
32
+ .yable *::after {
33
+ box-sizing: border-box;
34
+ }
35
+
36
+ /* ── Custom Scrollbar ────────────────────────────────────────────────────── */
37
+
38
+ .yable ::-webkit-scrollbar {
39
+ width: 6px;
40
+ height: 6px;
41
+ }
42
+
43
+ .yable ::-webkit-scrollbar-track {
44
+ background: transparent;
45
+ }
46
+
47
+ .yable ::-webkit-scrollbar-thumb {
48
+ background: var(--yable-border-color-strong);
49
+ border-radius: 3px;
50
+ }
51
+
52
+ .yable ::-webkit-scrollbar-thumb:hover {
53
+ background: var(--yable-text-tertiary);
54
+ }
55
+
56
+ .yable ::-webkit-scrollbar-corner {
57
+ background: transparent;
58
+ }
59
+
60
+ /* Firefox scrollbar */
61
+ .yable {
62
+ scrollbar-width: thin;
63
+ scrollbar-color: var(--yable-border-color-strong) transparent;
64
+ }
65
+
66
+ /* ── Table Element ───────────────────────────────────────────────────────── */
67
+
68
+ .yable-table {
69
+ width: 100%;
70
+ border-collapse: collapse;
71
+ border-spacing: 0;
72
+ table-layout: fixed;
73
+ }
74
+
75
+ /* ── Main Content Area ───────────────────────────────────────────────────── */
76
+
77
+ .yable-main {
78
+ position: relative;
79
+ flex: 1;
80
+ min-width: 0;
81
+ overflow: auto;
82
+ }
83
+
84
+ /* Scrollbar on .yable-main (the actual scrolling container) */
85
+ .yable-main::-webkit-scrollbar {
86
+ width: 6px;
87
+ height: 6px;
88
+ }
89
+
90
+ .yable-main::-webkit-scrollbar-track {
91
+ background: transparent;
92
+ }
93
+
94
+ .yable-main::-webkit-scrollbar-thumb {
95
+ background: var(--yable-border-color-strong);
96
+ border-radius: 3px;
97
+ }
98
+
99
+ .yable-main::-webkit-scrollbar-thumb:hover {
100
+ background: var(--yable-text-tertiary);
101
+ }
102
+
103
+ .yable-main::-webkit-scrollbar-corner {
104
+ background: transparent;
105
+ }
106
+
107
+ .yable-main {
108
+ scrollbar-width: thin;
109
+ scrollbar-color: var(--yable-border-color-strong) transparent;
110
+ }
111
+
112
+ /* ── Header ──────────────────────────────────────────────────────────────── */
113
+
114
+ .yable-thead {
115
+ position: relative;
116
+ }
117
+
118
+ .yable-header-row {
119
+ background: var(--yable-bg-header);
120
+ }
121
+
122
+ .yable-th {
123
+ position: relative;
124
+ padding: var(--yable-header-padding-y) var(--yable-header-padding-x);
125
+ min-height: var(--yable-header-min-height);
126
+ font-size: var(--yable-font-size-header);
127
+ font-weight: var(--yable-font-weight-medium);
128
+ color: var(--yable-text-header);
129
+ text-align: left;
130
+ white-space: nowrap;
131
+ overflow: hidden;
132
+ text-overflow: ellipsis;
133
+ border-bottom: calc(var(--yable-border-width) + 1px) solid var(--yable-border-color-strong);
134
+ user-select: none;
135
+ vertical-align: middle;
136
+ letter-spacing: 0.02em;
137
+ transition: background var(--yable-transition-fast);
138
+ }
139
+
140
+ .yable-th[data-sortable="true"] {
141
+ cursor: pointer;
142
+ }
143
+
144
+ .yable-th[data-sortable="true"]:hover {
145
+ background: var(--yable-bg-row-hover);
146
+ }
147
+
148
+ /* Header content wrapper */
149
+ .yable-th-content {
150
+ display: flex;
151
+ align-items: center;
152
+ gap: 6px;
153
+ min-height: calc(var(--yable-header-min-height) - var(--yable-header-padding-y) * 2);
154
+ }
155
+
156
+ /* ── Sort Indicator ──────────────────────────────────────────────────────── */
157
+
158
+ .yable-sort-indicator {
159
+ display: inline-flex;
160
+ align-items: center;
161
+ justify-content: center;
162
+ flex-shrink: 0;
163
+ width: calc(var(--yable-sort-icon-size) + 2px);
164
+ height: calc(var(--yable-sort-icon-size) + 2px);
165
+ color: var(--yable-sort-icon-color);
166
+ opacity: 0;
167
+ transition: color var(--yable-transition),
168
+ transform var(--yable-transition),
169
+ opacity var(--yable-transition);
170
+ }
171
+
172
+ /* Show sort indicator on header hover */
173
+ .yable-th[data-sortable="true"]:hover .yable-sort-indicator {
174
+ opacity: 0.4;
175
+ }
176
+
177
+ .yable-sort-indicator[data-active="true"] {
178
+ color: var(--yable-sort-icon-color-active);
179
+ opacity: 1;
180
+ }
181
+
182
+ .yable-sort-indicator[data-direction="desc"] {
183
+ transform: rotate(180deg);
184
+ }
185
+
186
+ .yable-sort-badge {
187
+ font-size: 9px;
188
+ font-weight: var(--yable-font-weight-semibold);
189
+ color: var(--yable-accent);
190
+ background: var(--yable-accent-light);
191
+ width: 14px;
192
+ height: 14px;
193
+ display: inline-flex;
194
+ align-items: center;
195
+ justify-content: center;
196
+ border-radius: 50%;
197
+ margin-left: 2px;
198
+ }
199
+
200
+ /* ── Resize Handle ───────────────────────────────────────────────────────── */
201
+
202
+ .yable-resize-handle {
203
+ position: absolute;
204
+ top: 0;
205
+ right: 0;
206
+ bottom: 0;
207
+ width: calc(var(--yable-resize-handle-width) * 2);
208
+ cursor: col-resize;
209
+ z-index: var(--yable-z-resize);
210
+ touch-action: none;
211
+ display: flex;
212
+ align-items: center;
213
+ justify-content: center;
214
+ }
215
+
216
+ .yable-resize-handle::after {
217
+ content: '';
218
+ width: var(--yable-resize-handle-width);
219
+ height: 0%;
220
+ border-radius: 2px;
221
+ background: var(--yable-resize-handle-color);
222
+ transition: background var(--yable-transition),
223
+ height var(--yable-transition);
224
+ }
225
+
226
+ .yable-resize-handle:hover::after {
227
+ background: var(--yable-border-color-strong);
228
+ height: 50%;
229
+ }
230
+
231
+ .yable-resize-handle[data-resizing="true"]::after {
232
+ background: var(--yable-resize-handle-color-active);
233
+ height: 70%;
234
+ }
235
+
236
+ /* ── Column Reorder ──────────────────────────────────────────────────────── */
237
+
238
+ .yable-th[data-reorderable="true"] {
239
+ cursor: grab;
240
+ }
241
+
242
+ .yable-th[data-reorderable="true"]:active {
243
+ cursor: grabbing;
244
+ }
245
+
246
+ /* When sortable AND reorderable, sort cursor wins on the content area so the
247
+ header still feels clickable. The drag is initiated from a mousedown that
248
+ moves; a click without movement still triggers the sort. */
249
+ .yable-th[data-sortable="true"][data-reorderable="true"] {
250
+ cursor: pointer;
251
+ }
252
+
253
+ /* Drop indicator — a 2px accent bar on the leading or trailing edge of the
254
+ target column. Drawn by a child of the th so it doesn't shift layout. */
255
+ .yable-th[data-drag-over]::before,
256
+ .yable-th[data-drag-over]::after {
257
+ content: '';
258
+ position: absolute;
259
+ top: 0;
260
+ bottom: 0;
261
+ width: 2px;
262
+ background: var(--yable-accent);
263
+ pointer-events: none;
264
+ z-index: calc(var(--yable-z-resize) + 1);
265
+ }
266
+
267
+ .yable-th[data-drag-over="left"]::before {
268
+ left: -1px;
269
+ }
270
+
271
+ .yable-th[data-drag-over="right"]::after {
272
+ right: -1px;
273
+ }
274
+
275
+ .yable-th[data-drag-over="left"]::after,
276
+ .yable-th[data-drag-over="right"]::before {
277
+ display: none;
278
+ }
279
+
280
+ /* ── Body ────────────────────────────────────────────────────────────────── */
281
+
282
+ .yable-tbody {
283
+ background: var(--yable-bg);
284
+ }
285
+
286
+ /* ── Row ─────────────────────────────────────────────────────────────────── */
287
+
288
+ .yable-tr {
289
+ background: var(--yable-bg-row);
290
+ min-height: var(--yable-row-min-height);
291
+ transition: background-color var(--yable-transition);
292
+ }
293
+
294
+ .yable-tr:not(:last-child) .yable-td {
295
+ border-bottom: var(--yable-border-width) solid var(--yable-border-color);
296
+ }
297
+
298
+ .yable-tr:hover {
299
+ background: var(--yable-bg-row-hover);
300
+ }
301
+
302
+ .yable-tr[data-selected="true"] {
303
+ background: var(--yable-bg-row-selected);
304
+ box-shadow: inset 2px 0 0 0 var(--yable-accent);
305
+ }
306
+
307
+ .yable-tr[data-selected="true"]:hover {
308
+ background: var(--yable-bg-row-selected);
309
+ }
310
+
311
+ .yable-tr[data-expanded="true"] {
312
+ background: var(--yable-bg-row-expanded);
313
+ }
314
+
315
+ .yable-tr[data-clickable="true"] {
316
+ cursor: pointer;
317
+ }
318
+
319
+ /* Striped rows — barely perceptible */
320
+ .yable--striped .yable-tr:nth-child(even) {
321
+ background: var(--yable-bg-row-alt);
322
+ }
323
+
324
+ .yable--striped .yable-tr:nth-child(even):hover {
325
+ background: var(--yable-bg-row-hover);
326
+ }
327
+
328
+ /* Bordered variant — visible column separators */
329
+ .yable--bordered .yable-th + .yable-th,
330
+ .yable--bordered .yable-td + .yable-td {
331
+ border-left: var(--yable-border-width) solid var(--yable-border-color);
332
+ }
333
+
334
+ /* Compact variant */
335
+ .yable--compact .yable-th {
336
+ padding: 6px var(--yable-header-padding-x);
337
+ }
338
+
339
+ .yable--compact .yable-td {
340
+ padding: 4px var(--yable-cell-padding-x);
341
+ }
342
+
343
+ .yable--compact .yable-th,
344
+ .yable--compact .yable-td {
345
+ min-height: 32px;
346
+ }
347
+
348
+ /* ── Cell ────────────────────────────────────────────────────────────────── */
349
+
350
+ .yable-td {
351
+ padding: var(--yable-cell-padding-y) var(--yable-cell-padding-x);
352
+ min-height: var(--yable-row-min-height);
353
+ vertical-align: middle;
354
+ white-space: nowrap;
355
+ overflow: hidden;
356
+ text-overflow: ellipsis;
357
+ transition: background var(--yable-transition-fast),
358
+ box-shadow var(--yable-transition-fast);
359
+ }
360
+
361
+ .yable-td[data-editing="true"] {
362
+ padding: 4px 6px;
363
+ background: var(--yable-bg-cell-editing);
364
+ box-shadow: inset 0 0 0 2px var(--yable-accent),
365
+ 0 0 0 3px var(--yable-accent-light);
366
+ z-index: 2;
367
+ position: relative;
368
+ }
369
+
370
+ .yable-td.yable-cell--focused:not([data-editing="true"]) {
371
+ box-shadow: var(--yable-focus-ring);
372
+ position: relative;
373
+ z-index: calc(var(--yable-z-pinned) + 1);
374
+ }
375
+
376
+ /* ── Column Pinning ──────────────────────────────────────────────────────── */
377
+
378
+ .yable-th[data-pinned="left"],
379
+ .yable-td[data-pinned="left"] {
380
+ position: sticky;
381
+ left: var(--yable-pin-offset, 0px);
382
+ z-index: var(--yable-z-pinned);
383
+ background: var(--yable-bg-pinned);
384
+ }
385
+
386
+ .yable-th[data-pinned="right"],
387
+ .yable-td[data-pinned="right"] {
388
+ position: sticky;
389
+ right: var(--yable-pin-offset, 0px);
390
+ z-index: var(--yable-z-pinned);
391
+ background: var(--yable-bg-pinned);
392
+ }
393
+
394
+ /* Shadow on last left-pinned and first right-pinned */
395
+ .yable-th[data-pinned-edge="left"],
396
+ .yable-td[data-pinned-edge="left"] {
397
+ box-shadow: var(--yable-shadow-pinned);
398
+ clip-path: inset(0 -10px 0 0);
399
+ }
400
+
401
+ .yable-th[data-pinned-edge="right"],
402
+ .yable-td[data-pinned-edge="right"] {
403
+ box-shadow: calc(var(--yable-shadow-pinned) * -1);
404
+ clip-path: inset(0 0 0 -10px);
405
+ }
406
+
407
+ /* ── Sticky Header ───────────────────────────────────────────────────────── */
408
+
409
+ .yable--sticky-header .yable-thead .yable-th {
410
+ position: sticky;
411
+ top: 0;
412
+ z-index: var(--yable-z-header);
413
+ background: var(--yable-bg-header);
414
+ }
415
+
416
+ /* Pinned + sticky header stacks z-index */
417
+ .yable--sticky-header .yable-th[data-pinned] {
418
+ z-index: calc(var(--yable-z-header) + var(--yable-z-pinned));
419
+ }
420
+
421
+ /* ── Row Pinning ─────────────────────────────────────────────────────────── */
422
+
423
+ .yable-tr[data-pinned="top"] {
424
+ position: sticky;
425
+ top: 0;
426
+ z-index: calc(var(--yable-z-pinned) - 1);
427
+ background: var(--yable-bg-pinned);
428
+ box-shadow: 0 1px 0 var(--yable-border-color);
429
+ }
430
+
431
+ .yable-tr[data-pinned="bottom"] {
432
+ position: sticky;
433
+ bottom: 0;
434
+ z-index: calc(var(--yable-z-pinned) - 1);
435
+ background: var(--yable-bg-pinned);
436
+ box-shadow: 0 -1px 0 var(--yable-border-color);
437
+ }
438
+
439
+ /* ── Footer ──────────────────────────────────────────────────────────────── */
440
+
441
+ .yable-tfoot {
442
+ background: var(--yable-bg-footer);
443
+ }
444
+
445
+ .yable-tfoot .yable-td {
446
+ font-weight: var(--yable-font-weight-semibold);
447
+ border-top: calc(var(--yable-border-width) + 1px) solid var(--yable-border-color-strong);
448
+ border-bottom: none;
449
+ font-variant-numeric: tabular-nums;
450
+ }
451
+
452
+ /* ── Expanded Row Detail ─────────────────────────────────────────────────── */
453
+
454
+ .yable-expand-row {
455
+ background: var(--yable-bg-row-expanded);
456
+ }
457
+
458
+ .yable-expand-row .yable-td {
459
+ padding: 16px var(--yable-cell-padding-x);
460
+ border-bottom: var(--yable-border-width) solid var(--yable-border-color);
461
+ }
462
+
463
+ .yable-expand-toggle {
464
+ display: inline-flex;
465
+ align-items: center;
466
+ justify-content: center;
467
+ width: 22px;
468
+ height: 22px;
469
+ border: none;
470
+ background: none;
471
+ cursor: pointer;
472
+ color: var(--yable-text-secondary);
473
+ transition: transform var(--yable-transition),
474
+ color var(--yable-transition-fast),
475
+ background var(--yable-transition-fast);
476
+ padding: 0;
477
+ border-radius: var(--yable-border-radius-sm);
478
+ }
479
+
480
+ .yable-expand-toggle:hover {
481
+ color: var(--yable-text-primary);
482
+ background: var(--yable-bg-row-hover);
483
+ }
484
+
485
+ .yable-expand-toggle[data-expanded="true"] {
486
+ transform: rotate(90deg);
487
+ color: var(--yable-accent);
488
+ }
489
+
490
+ /* ── Form Controls (in-cell editing) ─────────────────────────────────────── */
491
+
492
+ .yable-input {
493
+ width: 100%;
494
+ height: var(--yable-input-height);
495
+ padding: 0 var(--yable-input-padding-x);
496
+ background: var(--yable-input-bg);
497
+ border: var(--yable-border-width) solid var(--yable-input-border);
498
+ border-radius: var(--yable-input-border-radius);
499
+ font-family: inherit;
500
+ font-size: var(--yable-input-font-size);
501
+ color: var(--yable-text-primary);
502
+ outline: none;
503
+ transition: border-color var(--yable-transition-fast),
504
+ background var(--yable-transition-fast),
505
+ box-shadow var(--yable-transition-fast);
506
+ }
507
+
508
+ .yable-input:hover {
509
+ background: var(--yable-input-bg-hover);
510
+ border-color: var(--yable-input-border-hover);
511
+ }
512
+
513
+ .yable-input:focus {
514
+ background: var(--yable-input-bg-focus);
515
+ border-color: var(--yable-input-border-focus);
516
+ box-shadow: var(--yable-input-shadow-focus);
517
+ }
518
+
519
+ .yable-input::placeholder {
520
+ color: var(--yable-text-placeholder);
521
+ }
522
+
523
+ /* Always-editable: inputs blend into cells */
524
+ .yable-input--inline {
525
+ border-color: transparent;
526
+ background: transparent;
527
+ border-radius: 0;
528
+ }
529
+
530
+ .yable-input--inline:hover {
531
+ border-color: var(--yable-input-border);
532
+ background: var(--yable-input-bg-hover);
533
+ }
534
+
535
+ .yable-input--inline:focus {
536
+ border-color: var(--yable-input-border-focus);
537
+ background: var(--yable-input-bg-focus);
538
+ box-shadow: var(--yable-input-shadow-focus);
539
+ border-radius: var(--yable-input-border-radius);
540
+ }
541
+
542
+ /* Select */
543
+ .yable-select {
544
+ appearance: none;
545
+ width: 100%;
546
+ height: var(--yable-input-height);
547
+ padding: 0 calc(var(--yable-input-padding-x) + 16px) 0 var(--yable-input-padding-x);
548
+ background: var(--yable-input-bg);
549
+ border: var(--yable-border-width) solid var(--yable-input-border);
550
+ border-radius: var(--yable-input-border-radius);
551
+ font-family: inherit;
552
+ font-size: var(--yable-input-font-size);
553
+ color: var(--yable-text-primary);
554
+ outline: none;
555
+ cursor: pointer;
556
+ background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12' fill='%236b7280'%3E%3Cpath d='M6 8.5L1.5 4h9L6 8.5z'/%3E%3C/svg%3E");
557
+ background-repeat: no-repeat;
558
+ background-position: right 6px center;
559
+ background-size: 12px;
560
+ transition: border-color var(--yable-transition-fast),
561
+ background-color var(--yable-transition-fast),
562
+ box-shadow var(--yable-transition-fast);
563
+ }
564
+
565
+ .yable-select:hover {
566
+ border-color: var(--yable-input-border-hover);
567
+ }
568
+
569
+ .yable-select:focus {
570
+ border-color: var(--yable-input-border-focus);
571
+ box-shadow: var(--yable-input-shadow-focus);
572
+ }
573
+
574
+ /* Checkbox */
575
+ .yable-checkbox {
576
+ appearance: none;
577
+ width: var(--yable-checkbox-size);
578
+ height: var(--yable-checkbox-size);
579
+ border: var(--yable-border-width) solid var(--yable-checkbox-border);
580
+ border-radius: var(--yable-checkbox-radius);
581
+ background: var(--yable-checkbox-bg);
582
+ cursor: pointer;
583
+ position: relative;
584
+ flex-shrink: 0;
585
+ transition: background var(--yable-transition-fast),
586
+ border-color var(--yable-transition-fast),
587
+ box-shadow var(--yable-transition-fast);
588
+ }
589
+
590
+ .yable-checkbox:checked {
591
+ background: var(--yable-checkbox-bg-checked);
592
+ border-color: var(--yable-checkbox-border-checked);
593
+ }
594
+
595
+ .yable-checkbox:checked::after {
596
+ content: '';
597
+ position: absolute;
598
+ top: 2px;
599
+ left: 5px;
600
+ width: 4px;
601
+ height: 8px;
602
+ border: solid var(--yable-checkbox-checkmark);
603
+ border-width: 0 1.5px 1.5px 0;
604
+ transform: rotate(45deg);
605
+ }
606
+
607
+ .yable-checkbox:indeterminate {
608
+ background: var(--yable-checkbox-bg-checked);
609
+ border-color: var(--yable-checkbox-border-checked);
610
+ }
611
+
612
+ .yable-checkbox:indeterminate::after {
613
+ content: '';
614
+ position: absolute;
615
+ top: 50%;
616
+ left: 3px;
617
+ right: 3px;
618
+ height: 1.5px;
619
+ background: var(--yable-checkbox-checkmark);
620
+ transform: translateY(-50%);
621
+ }
622
+
623
+ .yable-checkbox:hover {
624
+ border-color: var(--yable-input-border-hover);
625
+ }
626
+
627
+ .yable-checkbox:focus-visible {
628
+ box-shadow: var(--yable-input-shadow-focus);
629
+ }
630
+
631
+ /* Toggle / Switch */
632
+ .yable-toggle {
633
+ appearance: none;
634
+ width: 36px;
635
+ height: 20px;
636
+ border-radius: 10px;
637
+ background: var(--yable-border-color-strong);
638
+ cursor: pointer;
639
+ position: relative;
640
+ transition: background var(--yable-transition);
641
+ border: none;
642
+ flex-shrink: 0;
643
+ }
644
+
645
+ .yable-toggle::after {
646
+ content: '';
647
+ position: absolute;
648
+ top: 2px;
649
+ left: 2px;
650
+ width: 16px;
651
+ height: 16px;
652
+ border-radius: 50%;
653
+ background: #ffffff;
654
+ box-shadow: 0 1px 2px rgba(0, 0, 0, 0.15);
655
+ transition: transform var(--yable-transition);
656
+ }
657
+
658
+ .yable-toggle:checked {
659
+ background: var(--yable-accent);
660
+ }
661
+
662
+ .yable-toggle:checked::after {
663
+ transform: translateX(16px);
664
+ }
665
+
666
+ .yable-toggle:focus-visible {
667
+ box-shadow: var(--yable-input-shadow-focus);
668
+ }
669
+
670
+ /* ── Pagination ──────────────────────────────────────────────────────────── */
671
+
672
+ .yable-pagination {
673
+ display: flex;
674
+ align-items: center;
675
+ justify-content: space-between;
676
+ gap: 16px;
677
+ padding: 10px var(--yable-cell-padding-x);
678
+ font-size: var(--yable-font-size-sm);
679
+ color: var(--yable-text-secondary);
680
+ border-top: var(--yable-border-width) solid var(--yable-border-color);
681
+ background: var(--yable-bg-footer);
682
+ }
683
+
684
+ .yable-pagination-info {
685
+ display: flex;
686
+ align-items: center;
687
+ gap: 8px;
688
+ color: var(--yable-text-tertiary);
689
+ font-variant-numeric: tabular-nums;
690
+ }
691
+
692
+ .yable-pagination-pages {
693
+ display: flex;
694
+ align-items: center;
695
+ gap: var(--yable-pagination-gap);
696
+ }
697
+
698
+ .yable-pagination-btn {
699
+ display: inline-flex;
700
+ align-items: center;
701
+ justify-content: center;
702
+ min-width: var(--yable-pagination-button-size);
703
+ height: var(--yable-pagination-button-size);
704
+ padding: 0 8px;
705
+ border: var(--yable-border-width) solid transparent;
706
+ border-radius: var(--yable-pagination-button-radius);
707
+ background: var(--yable-pagination-button-bg);
708
+ color: var(--yable-pagination-button-text);
709
+ font-family: inherit;
710
+ font-size: var(--yable-font-size-sm);
711
+ font-weight: var(--yable-font-weight-medium);
712
+ cursor: pointer;
713
+ transition: background var(--yable-transition-fast),
714
+ color var(--yable-transition-fast),
715
+ border-color var(--yable-transition-fast),
716
+ box-shadow var(--yable-transition-fast);
717
+ user-select: none;
718
+ font-variant-numeric: tabular-nums;
719
+ }
720
+
721
+ .yable-pagination-btn:hover:not(:disabled):not([data-active="true"]) {
722
+ background: var(--yable-pagination-button-bg-hover);
723
+ border-color: var(--yable-border-color);
724
+ }
725
+
726
+ .yable-pagination-btn[data-active="true"] {
727
+ background: var(--yable-pagination-button-bg-active);
728
+ color: var(--yable-pagination-button-text-active);
729
+ border-color: var(--yable-pagination-button-bg-active);
730
+ box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
731
+ }
732
+
733
+ .yable-pagination-btn:disabled {
734
+ opacity: 0.35;
735
+ cursor: not-allowed;
736
+ }
737
+
738
+ .yable-pagination-select {
739
+ appearance: none;
740
+ height: var(--yable-pagination-button-size);
741
+ padding: 0 28px 0 10px;
742
+ border: var(--yable-border-width) solid var(--yable-border-color);
743
+ border-radius: var(--yable-pagination-button-radius);
744
+ background: var(--yable-bg);
745
+ font-family: inherit;
746
+ font-size: var(--yable-font-size-sm);
747
+ color: var(--yable-text-secondary);
748
+ cursor: pointer;
749
+ outline: none;
750
+ background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12' fill='%236b7280'%3E%3Cpath d='M6 8.5L1.5 4h9L6 8.5z'/%3E%3C/svg%3E");
751
+ background-repeat: no-repeat;
752
+ background-position: right 8px center;
753
+ background-size: 10px;
754
+ transition: border-color var(--yable-transition-fast),
755
+ box-shadow var(--yable-transition-fast);
756
+ }
757
+
758
+ .yable-pagination-select:hover {
759
+ border-color: var(--yable-input-border-hover);
760
+ }
761
+
762
+ .yable-pagination-select:focus {
763
+ border-color: var(--yable-input-border-focus);
764
+ box-shadow: var(--yable-input-shadow-focus);
765
+ }
766
+
767
+ /* "Rows per page" label */
768
+ .yable-pagination-label {
769
+ color: var(--yable-text-tertiary);
770
+ font-size: var(--yable-font-size-sm);
771
+ white-space: nowrap;
772
+ }
773
+
774
+ /* ── Global Filter ───────────────────────────────────────────────────────── */
775
+
776
+ .yable-global-filter {
777
+ padding: 10px var(--yable-cell-padding-x);
778
+ border-bottom: var(--yable-border-width) solid var(--yable-border-color);
779
+ background: var(--yable-bg);
780
+ }
781
+
782
+ .yable-global-filter-input {
783
+ width: 100%;
784
+ max-width: 320px;
785
+ height: 34px;
786
+ padding: 0 10px 0 34px;
787
+ background: var(--yable-input-bg-hover);
788
+ border: var(--yable-border-width) solid transparent;
789
+ border-radius: 8px;
790
+ font-family: inherit;
791
+ font-size: var(--yable-font-size);
792
+ color: var(--yable-text-primary);
793
+ outline: none;
794
+ transition: border-color var(--yable-transition),
795
+ background var(--yable-transition),
796
+ box-shadow var(--yable-transition),
797
+ width var(--yable-transition-slow);
798
+ /* Search icon via background-image */
799
+ background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='%239ca3af' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='7' cy='7' r='4.5'/%3E%3Cpath d='M10.5 10.5L14 14'/%3E%3C/svg%3E");
800
+ background-repeat: no-repeat;
801
+ background-position: 10px center;
802
+ background-size: 15px;
803
+ }
804
+
805
+ .yable-global-filter-input:hover {
806
+ border-color: var(--yable-border-color);
807
+ }
808
+
809
+ .yable-global-filter-input:focus {
810
+ border-color: var(--yable-input-border-focus);
811
+ background-color: var(--yable-input-bg-focus);
812
+ box-shadow: var(--yable-input-shadow-focus);
813
+ }
814
+
815
+ .yable-global-filter-input::placeholder {
816
+ color: var(--yable-text-placeholder);
817
+ }
818
+
819
+ /* Clear button inside filter */
820
+ .yable-global-filter-clear {
821
+ display: inline-flex;
822
+ align-items: center;
823
+ justify-content: center;
824
+ width: 22px;
825
+ height: 22px;
826
+ border: none;
827
+ background: none;
828
+ color: var(--yable-text-tertiary);
829
+ cursor: pointer;
830
+ border-radius: 50%;
831
+ margin-left: -30px;
832
+ transition: color var(--yable-transition-fast),
833
+ background var(--yable-transition-fast);
834
+ }
835
+
836
+ .yable-global-filter-clear:hover {
837
+ color: var(--yable-text-primary);
838
+ background: var(--yable-bg-row-hover);
839
+ }
840
+
841
+ /* ── Empty State ─────────────────────────────────────────────────────────── */
842
+
843
+ .yable-empty {
844
+ display: flex;
845
+ flex-direction: column;
846
+ align-items: center;
847
+ justify-content: center;
848
+ padding: var(--yable-empty-padding);
849
+ color: var(--yable-empty-text-color);
850
+ text-align: center;
851
+ min-height: 200px;
852
+ }
853
+
854
+ .yable-empty-icon {
855
+ width: 48px;
856
+ height: 48px;
857
+ margin-bottom: 16px;
858
+ opacity: 0.3;
859
+ color: var(--yable-text-tertiary);
860
+ }
861
+
862
+ .yable-empty-message {
863
+ font-size: var(--yable-font-size);
864
+ font-weight: var(--yable-font-weight-medium);
865
+ color: var(--yable-text-secondary);
866
+ }
867
+
868
+ .yable-empty-detail {
869
+ font-size: var(--yable-font-size-sm);
870
+ margin-top: 6px;
871
+ color: var(--yable-text-tertiary);
872
+ max-width: 320px;
873
+ }
874
+
875
+ /* ── Loading State ───────────────────────────────────────────────────────── */
876
+
877
+ .yable-loading {
878
+ position: relative;
879
+ pointer-events: none;
880
+ }
881
+
882
+ .yable-loading::after {
883
+ content: '';
884
+ position: absolute;
885
+ inset: 0;
886
+ background: var(--yable-bg);
887
+ opacity: 0.5;
888
+ z-index: var(--yable-z-overlay);
889
+ }
890
+
891
+ .yable-skeleton {
892
+ height: 12px;
893
+ border-radius: 4px;
894
+ background: var(--yable-loading-shimmer);
895
+ background-size: 200% 100%;
896
+ animation: yable-shimmer 1.5s infinite linear;
897
+ }
898
+
899
+ @keyframes yable-shimmer {
900
+ 0% { background-position: 200% 0; }
901
+ 100% { background-position: -200% 0; }
902
+ }
903
+
904
+ /* ── Selection Column ────────────────────────────────────────────────────── */
905
+
906
+ .yable-th--selection,
907
+ .yable-td--selection {
908
+ width: 44px;
909
+ min-width: 44px;
910
+ max-width: 44px;
911
+ padding: 0;
912
+ text-align: center;
913
+ }
914
+
915
+ /* ── Accessibility ───────────────────────────────────────────────────────── */
916
+
917
+ .yable [role="columnheader"][aria-sort] {
918
+ cursor: pointer;
919
+ }
920
+
921
+ .yable:focus-within .yable-tr:focus-visible {
922
+ outline: 2px solid var(--yable-accent);
923
+ outline-offset: -2px;
924
+ }
925
+
926
+ .yable-td:focus-visible {
927
+ outline: 2px solid var(--yable-accent);
928
+ outline-offset: -2px;
929
+ }
930
+
931
+ /* Screen reader only */
932
+ .yable-sr-only {
933
+ position: absolute;
934
+ width: 1px;
935
+ height: 1px;
936
+ padding: 0;
937
+ margin: -1px;
938
+ overflow: hidden;
939
+ clip: rect(0, 0, 0, 0);
940
+ white-space: nowrap;
941
+ border: 0;
942
+ }
943
+
944
+ /* ── Fill Handle ─────────────────────────────────────────────────────────── */
945
+
946
+ .yable-fill-handle {
947
+ position: absolute;
948
+ bottom: -3px;
949
+ right: -3px;
950
+ width: 7px;
951
+ height: 7px;
952
+ background: var(--yable-accent);
953
+ border: 1.5px solid var(--yable-bg);
954
+ cursor: crosshair;
955
+ z-index: var(--yable-z-resize);
956
+ border-radius: 1px;
957
+ pointer-events: auto;
958
+ transition: width var(--yable-transition-fast),
959
+ height var(--yable-transition-fast);
960
+ }
961
+
962
+ .yable-fill-handle:hover {
963
+ width: 9px;
964
+ height: 9px;
965
+ bottom: -4px;
966
+ right: -4px;
967
+ }
968
+
969
+ .yable-fill-highlight {
970
+ background: var(--yable-accent);
971
+ opacity: 0.08;
972
+ pointer-events: none;
973
+ }
974
+
975
+ .yable-td--fill-source {
976
+ outline: 2px solid var(--yable-accent);
977
+ outline-offset: -2px;
978
+ }
979
+
980
+ .yable-td--fill-target {
981
+ background: color-mix(in srgb, var(--yable-accent) 6%, transparent);
982
+ border: 1px dashed var(--yable-accent);
983
+ }
984
+
985
+ /* ============================================================================
986
+ Row Dragging (yable-row-drag-*)
987
+ ============================================================================ */
988
+
989
+ .yable-row-drag-handle {
990
+ display: inline-flex;
991
+ align-items: center;
992
+ justify-content: center;
993
+ width: 24px;
994
+ height: 24px;
995
+ padding: 0;
996
+ border: none;
997
+ background: none;
998
+ cursor: grab;
999
+ color: var(--yable-text-tertiary);
1000
+ border-radius: var(--yable-border-radius-sm);
1001
+ transition: color var(--yable-transition-fast),
1002
+ background var(--yable-transition-fast);
1003
+ flex-shrink: 0;
1004
+ }
1005
+
1006
+ .yable-row-drag-handle:hover {
1007
+ color: var(--yable-text-primary);
1008
+ background: var(--yable-bg-row-hover);
1009
+ }
1010
+
1011
+ .yable-row-drag-handle:active,
1012
+ .yable-row-drag-handle--dragging {
1013
+ cursor: grabbing;
1014
+ color: var(--yable-accent);
1015
+ }
1016
+
1017
+ .yable-row-drag-cell {
1018
+ width: 32px;
1019
+ min-width: 32px;
1020
+ max-width: 32px;
1021
+ padding: 0 4px;
1022
+ text-align: center;
1023
+ }
1024
+
1025
+ .yable-row-drag-dragging {
1026
+ opacity: 0.4;
1027
+ background: var(--yable-bg-row-hover);
1028
+ }
1029
+
1030
+ .yable-row-drag-over-before {
1031
+ box-shadow: inset 0 2px 0 0 var(--yable-accent);
1032
+ }
1033
+
1034
+ .yable-row-drag-over-after {
1035
+ box-shadow: inset 0 -2px 0 0 var(--yable-accent);
1036
+ }
1037
+
1038
+ /* ============================================================================
1039
+ Tree Data (yable-tree-*)
1040
+ ============================================================================ */
1041
+
1042
+ .yable-tree-toggle {
1043
+ display: inline-flex;
1044
+ align-items: center;
1045
+ vertical-align: middle;
1046
+ white-space: nowrap;
1047
+ }
1048
+
1049
+ .yable-tree-toggle-btn {
1050
+ display: inline-flex;
1051
+ align-items: center;
1052
+ justify-content: center;
1053
+ width: 20px;
1054
+ height: 20px;
1055
+ padding: 0;
1056
+ border: none;
1057
+ background: none;
1058
+ cursor: pointer;
1059
+ color: var(--yable-text-secondary);
1060
+ border-radius: var(--yable-border-radius-sm);
1061
+ transition: transform var(--yable-transition),
1062
+ color var(--yable-transition-fast),
1063
+ background var(--yable-transition-fast);
1064
+ flex-shrink: 0;
1065
+ margin-right: 4px;
1066
+ }
1067
+
1068
+ .yable-tree-toggle-btn:hover {
1069
+ color: var(--yable-text-primary);
1070
+ background: var(--yable-bg-row-hover);
1071
+ }
1072
+
1073
+ .yable-tree-toggle-btn[data-expanded="true"] {
1074
+ transform: rotate(90deg);
1075
+ }
1076
+
1077
+ .yable-tree-chevron {
1078
+ display: block;
1079
+ }
1080
+
1081
+ .yable-tree-toggle-spacer {
1082
+ display: inline-block;
1083
+ width: 20px;
1084
+ height: 20px;
1085
+ flex-shrink: 0;
1086
+ margin-right: 4px;
1087
+ }
1088
+
1089
+ /* Tree depth visual indentation */
1090
+ .yable-tr[data-tree-depth="1"] .yable-tree-toggle {
1091
+ padding-left: 20px;
1092
+ }
1093
+
1094
+ .yable-tr[data-tree-depth="2"] .yable-tree-toggle {
1095
+ padding-left: 40px;
1096
+ }
1097
+
1098
+ .yable-tr[data-tree-depth="3"] .yable-tree-toggle {
1099
+ padding-left: 60px;
1100
+ }
1101
+
1102
+ .yable-tr[data-tree-depth="4"] .yable-tree-toggle {
1103
+ padding-left: 80px;
1104
+ }
1105
+
1106
+ .yable-tr[data-tree-depth="5"] .yable-tree-toggle {
1107
+ padding-left: 100px;
1108
+ }
1109
+
1110
+ /* ============================================================================
1111
+ Master/Detail (yable-detail-*)
1112
+ ============================================================================ */
1113
+
1114
+ .yable-detail-row {
1115
+ background: var(--yable-bg-row-expanded);
1116
+ }
1117
+
1118
+ .yable-detail-cell {
1119
+ padding: 0;
1120
+ border-bottom: var(--yable-border-width) solid var(--yable-border-color);
1121
+ }
1122
+
1123
+ .yable-detail-panel {
1124
+ padding: 16px var(--yable-cell-padding-x);
1125
+ }
1126
+
1127
+ .yable-detail-expand-icon {
1128
+ display: inline-flex;
1129
+ align-items: center;
1130
+ justify-content: center;
1131
+ width: 24px;
1132
+ height: 24px;
1133
+ padding: 0;
1134
+ border: none;
1135
+ background: none;
1136
+ cursor: pointer;
1137
+ color: var(--yable-text-secondary);
1138
+ border-radius: var(--yable-border-radius-sm);
1139
+ transition: transform var(--yable-transition),
1140
+ color var(--yable-transition-fast),
1141
+ background var(--yable-transition-fast);
1142
+ flex-shrink: 0;
1143
+ }
1144
+
1145
+ .yable-detail-expand-icon:hover {
1146
+ color: var(--yable-text-primary);
1147
+ background: var(--yable-bg-row-hover);
1148
+ }
1149
+
1150
+ .yable-detail-expand-icon--expanded {
1151
+ transform: rotate(180deg);
1152
+ color: var(--yable-accent);
1153
+ }
1154
+
1155
+ /* ============================================================================
1156
+ Pivot Mode (yable-pivot-*)
1157
+ ============================================================================ */
1158
+
1159
+ .yable-pivot-config {
1160
+ display: grid;
1161
+ grid-template-columns: 1fr 1fr;
1162
+ gap: 12px;
1163
+ padding: 12px var(--yable-cell-padding-x);
1164
+ border-bottom: var(--yable-border-width) solid var(--yable-border-color);
1165
+ background: var(--yable-bg-footer);
1166
+ }
1167
+
1168
+ .yable-pivot-zone {
1169
+ min-height: 60px;
1170
+ padding: 10px;
1171
+ border: 1px dashed var(--yable-border-color);
1172
+ border-radius: var(--yable-border-radius);
1173
+ background: var(--yable-bg);
1174
+ transition: border-color var(--yable-transition-fast),
1175
+ background var(--yable-transition-fast);
1176
+ }
1177
+
1178
+ .yable-pivot-zone:hover {
1179
+ border-color: var(--yable-border-color-strong);
1180
+ }
1181
+
1182
+ .yable-pivot-zone--available {
1183
+ grid-column: 1 / -1;
1184
+ }
1185
+
1186
+ .yable-pivot-zone-label {
1187
+ font-size: var(--yable-font-size-sm);
1188
+ font-weight: var(--yable-font-weight-semibold);
1189
+ color: var(--yable-text-secondary);
1190
+ text-transform: uppercase;
1191
+ letter-spacing: 0.05em;
1192
+ margin-bottom: 8px;
1193
+ }
1194
+
1195
+ .yable-pivot-zone-items {
1196
+ display: flex;
1197
+ flex-wrap: wrap;
1198
+ gap: 4px;
1199
+ }
1200
+
1201
+ .yable-pivot-zone-empty {
1202
+ font-size: var(--yable-font-size-sm);
1203
+ color: var(--yable-text-placeholder);
1204
+ font-style: italic;
1205
+ padding: 4px 0;
1206
+ }
1207
+
1208
+ .yable-pivot-field {
1209
+ display: inline-flex;
1210
+ align-items: center;
1211
+ gap: 4px;
1212
+ padding: 4px 8px;
1213
+ background: var(--yable-bg-row-hover);
1214
+ border: 1px solid var(--yable-border-color);
1215
+ border-radius: var(--yable-border-radius-sm);
1216
+ font-size: var(--yable-font-size-sm);
1217
+ color: var(--yable-text-primary);
1218
+ cursor: grab;
1219
+ user-select: none;
1220
+ transition: background var(--yable-transition-fast),
1221
+ box-shadow var(--yable-transition-fast),
1222
+ border-color var(--yable-transition-fast);
1223
+ }
1224
+
1225
+ .yable-pivot-field:hover {
1226
+ background: var(--yable-bg);
1227
+ box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
1228
+ border-color: var(--yable-border-color-strong);
1229
+ }
1230
+
1231
+ .yable-pivot-field:active {
1232
+ cursor: grabbing;
1233
+ }
1234
+
1235
+ .yable-pivot-field-label {
1236
+ white-space: nowrap;
1237
+ }
1238
+
1239
+ .yable-pivot-field-remove {
1240
+ display: inline-flex;
1241
+ align-items: center;
1242
+ justify-content: center;
1243
+ width: 16px;
1244
+ height: 16px;
1245
+ padding: 0;
1246
+ border: none;
1247
+ background: none;
1248
+ cursor: pointer;
1249
+ color: var(--yable-text-tertiary);
1250
+ font-size: 12px;
1251
+ line-height: 1;
1252
+ border-radius: 50%;
1253
+ transition: color var(--yable-transition-fast),
1254
+ background var(--yable-transition-fast);
1255
+ }
1256
+
1257
+ .yable-pivot-field-remove:hover {
1258
+ color: var(--yable-text-primary);
1259
+ background: var(--yable-border-color);
1260
+ }
1261
+
1262
+ .yable-pivot-agg-select {
1263
+ appearance: none;
1264
+ padding: 1px 4px;
1265
+ border: 1px solid var(--yable-border-color);
1266
+ border-radius: var(--yable-border-radius-sm);
1267
+ background: var(--yable-bg);
1268
+ font-size: 11px;
1269
+ color: var(--yable-text-secondary);
1270
+ cursor: pointer;
1271
+ }
1272
+
1273
+ .yable-pivot-field--value {
1274
+ background: color-mix(in srgb, var(--yable-accent) 10%, transparent);
1275
+ border-color: color-mix(in srgb, var(--yable-accent) 30%, transparent);
1276
+ }
1277
+
1278
+ /* Row editing state */
1279
+ .yable-tr--row-editing {
1280
+ background: var(--yable-bg-cell-editing);
1281
+ }
1282
+
1283
+ .yable-tr--row-editing .yable-td {
1284
+ border-color: color-mix(in srgb, var(--yable-accent) 20%, transparent);
1285
+ }
1286
+
1287
+ /* ── Formula Cell ────────────────────────────────────────────────────────── */
1288
+
1289
+ .yable-formula-bar {
1290
+ display: flex;
1291
+ align-items: center;
1292
+ gap: 8px;
1293
+ padding: 4px var(--yable-cell-padding-x);
1294
+ background: var(--yable-bg-header);
1295
+ border-bottom: var(--yable-border-width) solid var(--yable-border-color);
1296
+ font-family: 'SF Mono', 'Fira Code', 'Cascadia Code', monospace;
1297
+ font-size: var(--yable-font-size-sm);
1298
+ }
1299
+
1300
+ .yable-formula-bar-label {
1301
+ font-weight: var(--yable-font-weight-semibold);
1302
+ color: var(--yable-text-secondary);
1303
+ user-select: none;
1304
+ min-width: 24px;
1305
+ text-align: center;
1306
+ }
1307
+
1308
+ .yable-formula-bar-input {
1309
+ flex: 1;
1310
+ height: 24px;
1311
+ padding: 0 6px;
1312
+ background: var(--yable-input-bg);
1313
+ border: var(--yable-border-width) solid var(--yable-input-border);
1314
+ border-radius: var(--yable-input-border-radius);
1315
+ font-family: inherit;
1316
+ font-size: inherit;
1317
+ color: var(--yable-text-primary);
1318
+ outline: none;
1319
+ transition: border-color var(--yable-transition-fast),
1320
+ box-shadow var(--yable-transition-fast);
1321
+ }
1322
+
1323
+ .yable-formula-bar-input:focus {
1324
+ border-color: var(--yable-input-border-focus);
1325
+ box-shadow: var(--yable-input-shadow-focus);
1326
+ }
1327
+
1328
+ .yable-formula-cell {
1329
+ position: relative;
1330
+ }
1331
+
1332
+ .yable-formula-error {
1333
+ color: #ef4444;
1334
+ font-style: italic;
1335
+ font-size: var(--yable-font-size-sm);
1336
+ }
1337
+
1338
+ /* ── Virtual Scroll Container ────────────────────────────────────────────── */
1339
+
1340
+ .yable-virtual {
1341
+ position: relative;
1342
+ overflow: auto;
1343
+ }
1344
+
1345
+ .yable-virtual-inner {
1346
+ position: relative;
1347
+ width: 100%;
1348
+ }
1349
+
1350
+ .yable-virtual-row {
1351
+ position: absolute;
1352
+ left: 0;
1353
+ width: 100%;
1354
+ }
1355
+
1356
+ /* ============================================================================
1357
+ LOADING OVERLAY
1358
+ Semi-transparent overlay with animated spinner.
1359
+ Prefix: yable-overlay-*
1360
+ ============================================================================ */
1361
+
1362
+ .yable-overlay-loading {
1363
+ position: absolute;
1364
+ inset: 0;
1365
+ display: flex;
1366
+ align-items: center;
1367
+ justify-content: center;
1368
+ background: color-mix(in srgb, var(--yable-bg) 80%, transparent);
1369
+ z-index: var(--yable-z-overlay);
1370
+ backdrop-filter: blur(3px);
1371
+ -webkit-backdrop-filter: blur(3px);
1372
+ pointer-events: all;
1373
+ animation: yable-overlay-fade-in 200ms ease;
1374
+ }
1375
+
1376
+ @keyframes yable-overlay-fade-in {
1377
+ from { opacity: 0; }
1378
+ to { opacity: 1; }
1379
+ }
1380
+
1381
+ .yable-overlay-loading-content {
1382
+ display: flex;
1383
+ flex-direction: column;
1384
+ align-items: center;
1385
+ gap: 12px;
1386
+ }
1387
+
1388
+ .yable-overlay-spinner {
1389
+ color: var(--yable-accent);
1390
+ animation: yable-spin 0.75s linear infinite;
1391
+ }
1392
+
1393
+ .yable-overlay-loading-text {
1394
+ font-size: var(--yable-font-size-sm);
1395
+ color: var(--yable-text-secondary);
1396
+ font-weight: var(--yable-font-weight-medium);
1397
+ }
1398
+
1399
+ @keyframes yable-spin {
1400
+ from { transform: rotate(0deg); }
1401
+ to { transform: rotate(360deg); }
1402
+ }
1403
+
1404
+ /* ============================================================================
1405
+ NO-ROWS / EMPTY OVERLAY
1406
+ Prefix: yable-overlay-*
1407
+ ============================================================================ */
1408
+
1409
+ .yable-overlay-empty {
1410
+ display: flex;
1411
+ flex-direction: column;
1412
+ align-items: center;
1413
+ justify-content: center;
1414
+ padding: var(--yable-empty-padding);
1415
+ color: var(--yable-empty-text-color);
1416
+ text-align: center;
1417
+ min-height: 200px;
1418
+ }
1419
+
1420
+ .yable-overlay-empty-icon {
1421
+ width: 48px;
1422
+ height: 48px;
1423
+ margin-bottom: 16px;
1424
+ color: var(--yable-text-tertiary);
1425
+ opacity: 0.35;
1426
+ }
1427
+
1428
+ .yable-overlay-empty-message {
1429
+ font-size: 14px;
1430
+ font-weight: var(--yable-font-weight-medium);
1431
+ color: var(--yable-text-secondary);
1432
+ margin-bottom: 4px;
1433
+ }
1434
+
1435
+ .yable-overlay-empty-detail {
1436
+ font-size: var(--yable-font-size-sm);
1437
+ color: var(--yable-text-tertiary);
1438
+ max-width: 320px;
1439
+ line-height: 1.5;
1440
+ }
1441
+
1442
+ /* ============================================================================
1443
+ TOOLTIPS
1444
+ Prefix: yable-tooltip-*
1445
+ ============================================================================ */
1446
+
1447
+ .yable-tooltip {
1448
+ position: fixed;
1449
+ z-index: var(--yable-z-tooltip);
1450
+ pointer-events: none;
1451
+ animation: yable-tooltip-enter 150ms ease;
1452
+ }
1453
+
1454
+ .yable-tooltip-content {
1455
+ padding: 6px 12px;
1456
+ background: var(--yable-text-primary);
1457
+ color: var(--yable-bg);
1458
+ font-size: var(--yable-font-size-sm);
1459
+ font-weight: var(--yable-font-weight-medium);
1460
+ border-radius: 6px;
1461
+ white-space: nowrap;
1462
+ max-width: 300px;
1463
+ overflow: hidden;
1464
+ text-overflow: ellipsis;
1465
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
1466
+ line-height: 1.4;
1467
+ }
1468
+
1469
+ .yable-tooltip-arrow {
1470
+ position: absolute;
1471
+ width: 8px;
1472
+ height: 8px;
1473
+ background: var(--yable-text-primary);
1474
+ transform: rotate(45deg);
1475
+ }
1476
+
1477
+ .yable-tooltip-arrow--top {
1478
+ bottom: -3px;
1479
+ left: calc(50% - 4px);
1480
+ }
1481
+
1482
+ .yable-tooltip-arrow--bottom {
1483
+ top: -3px;
1484
+ left: calc(50% - 4px);
1485
+ }
1486
+
1487
+ .yable-tooltip-arrow--left {
1488
+ right: -3px;
1489
+ top: calc(50% - 4px);
1490
+ }
1491
+
1492
+ .yable-tooltip-arrow--right {
1493
+ left: -3px;
1494
+ top: calc(50% - 4px);
1495
+ }
1496
+
1497
+ @keyframes yable-tooltip-enter {
1498
+ from {
1499
+ opacity: 0;
1500
+ transform: translateY(4px) scale(0.98);
1501
+ }
1502
+ to {
1503
+ opacity: 1;
1504
+ transform: translateY(0) scale(1);
1505
+ }
1506
+ }
1507
+
1508
+ /* ============================================================================
1509
+ STATUS BAR
1510
+ Footer bar: row counts, selected counts, aggregations.
1511
+ Prefix: yable-status-*
1512
+ ============================================================================ */
1513
+
1514
+ .yable-status-bar {
1515
+ display: flex;
1516
+ align-items: center;
1517
+ justify-content: space-between;
1518
+ padding: 6px var(--yable-cell-padding-x);
1519
+ font-size: 11px;
1520
+ color: var(--yable-text-tertiary);
1521
+ border-top: var(--yable-border-width) solid var(--yable-border-color);
1522
+ background: var(--yable-bg-footer);
1523
+ position: sticky;
1524
+ bottom: 0;
1525
+ z-index: 5;
1526
+ letter-spacing: 0.01em;
1527
+ }
1528
+
1529
+ .yable-status-bar-section {
1530
+ display: flex;
1531
+ align-items: center;
1532
+ gap: 16px;
1533
+ }
1534
+
1535
+ .yable-status-panel {
1536
+ display: flex;
1537
+ align-items: center;
1538
+ gap: 4px;
1539
+ }
1540
+
1541
+ .yable-status-panel-icon {
1542
+ display: flex;
1543
+ align-items: center;
1544
+ opacity: 0.5;
1545
+ }
1546
+
1547
+ .yable-status-panel-label {
1548
+ color: var(--yable-text-tertiary);
1549
+ font-weight: var(--yable-font-weight-normal);
1550
+ }
1551
+
1552
+ .yable-status-panel-value {
1553
+ color: var(--yable-text-secondary);
1554
+ font-weight: var(--yable-font-weight-medium);
1555
+ font-variant-numeric: tabular-nums;
1556
+ }
1557
+
1558
+ /* ============================================================================
1559
+ CELL FLASHING
1560
+ Flash/fade animation on data change.
1561
+ Prefix: yable-flash-*
1562
+ ============================================================================ */
1563
+
1564
+ .yable-flash-cell {
1565
+ position: relative;
1566
+ animation-fill-mode: forwards;
1567
+ animation-timing-function: ease-out;
1568
+ }
1569
+
1570
+ .yable-flash-cell--up {
1571
+ animation-name: yable-flash-up;
1572
+ }
1573
+
1574
+ .yable-flash-cell--down {
1575
+ animation-name: yable-flash-down;
1576
+ }
1577
+
1578
+ .yable-flash-cell--change {
1579
+ animation-name: yable-flash-change;
1580
+ }
1581
+
1582
+ @keyframes yable-flash-up {
1583
+ 0% {
1584
+ background: var(--yable-flash-up-color);
1585
+ }
1586
+ 100% {
1587
+ background: transparent;
1588
+ }
1589
+ }
1590
+
1591
+ @keyframes yable-flash-down {
1592
+ 0% {
1593
+ background: var(--yable-flash-down-color);
1594
+ }
1595
+ 100% {
1596
+ background: transparent;
1597
+ }
1598
+ }
1599
+
1600
+ @keyframes yable-flash-change {
1601
+ 0% {
1602
+ background: var(--yable-flash-change-color);
1603
+ }
1604
+ 100% {
1605
+ background: transparent;
1606
+ }
1607
+ }
1608
+
1609
+ /* ============================================================================
1610
+ ROW ANIMATION
1611
+ Transitions on sort/filter/group changes.
1612
+ ============================================================================ */
1613
+
1614
+ @keyframes yable-row-fade-in {
1615
+ from {
1616
+ opacity: 0;
1617
+ transform: translateY(-8px);
1618
+ }
1619
+ to {
1620
+ opacity: 1;
1621
+ transform: translateY(0);
1622
+ }
1623
+ }
1624
+
1625
+ @keyframes yable-row-fade-out {
1626
+ from {
1627
+ opacity: 1;
1628
+ transform: translateY(0);
1629
+ }
1630
+ to {
1631
+ opacity: 0;
1632
+ transform: translateY(8px);
1633
+ }
1634
+ }
1635
+
1636
+ .yable-row-enter {
1637
+ opacity: 0;
1638
+ }
1639
+
1640
+ /* ============================================================================
1641
+ CONTEXT MENU
1642
+ Right-click menu with nested submenus.
1643
+ Prefix: yable-ctx-*
1644
+ ============================================================================ */
1645
+
1646
+ .yable-ctx-menu {
1647
+ min-width: 180px;
1648
+ max-width: 280px;
1649
+ padding: 4px;
1650
+ background: var(--yable-bg);
1651
+ border: var(--yable-border-width) solid var(--yable-border-color);
1652
+ border-radius: 8px;
1653
+ box-shadow: 0 8px 30px rgba(0, 0, 0, 0.12),
1654
+ 0 2px 8px rgba(0, 0, 0, 0.06);
1655
+ font-size: var(--yable-font-size-sm);
1656
+ animation: yable-ctx-appear 120ms ease;
1657
+ overflow: hidden;
1658
+ }
1659
+
1660
+ @media (prefers-color-scheme: dark) {
1661
+ :root:not([data-yable-theme="light"]) .yable-ctx-menu {
1662
+ box-shadow: 0 8px 30px rgba(0, 0, 0, 0.4),
1663
+ 0 2px 8px rgba(0, 0, 0, 0.2);
1664
+ }
1665
+ }
1666
+
1667
+ [data-yable-theme="dark"] .yable-ctx-menu {
1668
+ box-shadow: 0 8px 30px rgba(0, 0, 0, 0.4),
1669
+ 0 2px 8px rgba(0, 0, 0, 0.2);
1670
+ }
1671
+
1672
+ @keyframes yable-ctx-appear {
1673
+ from {
1674
+ opacity: 0;
1675
+ transform: scale(0.95);
1676
+ }
1677
+ to {
1678
+ opacity: 1;
1679
+ transform: scale(1);
1680
+ }
1681
+ }
1682
+
1683
+ .yable-ctx-item {
1684
+ display: flex;
1685
+ align-items: center;
1686
+ gap: 8px;
1687
+ padding: 7px 10px;
1688
+ border-radius: 5px;
1689
+ cursor: pointer;
1690
+ position: relative;
1691
+ user-select: none;
1692
+ outline: none;
1693
+ color: var(--yable-text-primary);
1694
+ transition: background var(--yable-transition-fast),
1695
+ color var(--yable-transition-fast);
1696
+ }
1697
+
1698
+ .yable-ctx-item:hover,
1699
+ .yable-ctx-item:focus-visible {
1700
+ background: var(--yable-bg-row-hover);
1701
+ }
1702
+
1703
+ .yable-ctx-item--disabled {
1704
+ opacity: 0.4;
1705
+ cursor: not-allowed;
1706
+ pointer-events: none;
1707
+ }
1708
+
1709
+ .yable-ctx-item--danger {
1710
+ color: #ef4444;
1711
+ }
1712
+
1713
+ .yable-ctx-item--danger:hover {
1714
+ background: rgba(239, 68, 68, 0.06);
1715
+ }
1716
+
1717
+ .yable-ctx-item-icon {
1718
+ display: flex;
1719
+ align-items: center;
1720
+ justify-content: center;
1721
+ width: 16px;
1722
+ height: 16px;
1723
+ flex-shrink: 0;
1724
+ color: var(--yable-text-tertiary);
1725
+ }
1726
+
1727
+ .yable-ctx-item-label {
1728
+ flex: 1;
1729
+ white-space: nowrap;
1730
+ overflow: hidden;
1731
+ text-overflow: ellipsis;
1732
+ }
1733
+
1734
+ .yable-ctx-item-shortcut {
1735
+ margin-left: auto;
1736
+ padding-left: 16px;
1737
+ font-size: 11px;
1738
+ color: var(--yable-text-tertiary);
1739
+ font-family: -apple-system, system-ui, sans-serif;
1740
+ letter-spacing: 0.02em;
1741
+ }
1742
+
1743
+ .yable-ctx-item-arrow {
1744
+ display: flex;
1745
+ align-items: center;
1746
+ margin-left: auto;
1747
+ color: var(--yable-text-tertiary);
1748
+ }
1749
+
1750
+ .yable-ctx-separator {
1751
+ height: 1px;
1752
+ margin: 4px 6px;
1753
+ background: var(--yable-border-color);
1754
+ }
1755
+
1756
+ .yable-ctx-submenu {
1757
+ position: absolute;
1758
+ left: 100%;
1759
+ top: -4px;
1760
+ margin-left: 2px;
1761
+ }
1762
+
1763
+ /* ============================================================================
1764
+ SIDEBAR / TOOL PANELS
1765
+ Slides in from right, tab interface.
1766
+ Prefix: yable-sidebar-*
1767
+ ============================================================================ */
1768
+
1769
+ .yable--sidebar-open {
1770
+ display: flex;
1771
+ }
1772
+
1773
+ .yable-sidebar {
1774
+ position: absolute;
1775
+ top: 0;
1776
+ right: 0;
1777
+ bottom: 0;
1778
+ width: 280px;
1779
+ background: var(--yable-bg);
1780
+ border-left: 1px solid var(--yable-border-color);
1781
+ z-index: calc(var(--yable-z-overlay) + 5);
1782
+ transform: translateX(100%);
1783
+ transition: transform var(--yable-transition-slow);
1784
+ display: flex;
1785
+ flex-direction: column;
1786
+ overflow: hidden;
1787
+ box-shadow: -4px 0 20px rgba(0, 0, 0, 0.08);
1788
+ }
1789
+
1790
+ .yable-sidebar--open {
1791
+ transform: translateX(0);
1792
+ }
1793
+
1794
+ .yable-sidebar-header {
1795
+ display: flex;
1796
+ align-items: center;
1797
+ justify-content: space-between;
1798
+ padding: 0 8px;
1799
+ border-bottom: 1px solid var(--yable-border-color);
1800
+ min-height: 44px;
1801
+ flex-shrink: 0;
1802
+ }
1803
+
1804
+ .yable-sidebar-tabs {
1805
+ display: flex;
1806
+ gap: 2px;
1807
+ }
1808
+
1809
+ .yable-sidebar-tab {
1810
+ display: flex;
1811
+ align-items: center;
1812
+ gap: 6px;
1813
+ padding: 8px 12px;
1814
+ border: none;
1815
+ background: none;
1816
+ color: var(--yable-text-tertiary);
1817
+ font-family: inherit;
1818
+ font-size: var(--yable-font-size-sm);
1819
+ font-weight: var(--yable-font-weight-medium);
1820
+ cursor: pointer;
1821
+ border-radius: 6px;
1822
+ transition: color var(--yable-transition-fast),
1823
+ background var(--yable-transition-fast);
1824
+ }
1825
+
1826
+ .yable-sidebar-tab:hover {
1827
+ color: var(--yable-text-primary);
1828
+ background: var(--yable-bg-row-hover);
1829
+ }
1830
+
1831
+ .yable-sidebar-tab--active {
1832
+ color: var(--yable-accent);
1833
+ background: var(--yable-accent-light);
1834
+ }
1835
+
1836
+ .yable-sidebar-close {
1837
+ display: flex;
1838
+ align-items: center;
1839
+ justify-content: center;
1840
+ width: 28px;
1841
+ height: 28px;
1842
+ border: none;
1843
+ background: none;
1844
+ color: var(--yable-text-tertiary);
1845
+ cursor: pointer;
1846
+ border-radius: 6px;
1847
+ transition: color var(--yable-transition-fast),
1848
+ background var(--yable-transition-fast);
1849
+ }
1850
+
1851
+ .yable-sidebar-close:hover {
1852
+ color: var(--yable-text-primary);
1853
+ background: var(--yable-bg-row-hover);
1854
+ }
1855
+
1856
+ .yable-sidebar-content {
1857
+ flex: 1;
1858
+ overflow-y: auto;
1859
+ overflow-x: hidden;
1860
+ }
1861
+
1862
+ /* Sidebar content scrollbar */
1863
+ .yable-sidebar-content::-webkit-scrollbar {
1864
+ width: 4px;
1865
+ }
1866
+
1867
+ .yable-sidebar-content::-webkit-scrollbar-track {
1868
+ background: transparent;
1869
+ }
1870
+
1871
+ .yable-sidebar-content::-webkit-scrollbar-thumb {
1872
+ background: var(--yable-border-color-strong);
1873
+ border-radius: 2px;
1874
+ }
1875
+
1876
+ .yable-sidebar-content {
1877
+ scrollbar-width: thin;
1878
+ scrollbar-color: var(--yable-border-color-strong) transparent;
1879
+ }
1880
+
1881
+ .yable-sidebar-panel {
1882
+ padding: 12px;
1883
+ }
1884
+
1885
+ .yable-sidebar-panel-search {
1886
+ margin-bottom: 12px;
1887
+ }
1888
+
1889
+ .yable-sidebar-search-input {
1890
+ width: 100%;
1891
+ height: 30px;
1892
+ padding: 0 10px;
1893
+ background: var(--yable-input-bg-hover);
1894
+ border: 1px solid transparent;
1895
+ border-radius: 6px;
1896
+ font-family: inherit;
1897
+ font-size: var(--yable-font-size-sm);
1898
+ color: var(--yable-text-primary);
1899
+ outline: none;
1900
+ transition: border-color var(--yable-transition-fast),
1901
+ background var(--yable-transition-fast),
1902
+ box-shadow var(--yable-transition-fast);
1903
+ }
1904
+
1905
+ .yable-sidebar-search-input:focus {
1906
+ border-color: var(--yable-accent);
1907
+ background: var(--yable-input-bg-focus);
1908
+ box-shadow: var(--yable-input-shadow-focus);
1909
+ }
1910
+
1911
+ .yable-sidebar-search-input::placeholder {
1912
+ color: var(--yable-text-placeholder);
1913
+ }
1914
+
1915
+ .yable-sidebar-panel-actions {
1916
+ display: flex;
1917
+ gap: 8px;
1918
+ margin-bottom: 12px;
1919
+ }
1920
+
1921
+ .yable-sidebar-action-btn {
1922
+ padding: 4px 10px;
1923
+ border: 1px solid var(--yable-border-color);
1924
+ border-radius: 5px;
1925
+ background: none;
1926
+ color: var(--yable-text-secondary);
1927
+ font-family: inherit;
1928
+ font-size: 11px;
1929
+ font-weight: var(--yable-font-weight-medium);
1930
+ cursor: pointer;
1931
+ transition: color var(--yable-transition-fast),
1932
+ background var(--yable-transition-fast),
1933
+ border-color var(--yable-transition-fast);
1934
+ }
1935
+
1936
+ .yable-sidebar-action-btn:hover {
1937
+ background: var(--yable-bg-row-hover);
1938
+ border-color: var(--yable-border-color-strong);
1939
+ }
1940
+
1941
+ .yable-sidebar-action-btn--danger {
1942
+ color: #ef4444;
1943
+ border-color: rgba(239, 68, 68, 0.2);
1944
+ }
1945
+
1946
+ .yable-sidebar-action-btn--danger:hover {
1947
+ background: rgba(239, 68, 68, 0.06);
1948
+ }
1949
+
1950
+ .yable-sidebar-column-list {
1951
+ display: flex;
1952
+ flex-direction: column;
1953
+ gap: 2px;
1954
+ }
1955
+
1956
+ .yable-sidebar-column-item {
1957
+ display: flex;
1958
+ align-items: center;
1959
+ gap: 6px;
1960
+ padding: 6px 8px;
1961
+ border-radius: 6px;
1962
+ cursor: grab;
1963
+ transition: background var(--yable-transition-fast);
1964
+ }
1965
+
1966
+ .yable-sidebar-column-item:hover {
1967
+ background: var(--yable-bg-row-hover);
1968
+ }
1969
+
1970
+ .yable-sidebar-column-item--dragging {
1971
+ opacity: 0.4;
1972
+ background: var(--yable-accent-light);
1973
+ }
1974
+
1975
+ .yable-sidebar-drag-handle {
1976
+ display: flex;
1977
+ align-items: center;
1978
+ cursor: grab;
1979
+ flex-shrink: 0;
1980
+ color: var(--yable-text-tertiary);
1981
+ margin-right: 4px;
1982
+ }
1983
+
1984
+ .yable-sidebar-column-label {
1985
+ display: flex;
1986
+ align-items: center;
1987
+ gap: 8px;
1988
+ flex: 1;
1989
+ min-width: 0;
1990
+ cursor: pointer;
1991
+ font-size: var(--yable-font-size-sm);
1992
+ color: var(--yable-text-primary);
1993
+ }
1994
+
1995
+ .yable-sidebar-column-label span {
1996
+ overflow: hidden;
1997
+ text-overflow: ellipsis;
1998
+ white-space: nowrap;
1999
+ }
2000
+
2001
+ /* Filters panel */
2002
+ .yable-sidebar-panel-header {
2003
+ display: flex;
2004
+ align-items: center;
2005
+ justify-content: space-between;
2006
+ margin-bottom: 12px;
2007
+ }
2008
+
2009
+ .yable-sidebar-panel-title {
2010
+ font-size: var(--yable-font-size-sm);
2011
+ font-weight: var(--yable-font-weight-semibold);
2012
+ color: var(--yable-text-secondary);
2013
+ }
2014
+
2015
+ .yable-sidebar-empty {
2016
+ display: flex;
2017
+ flex-direction: column;
2018
+ align-items: center;
2019
+ gap: 8px;
2020
+ padding: 32px 16px;
2021
+ color: var(--yable-text-tertiary);
2022
+ font-size: var(--yable-font-size-sm);
2023
+ }
2024
+
2025
+ .yable-sidebar-filter-list {
2026
+ display: flex;
2027
+ flex-direction: column;
2028
+ gap: 6px;
2029
+ }
2030
+
2031
+ .yable-sidebar-filter-item {
2032
+ display: flex;
2033
+ align-items: center;
2034
+ justify-content: space-between;
2035
+ padding: 8px 10px;
2036
+ background: var(--yable-bg-row-hover);
2037
+ border-radius: 6px;
2038
+ gap: 8px;
2039
+ transition: background var(--yable-transition-fast);
2040
+ }
2041
+
2042
+ .yable-sidebar-filter-item:hover {
2043
+ background: var(--yable-bg-row-alt);
2044
+ }
2045
+
2046
+ .yable-sidebar-filter-info {
2047
+ display: flex;
2048
+ flex-direction: column;
2049
+ gap: 2px;
2050
+ min-width: 0;
2051
+ }
2052
+
2053
+ .yable-sidebar-filter-column {
2054
+ font-size: 11px;
2055
+ font-weight: var(--yable-font-weight-semibold);
2056
+ color: var(--yable-text-secondary);
2057
+ text-transform: uppercase;
2058
+ letter-spacing: 0.03em;
2059
+ }
2060
+
2061
+ .yable-sidebar-filter-value {
2062
+ font-size: var(--yable-font-size-sm);
2063
+ color: var(--yable-text-primary);
2064
+ overflow: hidden;
2065
+ text-overflow: ellipsis;
2066
+ white-space: nowrap;
2067
+ }
2068
+
2069
+ .yable-sidebar-filter-remove {
2070
+ display: flex;
2071
+ align-items: center;
2072
+ justify-content: center;
2073
+ width: 22px;
2074
+ height: 22px;
2075
+ border: none;
2076
+ background: none;
2077
+ color: var(--yable-text-tertiary);
2078
+ cursor: pointer;
2079
+ border-radius: 4px;
2080
+ flex-shrink: 0;
2081
+ transition: color var(--yable-transition-fast),
2082
+ background var(--yable-transition-fast);
2083
+ }
2084
+
2085
+ .yable-sidebar-filter-remove:hover {
2086
+ color: #ef4444;
2087
+ background: rgba(239, 68, 68, 0.08);
2088
+ }
2089
+
2090
+ /* ============================================================================
2091
+ PRINT LAYOUT
2092
+ Print-optimized CSS.
2093
+ Prefix: yable-print-*
2094
+ ============================================================================ */
2095
+
2096
+ .yable-print-layout {
2097
+ display: none;
2098
+ }
2099
+
2100
+ .yable-print-header {
2101
+ display: flex;
2102
+ align-items: baseline;
2103
+ justify-content: space-between;
2104
+ margin-bottom: 16px;
2105
+ }
2106
+
2107
+ .yable-print-title {
2108
+ font-size: 18px;
2109
+ font-weight: 600;
2110
+ margin: 0;
2111
+ }
2112
+
2113
+ .yable-print-timestamp {
2114
+ font-size: 11px;
2115
+ color: #666;
2116
+ }
2117
+
2118
+ .yable-print-table {
2119
+ width: 100%;
2120
+ border-collapse: collapse;
2121
+ font-size: 11px;
2122
+ }
2123
+
2124
+ .yable-print-table th {
2125
+ text-align: left;
2126
+ padding: 6px 8px;
2127
+ border-bottom: 2px solid #333;
2128
+ font-weight: 600;
2129
+ font-size: 10px;
2130
+ text-transform: uppercase;
2131
+ letter-spacing: 0.04em;
2132
+ }
2133
+
2134
+ .yable-print-table td {
2135
+ padding: 5px 8px;
2136
+ border-bottom: 1px solid #ddd;
2137
+ }
2138
+
2139
+ .yable-print-footer {
2140
+ margin-top: 12px;
2141
+ font-size: 10px;
2142
+ color: #999;
2143
+ }
2144
+
2145
+ /* @media print rules */
2146
+ @media print {
2147
+ /* Hide UI-only elements */
2148
+ .yable-pagination,
2149
+ .yable-global-filter,
2150
+ .yable-sidebar,
2151
+ .yable-ctx-menu,
2152
+ .yable-status-bar,
2153
+ .yable-overlay-loading,
2154
+ .yable-resize-handle,
2155
+ .yable-fill-handle,
2156
+ .yable-tooltip {
2157
+ display: none !important;
2158
+ }
2159
+
2160
+ /* Remove sticky positioning */
2161
+ .yable-print-mode .yable-th,
2162
+ .yable-print-mode .yable-td {
2163
+ position: static !important;
2164
+ }
2165
+
2166
+ .yable-print-mode .yable-thead .yable-th {
2167
+ position: static !important;
2168
+ }
2169
+
2170
+ /* Show all rows, remove decorative styles */
2171
+ .yable-print-mode {
2172
+ max-height: none !important;
2173
+ overflow: visible !important;
2174
+ border: none !important;
2175
+ box-shadow: none !important;
2176
+ border-radius: 0 !important;
2177
+ }
2178
+
2179
+ .yable-print-mode .yable-table {
2180
+ width: 100%;
2181
+ }
2182
+
2183
+ /* Repeat header on every page */
2184
+ .yable-print-mode .yable-thead {
2185
+ display: table-header-group;
2186
+ }
2187
+
2188
+ /* Print layout becomes visible */
2189
+ .yable-print-layout {
2190
+ display: block;
2191
+ }
2192
+
2193
+ /* Avoid breaking rows */
2194
+ .yable-print-mode .yable-tr {
2195
+ page-break-inside: avoid;
2196
+ }
2197
+
2198
+ .yable-print-mode .yable-th {
2199
+ background: #f5f5f5 !important;
2200
+ -webkit-print-color-adjust: exact;
2201
+ print-color-adjust: exact;
2202
+ border-bottom: 2px solid #000 !important;
2203
+ }
2204
+
2205
+ .yable-print-mode .yable-td {
2206
+ border-bottom: 1px solid #ccc !important;
2207
+ }
2208
+
2209
+ /* Reset colors for print */
2210
+ .yable-print-mode {
2211
+ color: #000 !important;
2212
+ background: #fff !important;
2213
+ }
2214
+
2215
+ .yable-print-mode .yable-tr[data-selected="true"] {
2216
+ box-shadow: none !important;
2217
+ background: transparent !important;
2218
+ }
2219
+ }
2220
+
2221
+ /* ============================================================================
2222
+ RTL SUPPORT
2223
+ Mirror layout for right-to-left languages.
2224
+ ============================================================================ */
2225
+
2226
+ .yable--rtl .yable-th {
2227
+ text-align: right;
2228
+ }
2229
+
2230
+ .yable--rtl .yable-resize-handle {
2231
+ right: auto;
2232
+ left: 0;
2233
+ }
2234
+
2235
+ .yable--rtl .yable-tr[data-selected="true"] {
2236
+ box-shadow: inset -2px 0 0 0 var(--yable-accent);
2237
+ }
2238
+
2239
+ .yable--rtl .yable-sidebar {
2240
+ right: auto;
2241
+ left: 0;
2242
+ border-left: none;
2243
+ border-right: 1px solid var(--yable-border-color);
2244
+ transform: translateX(-100%);
2245
+ box-shadow: 4px 0 20px rgba(0, 0, 0, 0.08);
2246
+ }
2247
+
2248
+ .yable--rtl .yable-sidebar--open {
2249
+ transform: translateX(0);
2250
+ }
2251
+
2252
+ /* ============================================================================
2253
+ ERROR STATE
2254
+ ============================================================================ */
2255
+
2256
+ .yable-error-cell {
2257
+ color: #ef4444;
2258
+ font-style: italic;
2259
+ font-size: var(--yable-font-size-sm);
2260
+ }
2261
+
2262
+ /* ============================================================================
2263
+ ADDITIONAL CLASSES
2264
+ Used by React components — structural/modifier variants.
2265
+ ============================================================================ */
2266
+
2267
+ /* Context menu extras */
2268
+ .yable-ctx-backdrop {
2269
+ position: fixed;
2270
+ inset: 0;
2271
+ z-index: calc(var(--yable-z-context-menu) - 1);
2272
+ }
2273
+
2274
+ .yable-ctx-item--has-submenu {
2275
+ padding-right: 28px;
2276
+ }
2277
+
2278
+ .yable-ctx-item--submenu-open {
2279
+ background: var(--yable-bg-row-hover);
2280
+ }
2281
+
2282
+ .yable-ctx-menu--animated {
2283
+ animation: yable-ctx-appear 120ms ease;
2284
+ }
2285
+
2286
+ /* Global filter extras */
2287
+ .yable-global-filter--has-value .yable-global-filter-input {
2288
+ padding-right: 32px;
2289
+ }
2290
+
2291
+ .yable-global-filter-icon {
2292
+ position: absolute;
2293
+ left: 10px;
2294
+ top: 50%;
2295
+ transform: translateY(-50%);
2296
+ pointer-events: none;
2297
+ color: var(--yable-text-tertiary);
2298
+ display: flex;
2299
+ align-items: center;
2300
+ }
2301
+
2302
+ /* Pagination extras */
2303
+ .yable-pagination-btn--active {
2304
+ background: var(--yable-pagination-button-bg-active);
2305
+ color: var(--yable-pagination-button-text-active);
2306
+ border-color: var(--yable-pagination-button-bg-active);
2307
+ box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
2308
+ }
2309
+
2310
+ .yable-pagination-btn--nav {
2311
+ background: transparent;
2312
+ }
2313
+
2314
+ .yable-pagination-btn--page {
2315
+ font-variant-numeric: tabular-nums;
2316
+ }
2317
+
2318
+ .yable-pagination-ellipsis {
2319
+ display: inline-flex;
2320
+ align-items: center;
2321
+ justify-content: center;
2322
+ min-width: var(--yable-pagination-button-size);
2323
+ height: var(--yable-pagination-button-size);
2324
+ color: var(--yable-text-tertiary);
2325
+ font-size: var(--yable-font-size-sm);
2326
+ user-select: none;
2327
+ letter-spacing: 0.1em;
2328
+ }
2329
+
2330
+ .yable-pagination-info-text {
2331
+ color: var(--yable-text-tertiary);
2332
+ font-size: var(--yable-font-size-sm);
2333
+ font-variant-numeric: tabular-nums;
2334
+ }
2335
+
2336
+ .yable-pagination-select-wrapper {
2337
+ display: flex;
2338
+ align-items: center;
2339
+ gap: 6px;
2340
+ position: relative;
2341
+ }
2342
+
2343
+ .yable-pagination-select-icon {
2344
+ display: flex;
2345
+ align-items: center;
2346
+ color: var(--yable-text-tertiary);
2347
+ pointer-events: none;
2348
+ }
2349
+
2350
+ /* Pivot zone values */
2351
+ .yable-pivot-zone--values {
2352
+ border-color: color-mix(in srgb, var(--yable-accent) 30%, transparent);
2353
+ background: color-mix(in srgb, var(--yable-accent) 3%, var(--yable-bg));
2354
+ }
2355
+
2356
+ /* Status bar section variants */
2357
+ .yable-status-bar-left {
2358
+ display: flex;
2359
+ align-items: center;
2360
+ gap: 16px;
2361
+ }
2362
+
2363
+ .yable-status-bar-center {
2364
+ display: flex;
2365
+ align-items: center;
2366
+ gap: 16px;
2367
+ }
2368
+
2369
+ .yable-status-bar-right {
2370
+ display: flex;
2371
+ align-items: center;
2372
+ gap: 16px;
2373
+ }
2374
+
2375
+ .yable-status-bar-divider {
2376
+ width: 1px;
2377
+ height: 14px;
2378
+ background: var(--yable-border-color);
2379
+ }
2380
+
2381
+ /* Sidebar panel variants */
2382
+ .yable-sidebar-columns,
2383
+ .yable-sidebar-filters {
2384
+ /* These are semantic class hooks; layout comes from .yable-sidebar-panel */
2385
+ }
2386
+
2387
+ /* Tooltip position variants */
2388
+ .yable-tooltip--top,
2389
+ .yable-tooltip--bottom,
2390
+ .yable-tooltip--left,
2391
+ .yable-tooltip--right {
2392
+ /* Positioned via JS; these are hooks for direction-aware animations */
2393
+ }
2394
+
2395
+ .yable-tooltip-arrow-svg {
2396
+ position: absolute;
2397
+ display: block;
2398
+ color: var(--yable-text-primary);
2399
+ }
2400
+
2401
+ /* Virtual scroll */
2402
+ .yable-virtual-scroll-container {
2403
+ position: relative;
2404
+ overflow: auto;
2405
+ will-change: transform;
2406
+ }
2407
+
2408
+ .yable-virtual-scroll-container::-webkit-scrollbar {
2409
+ width: 6px;
2410
+ height: 6px;
2411
+ }
2412
+
2413
+ .yable-virtual-scroll-container::-webkit-scrollbar-track {
2414
+ background: transparent;
2415
+ }
2416
+
2417
+ .yable-virtual-scroll-container::-webkit-scrollbar-thumb {
2418
+ background: var(--yable-border-color-strong);
2419
+ border-radius: 3px;
2420
+ }
2421
+
2422
+ .yable-virtual-scroll-container::-webkit-scrollbar-corner {
2423
+ background: transparent;
2424
+ }
2425
+
2426
+ .yable-virtual-scroll-container {
2427
+ scrollbar-width: thin;
2428
+ scrollbar-color: var(--yable-border-color-strong) transparent;
2429
+ }
2430
+
2431
+ .yable-virtual-spacer {
2432
+ width: 100%;
2433
+ pointer-events: none;
2434
+ }
2435
+
2436
+ /* ============================================================================
2437
+ Display Cell Types — Styled cell primitives for common data patterns.
2438
+ These use theme tokens so they adapt to any theme automatically.
2439
+ ============================================================================ */
2440
+
2441
+ /* ── CellBadge ──────────────────────────────────────────────────────────── */
2442
+
2443
+ .yable-cell-badge {
2444
+ display: inline-flex;
2445
+ align-items: center;
2446
+ padding: 2px 8px;
2447
+ border-radius: 4px;
2448
+ font-size: 0.8em;
2449
+ font-weight: 500;
2450
+ letter-spacing: 0.02em;
2451
+ line-height: 1.4;
2452
+ white-space: nowrap;
2453
+ }
2454
+
2455
+ .yable-cell-badge--soft.yable-cell-badge--default { background: var(--yable-bg-hover); color: var(--yable-text-secondary); }
2456
+ .yable-cell-badge--soft.yable-cell-badge--accent { background: var(--yable-accent-bg, rgba(99, 102, 241, 0.1)); color: var(--yable-accent); }
2457
+ .yable-cell-badge--soft.yable-cell-badge--success { background: rgba(52, 211, 153, 0.1); color: #34d399; }
2458
+ .yable-cell-badge--soft.yable-cell-badge--warning { background: rgba(251, 191, 36, 0.1); color: #fbbf24; }
2459
+ .yable-cell-badge--soft.yable-cell-badge--danger { background: rgba(248, 113, 113, 0.1); color: #f87171; }
2460
+ .yable-cell-badge--soft.yable-cell-badge--info { background: rgba(56, 189, 248, 0.1); color: #38bdf8; }
2461
+
2462
+ .yable-cell-badge--solid.yable-cell-badge--default { background: var(--yable-text-secondary); color: var(--yable-bg); }
2463
+ .yable-cell-badge--solid.yable-cell-badge--accent { background: var(--yable-accent); color: #fff; }
2464
+ .yable-cell-badge--solid.yable-cell-badge--success { background: #34d399; color: #0a2e1f; }
2465
+ .yable-cell-badge--solid.yable-cell-badge--warning { background: #fbbf24; color: #422006; }
2466
+ .yable-cell-badge--solid.yable-cell-badge--danger { background: #f87171; color: #2a0a0a; }
2467
+ .yable-cell-badge--solid.yable-cell-badge--info { background: #38bdf8; color: #082f49; }
2468
+
2469
+ .yable-cell-badge--outline { background: transparent; border: 1px solid currentColor; }
2470
+
2471
+ /* ── CellCurrency ───────────────────────────────────────────────────────── */
2472
+
2473
+ .yable-cell-currency {
2474
+ font-variant-numeric: tabular-nums;
2475
+ font-weight: 500;
2476
+ text-align: right;
2477
+ white-space: nowrap;
2478
+ }
2479
+
2480
+ .yable-cell-currency--positive { color: #34d399; }
2481
+ .yable-cell-currency--negative { color: #f87171; }
2482
+
2483
+ /* ── CellStatus ─────────────────────────────────────────────────────────── */
2484
+
2485
+ .yable-cell-status {
2486
+ display: inline-flex;
2487
+ align-items: center;
2488
+ gap: 6px;
2489
+ font-size: 0.85em;
2490
+ letter-spacing: 0.04em;
2491
+ text-transform: uppercase;
2492
+ white-space: nowrap;
2493
+ }
2494
+
2495
+ .yable-cell-status::before {
2496
+ content: '';
2497
+ width: 6px;
2498
+ height: 6px;
2499
+ border-radius: 50%;
2500
+ flex-shrink: 0;
2501
+ }
2502
+
2503
+ .yable-cell-status--success { color: #34d399; }
2504
+ .yable-cell-status--success::before { background: #34d399; }
2505
+ .yable-cell-status--warning { color: #fbbf24; }
2506
+ .yable-cell-status--warning::before { background: #fbbf24; }
2507
+ .yable-cell-status--danger { color: #f87171; }
2508
+ .yable-cell-status--danger::before { background: #f87171; }
2509
+ .yable-cell-status--info { color: #38bdf8; }
2510
+ .yable-cell-status--info::before { background: #38bdf8; }
2511
+ .yable-cell-status--default { color: var(--yable-text-secondary); }
2512
+ .yable-cell-status--default::before { background: var(--yable-text-secondary); }
2513
+
2514
+ /* ── CellNumeric ────────────────────────────────────────────────────────── */
2515
+
2516
+ .yable-cell-numeric {
2517
+ font-variant-numeric: tabular-nums;
2518
+ text-align: right;
2519
+ white-space: nowrap;
2520
+ }
2521
+
2522
+ .yable-cell-numeric__unit {
2523
+ margin-left: 2px;
2524
+ font-size: 0.85em;
2525
+ color: var(--yable-text-secondary);
2526
+ }
2527
+
2528
+ .yable-cell-numeric--positive { color: #34d399; }
2529
+ .yable-cell-numeric--negative { color: #f87171; }
2530
+
2531
+ /* ── CellRating ─────────────────────────────────────────────────────────── */
2532
+
2533
+ .yable-cell-rating {
2534
+ white-space: nowrap;
2535
+ letter-spacing: 2px;
2536
+ font-size: 1.1em;
2537
+ line-height: 1;
2538
+ }
2539
+
2540
+ .yable-cell-rating__filled {
2541
+ color: #fbbf24;
2542
+ }
2543
+
2544
+ .yable-cell-rating__empty {
2545
+ color: var(--yable-border-color-strong);
2546
+ }
2547
+
2548
+ /* ── CellBoolean ────────────────────────────────────────────────────────── */
2549
+
2550
+ .yable-cell-boolean {
2551
+ display: inline-flex;
2552
+ align-items: center;
2553
+ gap: 6px;
2554
+ font-size: 0.85em;
2555
+ letter-spacing: 0.04em;
2556
+ text-transform: uppercase;
2557
+ white-space: nowrap;
2558
+ }
2559
+
2560
+ .yable-cell-boolean--dot::before {
2561
+ content: '';
2562
+ width: 6px;
2563
+ height: 6px;
2564
+ border-radius: 50%;
2565
+ flex-shrink: 0;
2566
+ }
2567
+
2568
+ .yable-cell-boolean--success { color: #34d399; }
2569
+ .yable-cell-boolean--success.yable-cell-boolean--dot::before { background: #34d399; }
2570
+ .yable-cell-boolean--danger { color: #f87171; }
2571
+ .yable-cell-boolean--danger.yable-cell-boolean--dot::before { background: #f87171; }
2572
+
2573
+ .yable-cell-boolean--badge {
2574
+ padding: 2px 8px;
2575
+ border-radius: 4px;
2576
+ font-weight: 500;
2577
+ }
2578
+
2579
+ .yable-cell-boolean--badge.yable-cell-boolean--success { background: rgba(52, 211, 153, 0.1); }
2580
+ .yable-cell-boolean--badge.yable-cell-boolean--danger { background: rgba(248, 113, 113, 0.1); }
2581
+
2582
+ /* ── CellProgress ───────────────────────────────────────────────────────── */
2583
+
2584
+ .yable-cell-progress {
2585
+ display: inline-flex;
2586
+ align-items: center;
2587
+ gap: 8px;
2588
+ width: 100%;
2589
+ min-width: 60px;
2590
+ }
2591
+
2592
+ .yable-cell-progress__track {
2593
+ flex: 1;
2594
+ height: 6px;
2595
+ border-radius: 3px;
2596
+ background: var(--yable-bg-hover);
2597
+ overflow: hidden;
2598
+ }
2599
+
2600
+ .yable-cell-progress__fill {
2601
+ display: block;
2602
+ height: 100%;
2603
+ border-radius: 3px;
2604
+ transition: width 200ms ease;
2605
+ }
2606
+
2607
+ .yable-cell-progress--accent .yable-cell-progress__fill { background: var(--yable-accent); }
2608
+ .yable-cell-progress--default .yable-cell-progress__fill { background: var(--yable-text-secondary); }
2609
+ .yable-cell-progress--success .yable-cell-progress__fill { background: #34d399; }
2610
+ .yable-cell-progress--warning .yable-cell-progress__fill { background: #fbbf24; }
2611
+ .yable-cell-progress--danger .yable-cell-progress__fill { background: #f87171; }
2612
+
2613
+ .yable-cell-progress__label {
2614
+ font-variant-numeric: tabular-nums;
2615
+ font-size: 0.8em;
2616
+ color: var(--yable-text-secondary);
2617
+ min-width: 32px;
2618
+ text-align: right;
2619
+ }
2620
+
2621
+ /* ── CellDate ───────────────────────────────────────────────────────────── */
2622
+
2623
+ .yable-cell-date {
2624
+ white-space: nowrap;
2625
+ color: var(--yable-text-secondary);
2626
+ }
2627
+
2628
+ /* ── CellLink ───────────────────────────────────────────────────────────── */
2629
+
2630
+ .yable-cell-link {
2631
+ color: var(--yable-accent);
2632
+ text-decoration: none;
2633
+ transition: opacity 120ms ease;
2634
+ }
2635
+
2636
+ .yable-cell-link:hover {
2637
+ opacity: 0.8;
2638
+ text-decoration: underline;
2639
+ }
2640
+
2641
+ .yable-cell-link__icon {
2642
+ margin-left: 3px;
2643
+ font-size: 0.85em;
2644
+ }
2645
+
2646
+ /* ─────────────────────────────────────────────────────────────────────────
2647
+ * Async commit / cell status (Task #10)
2648
+ * ─────────────────────────────────────────────────────────────────────── */
2649
+
2650
+ .yable-td[data-cell-status='pending'] {
2651
+ opacity: var(--yable-cell-pending-opacity);
2652
+ cursor: var(--yable-cell-pending-cursor);
2653
+ }
2654
+
2655
+ .yable-td[data-cell-status='error'] {
2656
+ box-shadow: inset 0 0 0 1px var(--yable-cell-error-border-color);
2657
+ background: var(--yable-cell-error-bg);
2658
+ position: relative;
2659
+ }
2660
+
2661
+ .yable-td[data-cell-status='conflict'] {
2662
+ box-shadow: inset 0 0 0 1px var(--yable-cell-conflict-border-color);
2663
+ background: var(--yable-cell-conflict-bg);
2664
+ position: relative;
2665
+ }
2666
+
2667
+ .yable-cell-status-badge {
2668
+ position: absolute;
2669
+ top: 4px;
2670
+ right: 4px;
2671
+ display: inline-flex;
2672
+ align-items: center;
2673
+ gap: 2px;
2674
+ z-index: 2;
2675
+ font-size: 11px;
2676
+ line-height: 1;
2677
+ }
2678
+
2679
+ .yable-cell-status-badge button {
2680
+ width: var(--yable-cell-status-badge-size);
2681
+ height: var(--yable-cell-status-badge-size);
2682
+ padding: 0;
2683
+ display: inline-flex;
2684
+ align-items: center;
2685
+ justify-content: center;
2686
+ border: 1px solid transparent;
2687
+ border-radius: 4px;
2688
+ background: var(--yable-bg, #fff);
2689
+ cursor: pointer;
2690
+ font-size: 12px;
2691
+ line-height: 1;
2692
+ }
2693
+
2694
+ .yable-cell-status-badge button:hover {
2695
+ background: var(--yable-bg-hover, #f5f5f5);
2696
+ }
2697
+
2698
+ .yable-cell-status-badge--error button {
2699
+ color: var(--yable-cell-error-icon-color);
2700
+ border-color: var(--yable-cell-error-border-color);
2701
+ }
2702
+
2703
+ .yable-cell-status-badge--conflict button {
2704
+ color: var(--yable-cell-conflict-icon-color);
2705
+ border-color: var(--yable-cell-conflict-border-color);
2706
+ }