@ceebee/ui 0.5.2 → 1.0.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/styles.css CHANGED
@@ -11,6 +11,7 @@
11
11
  --cb-space-7: 3rem;
12
12
  --cb-space-8: 4rem;
13
13
 
14
+ --cb-radius-none: 0;
14
15
  --cb-radius-sm: 0.5rem;
15
16
  --cb-radius-md: 0.875rem;
16
17
  --cb-radius-lg: 1.25rem;
@@ -61,7 +62,7 @@
61
62
  }
62
63
 
63
64
  /* tokens/skin.css */
64
- /* Skin tokens: the default Ceebee skin. A Skin file rewrites only these (ADR 0002).
65
+ /* Skin tokens: the default Ceebee skin. A Skin file rewrites only these.
65
66
  Light is defined on bare :root so no colour has its only definition inside a media query. */
66
67
  :root {
67
68
  --cb-hue-brand: 274;
@@ -250,7 +251,7 @@ html, body { background: var(--cb-bg); color: var(--cb-fg); }
250
251
  }
251
252
 
252
253
  /* tokens/motion.css */
253
- /* Motion tokens. A component reads these; it never writes a duration (ADR 0004). */
254
+ /* Motion tokens. A component reads these; it never writes a duration. */
254
255
  :root {
255
256
  --cb-duration-instant: 80ms;
256
257
  --cb-duration-fast: 140ms;
@@ -271,43 +272,6 @@ html, body { background: var(--cb-bg); color: var(--cb-fg); }
271
272
  :root { --cb-motion-scale: 0; }
272
273
  }
273
274
 
274
- /* foundation/divider.css */
275
- .cb-divider {
276
- border: 0;
277
- border-top: var(--cb-border-width) solid var(--cb-border);
278
- margin: var(--cb-space-4) 0;
279
- }
280
-
281
- .cb-divider--vertical {
282
- display: inline-block;
283
- align-self: stretch;
284
- width: 0;
285
- min-height: 1em;
286
- margin: 0 var(--cb-space-3);
287
- border-top: 0;
288
- border-inline-start: var(--cb-border-width) solid var(--cb-border);
289
- }
290
-
291
- .cb-divider--labelled {
292
- display: flex;
293
- align-items: center;
294
- gap: var(--cb-space-3);
295
- border-top: 0;
296
- }
297
- .cb-divider--labelled::before,
298
- .cb-divider--labelled::after {
299
- content: '';
300
- flex: 1;
301
- border-top: var(--cb-border-width) solid var(--cb-border);
302
- }
303
- .cb-divider__label {
304
- flex: none;
305
- font-family: var(--cb-font-sans);
306
- font-size: var(--cb-text-xs);
307
- font-weight: var(--cb-weight-semibold);
308
- color: var(--cb-fg-muted);
309
- }
310
-
311
275
  /* foundation/layout.css */
312
276
  .cb-flex { display: flex; gap: var(--cb-flex-gap); }
313
277
  .cb-flex--column { flex-direction: column; }
@@ -344,6 +308,33 @@ html, body { background: var(--cb-bg); color: var(--cb-fg); }
344
308
  .cb-container--lg { max-width: 76rem; }
345
309
  .cb-container--full { max-width: none; }
346
310
 
311
+ /* foundation/page-container/page-container.css */
312
+ .cb-page-container { display: flex; flex-direction: column; gap: var(--cb-space-4); padding-block: var(--cb-space-5); color: var(--cb-fg); font-family: var(--cb-font-sans); }
313
+ .cb-page-container__breadcrumb { color: var(--cb-fg-muted); font-size: var(--cb-text-sm); }
314
+ .cb-page-container__header { display: flex; align-items: flex-start; justify-content: space-between; gap: var(--cb-space-4); }
315
+ .cb-page-container__heading { display: flex; flex-direction: column; gap: var(--cb-space-1); min-width: 0; }
316
+ .cb-page-container__title { color: var(--cb-fg); font-size: var(--cb-text-xl); font-weight: var(--cb-weight-semibold); }
317
+ .cb-page-container__subtitle { color: var(--cb-fg-muted); font-size: var(--cb-text-sm); line-height: var(--cb-leading-normal); }
318
+ .cb-page-container__extra { flex: none; }
319
+ .cb-page-container__tabs { border-block-end: var(--cb-border-width) solid var(--cb-border); }
320
+ .cb-page-container__body { min-width: 0; }
321
+ .cb-page-container__skeleton-breadcrumb { inline-size: calc(var(--cb-space-8) * 3); block-size: var(--cb-text-sm); }
322
+ .cb-page-container__skeleton-title { inline-size: calc(var(--cb-space-8) * 5); block-size: var(--cb-text-xl); }
323
+ .cb-page-container__skeleton-subtitle { inline-size: calc(var(--cb-space-8) * 7); block-size: var(--cb-text-sm); }
324
+ .cb-page-container__skeleton-extra { inline-size: calc(var(--cb-space-8) * 2); block-size: var(--cb-control-height-sm); }
325
+ .cb-page-container__skeleton-tabs { inline-size: 100%; block-size: var(--cb-control-height-md); }
326
+ @media (max-width: 40rem) { .cb-page-container__header { flex-direction: column; } }
327
+
328
+ /* PageContainer is server-safe, so its skeleton draws its own placeholders rather than reaching for
329
+ Ant's Skeleton, which is a client component. */
330
+ .cb-page-container--skeleton span {
331
+ display: block;
332
+ border-radius: var(--cb-radius-sm);
333
+ background: var(--cb-bg-subtle);
334
+ }
335
+ .cb-page-container__skeleton-line { inline-size: 100%; block-size: var(--cb-text-sm); margin-block-start: var(--cb-space-2); }
336
+ .cb-page-container__skeleton-line:last-child { inline-size: 60%; }
337
+
347
338
  /* foundation/surface.css */
348
339
  .cb-surface {
349
340
  --cb-surface-accent: var(--cb-tone-neutral);
@@ -443,6 +434,7 @@ html, body { background: var(--cb-bg); color: var(--cb-fg); }
443
434
  }
444
435
  }
445
436
 
437
+ .cb-radius--none { border-radius: var(--cb-radius-none); }
446
438
  .cb-radius--sm { border-radius: var(--cb-radius-sm); }
447
439
  .cb-radius--md { border-radius: var(--cb-radius-md); }
448
440
  .cb-radius--lg { border-radius: var(--cb-radius-lg); }
@@ -480,1495 +472,209 @@ html, body { background: var(--cb-bg); color: var(--cb-fg); }
480
472
  .cb-text[data-tone="warning"] { color: var(--cb-tone-warning); }
481
473
  .cb-text[data-tone="danger"] { color: var(--cb-tone-danger); }
482
474
 
483
- /* form/autocomplete.css */
484
- .cb-autocomplete__positioner { z-index: var(--cb-z-dropdown); }
485
-
486
- .cb-autocomplete {
475
+ /* feedback/toast.css */
476
+ .cb-toast__viewport {
477
+ position: fixed;
478
+ z-index: var(--cb-z-toast);
487
479
  display: flex;
488
- align-items: center;
489
- gap: var(--cb-space-1);
490
- width: 100%;
480
+ flex-direction: column;
481
+ gap: var(--cb-space-2);
482
+ width: min(22rem, calc(100vw - var(--cb-space-6)));
483
+ }
484
+ .cb-toast__viewport[data-position^="bottom"] { inset-block-end: var(--cb-space-4); }
485
+ .cb-toast__viewport[data-position^="top"] { inset-block-start: var(--cb-space-4); }
486
+ .cb-toast__viewport[data-position$="end"] { inset-inline-end: var(--cb-space-4); }
487
+ .cb-toast__viewport[data-position$="start"] { inset-inline-start: var(--cb-space-4); }
488
+ .cb-toast__viewport[data-position$="center"] { inset-inline-start: 50%; translate: -50% 0; }
489
+ /* A stack at the top should enter from above, not slide up from below. */
490
+ .cb-toast__viewport[data-position^="top"] .cb-toast[data-starting-style],
491
+ .cb-toast__viewport[data-position^="top"] .cb-toast[data-ending-style] { transform: translateY(-8px); }
492
+
493
+ .cb-toast {
494
+ --cb-toast-accent: var(--cb-tone-info);
495
+ display: grid;
496
+ grid-template-columns: auto minmax(0, 1fr) auto;
497
+ grid-template-areas:
498
+ "icon content close"
499
+ ". action .";
500
+ align-items: start;
501
+ column-gap: var(--cb-space-3);
502
+ row-gap: var(--cb-space-2);
491
503
  box-sizing: border-box;
492
- background: var(--cb-surface);
493
- border: var(--cb-border-width) solid var(--cb-border-strong);
504
+ width: 100%;
505
+ padding: var(--cb-space-3) var(--cb-space-4);
494
506
  border-radius: var(--cb-radius-md);
495
- padding-inline: var(--cb-space-3) var(--cb-space-1);
496
- transition: border-color var(--cb-duration-fast) var(--cb-ease-standard),
497
- box-shadow var(--cb-duration-fast) var(--cb-ease-standard);
498
- }
499
- .cb-autocomplete--sm { height: var(--cb-control-height-sm); }
500
- .cb-autocomplete--md { height: var(--cb-control-height-md); }
501
- .cb-autocomplete--lg { height: var(--cb-control-height-lg); }
502
- .cb-autocomplete:focus-within {
503
- border-color: var(--cb-tone-brand);
504
- box-shadow: 0 0 0 var(--cb-focus-width) color-mix(in oklch, var(--cb-tone-brand) 30%, transparent);
507
+ border: var(--cb-border-width) solid var(--cb-border);
508
+ background: var(--cb-surface-raised);
509
+ box-shadow: var(--cb-shadow-md);
510
+ font-family: var(--cb-font-sans);
511
+ transition: opacity var(--cb-duration-base) var(--cb-ease-entrance),
512
+ transform var(--cb-duration-base) var(--cb-ease-entrance);
513
+ }
514
+ .cb-toast[data-tone="success"] { --cb-toast-accent: var(--cb-tone-success); }
515
+ .cb-toast[data-tone="warning"] { --cb-toast-accent: var(--cb-tone-warning); }
516
+ .cb-toast[data-tone="danger"] { --cb-toast-accent: var(--cb-tone-danger); }
517
+ .cb-toast[data-starting-style],
518
+ .cb-toast[data-ending-style] { opacity: 0; transform: translateY(8px); }
519
+ @media (prefers-reduced-motion: reduce) {
520
+ .cb-toast { transition: opacity var(--cb-duration-fast) linear; }
521
+ .cb-toast[data-starting-style],
522
+ .cb-toast[data-ending-style] { transform: none; }
505
523
  }
506
- .cb-autocomplete[data-disabled] { opacity: 0.55; }
507
- .cb-autocomplete:has(.cb-autocomplete__input[aria-invalid="true"]) { border-color: var(--cb-tone-danger); }
508
524
 
509
- .cb-autocomplete__input {
510
- flex: 1;
511
- min-width: 0;
525
+ .cb-toast__icon { grid-area: icon; color: var(--cb-toast-accent); display: inline-flex; margin-top: 0.125rem; }
526
+ .cb-toast__content { grid-area: content; display: flex; flex-direction: column; gap: 0.125rem; min-width: 0; }
527
+ /* Base UI renders these as <h2> and <p>, which inherit the host app's heading and paragraph
528
+ margins — without this reset a two-line toast is twice as tall in one app as in another. */
529
+ .cb-toast__title { margin: 0; font-size: var(--cb-text-sm); font-weight: var(--cb-weight-semibold); color: var(--cb-fg); }
530
+ .cb-toast__description { margin: 0; font-size: var(--cb-text-sm); color: var(--cb-fg-muted); }
531
+ /* A bare text action reads as misaligned until it is hovered: its padding pushes the label off
532
+ the line the title sits on, and nothing explains the gap. Carrying the soft Button treatment
533
+ at rest makes the padding part of a control instead of stray space. */
534
+ .cb-toast__action {
535
+ grid-area: action;
536
+ justify-self: start;
537
+ display: inline-flex;
538
+ align-items: center;
539
+ height: var(--cb-control-height-sm);
540
+ padding-inline: var(--cb-space-3);
512
541
  border: none;
513
- background: transparent;
514
- color: var(--cb-fg);
542
+ border-radius: var(--cb-radius-md);
543
+ background: color-mix(in oklch, var(--cb-toast-accent) 16%, transparent);
544
+ color: var(--cb-toast-accent);
515
545
  font-family: var(--cb-font-sans);
516
546
  font-size: var(--cb-text-sm);
517
- outline: none;
547
+ font-weight: var(--cb-weight-medium);
548
+ cursor: pointer;
549
+ transition: background-color var(--cb-duration-fast) var(--cb-ease-standard);
518
550
  }
519
- .cb-autocomplete__input::placeholder { color: var(--cb-fg-subtle); }
520
-
521
- .cb-autocomplete__clear,
522
- .cb-autocomplete__trigger {
523
- flex: none;
524
- display: inline-flex;
525
- align-items: center;
526
- justify-content: center;
527
- width: 1.75rem;
528
- height: 1.75rem;
551
+ @media (hover: hover) {
552
+ .cb-toast__action:hover { background: color-mix(in oklch, var(--cb-toast-accent) 26%, transparent); }
553
+ }
554
+ /* An action-less toast must not reserve the row it would have sat in. */
555
+ .cb-toast:not(:has(.cb-toast__action)) { grid-template-areas: "icon content close"; }
556
+ .cb-toast__close {
557
+ grid-area: close;
529
558
  border: none;
530
- border-radius: var(--cb-radius-sm);
531
559
  background: transparent;
532
560
  color: var(--cb-fg-subtle);
533
561
  cursor: pointer;
562
+ padding: var(--cb-space-1);
563
+ border-radius: var(--cb-radius-sm);
534
564
  }
535
- .cb-autocomplete__clear:hover,
536
- .cb-autocomplete__trigger:hover { color: var(--cb-fg); background: var(--cb-bg-subtle); }
537
- .cb-autocomplete__clear:focus-visible,
538
- .cb-autocomplete__trigger:focus-visible { outline: var(--cb-focus-width) solid var(--cb-tone-brand); outline-offset: var(--cb-focus-offset-inset); }
539
-
565
+ @media (hover: hover) {
566
+ .cb-toast__close:hover { color: var(--cb-fg); }
567
+ }
568
+ .cb-toast__close:focus-visible,
569
+ .cb-toast__action:focus-visible { outline: var(--cb-focus-width) solid var(--cb-toast-accent); outline-offset: var(--cb-focus-offset); }
540
570
 
541
- /* The list is as wide as the control it drops from, and its labels start where
542
- that control's own text starts.
571
+ /* overlay/command-palette.css */
572
+ .cb-palette__backdrop {
573
+ position: fixed;
574
+ inset: 0;
575
+ z-index: var(--cb-z-command-backdrop);
576
+ background: var(--cb-scrim);
577
+ backdrop-filter: blur(2px);
578
+ transition: opacity var(--cb-duration-base) var(--cb-ease-entrance);
579
+ }
580
+ .cb-palette__backdrop[data-starting-style],
581
+ .cb-palette__backdrop[data-ending-style] { opacity: 0; }
543
582
 
544
- Both were off by a little and the little showed: a popup narrower than its
545
- field reads as belonging to something else, and a leading indicator column
546
- pushed every label 29px right of the text it was replacing, so the list did
547
- not line up with the thing it was a list for. The tick moves to the trailing
548
- edge `order`, so the reading order is untouched — and the row's inline
549
- padding matches the field's. */
550
- /* Same shape and the same reasoning as the Select's popup — see select.css. */
551
- .cb-autocomplete__popup {
583
+ .cb-palette {
584
+ position: fixed;
585
+ top: 12vh;
586
+ left: 50%;
587
+ translate: -50% 0;
588
+ z-index: var(--cb-z-command);
589
+ display: flex;
590
+ flex-direction: column;
591
+ width: min(34rem, calc(100vw - var(--cb-space-6)));
592
+ max-height: 60vh;
552
593
  box-sizing: border-box;
553
- width: max-content;
554
- min-width: var(--anchor-width, 12rem);
555
- max-width: var(--available-width, 100vw);
556
- max-height: min(18rem, var(--available-height, 18rem));
557
- overflow-y: auto;
558
- padding: var(--cb-space-1);
559
594
  background: var(--cb-surface-raised);
560
595
  border: var(--cb-border-width) solid var(--cb-border);
561
- border-radius: var(--cb-radius-md);
562
- box-shadow: var(--cb-shadow-md);
596
+ border-radius: var(--cb-radius-lg);
597
+ box-shadow: var(--cb-shadow-lg);
598
+ overflow: hidden;
563
599
  font-family: var(--cb-font-sans);
564
- transition: opacity var(--cb-duration-fast) var(--cb-ease-entrance);
600
+ transition: opacity var(--cb-duration-base) var(--cb-ease-entrance),
601
+ translate var(--cb-duration-base) var(--cb-ease-entrance);
602
+ }
603
+ .cb-palette[data-starting-style],
604
+ .cb-palette[data-ending-style] { opacity: 0; translate: -50% -0.5rem; }
605
+ @media (prefers-reduced-motion: reduce) {
606
+ .cb-palette__backdrop { transition: opacity var(--cb-duration-fast) linear; }
607
+ .cb-palette { transition: opacity var(--cb-duration-fast) linear; }
608
+ .cb-palette[data-starting-style],
609
+ .cb-palette[data-ending-style] { translate: -50% 0; }
565
610
  }
566
- .cb-autocomplete__popup[data-starting-style],
567
- .cb-autocomplete__popup[data-ending-style] { opacity: 0; }
568
611
 
569
- .cb-autocomplete__item {
570
- display: grid;
571
- grid-template-columns: 1fr 1.25rem;
572
- align-items: start;
573
- gap: var(--cb-space-2);
574
- padding: var(--cb-space-2) var(--cb-space-2);
575
- min-height: 2.25rem;
576
- border-radius: var(--cb-radius-sm);
577
- font-size: var(--cb-text-sm);
612
+ .cb-palette__search {
613
+ display: flex;
614
+ align-items: center;
615
+ gap: var(--cb-space-3);
616
+ padding: var(--cb-space-4);
617
+ border-bottom: var(--cb-border-width) solid var(--cb-border);
618
+ }
619
+ .cb-palette__search-icon { color: var(--cb-fg-subtle); flex: none; }
620
+ .cb-palette__input {
621
+ flex: 1;
622
+ border: none;
623
+ background: transparent;
578
624
  color: var(--cb-fg);
579
- cursor: pointer;
625
+ font-family: inherit;
626
+ font-size: var(--cb-text-md);
580
627
  outline: none;
581
628
  }
582
- .cb-autocomplete__item[data-highlighted] { background: color-mix(in oklch, var(--cb-tone-brand) 12%, transparent); }
583
- .cb-autocomplete__check { order: 2; display: inline-flex; justify-content: center; align-items: center; min-height: 1.25rem; color: var(--cb-tone-brand); }
584
- .cb-autocomplete__text { display: flex; flex-direction: column; gap: 0.0625rem; min-width: 0; line-height: 1.25rem; }
585
- .cb-autocomplete__description { font-size: var(--cb-text-xs); color: var(--cb-fg-subtle); }
586
- .cb-autocomplete__empty,
587
- .cb-autocomplete__status { padding: var(--cb-space-3); font-size: var(--cb-text-sm); color: var(--cb-fg-subtle); text-align: center; }
588
- /* Base UI keeps the empty message mounted while the list has matches, so it sat
589
- as a silent 24px band above every result. A message with nothing to say takes
590
- no room. */
591
- .cb-autocomplete__empty:empty { display: none; }
592
- .cb-autocomplete__status { margin: 0; }
593
-
594
- /* form/button.css */
595
- .cb-button {
596
- --cb-button-accent: var(--cb-tone-brand);
597
- --cb-button-fg: var(--cb-fg-on-brand);
598
- display: inline-flex;
629
+ .cb-palette__input::placeholder { color: var(--cb-fg-subtle); }
630
+
631
+ .cb-palette__list { overflow-y: auto; padding: var(--cb-space-2); }
632
+ .cb-palette__group + .cb-palette__group { margin-top: var(--cb-space-2); }
633
+ .cb-palette__group-label {
634
+ margin: 0 0 var(--cb-space-1);
635
+ padding-inline: var(--cb-space-2);
636
+ font-size: 0.6875rem;
637
+ text-transform: uppercase;
638
+ letter-spacing: 0.08em;
639
+ color: var(--cb-fg-subtle);
640
+ }
641
+ .cb-palette__item {
642
+ display: flex;
599
643
  align-items: center;
600
- justify-content: center;
601
- gap: var(--cb-space-2);
602
- border: var(--cb-border-width) solid transparent;
603
- border-radius: var(--cb-radius-md);
604
- font-family: var(--cb-font-sans);
605
- font-weight: var(--cb-weight-medium);
644
+ gap: var(--cb-space-3);
645
+ padding: var(--cb-space-2) var(--cb-space-3);
646
+ border-radius: var(--cb-radius-sm);
647
+ font-size: var(--cb-text-sm);
648
+ color: var(--cb-fg);
606
649
  cursor: pointer;
607
- white-space: nowrap;
608
- transition: background-color var(--cb-duration-fast) var(--cb-ease-standard),
609
- color var(--cb-duration-fast) var(--cb-ease-standard),
610
- border-color var(--cb-duration-fast) var(--cb-ease-standard);
611
650
  }
612
- .cb-button:disabled { opacity: 0.55; cursor: not-allowed; }
613
- .cb-button:focus-visible {
614
- outline: var(--cb-focus-width) solid var(--cb-button-accent);
615
- outline-offset: var(--cb-focus-offset);
616
- }
617
-
618
- .cb-button[data-tone="neutral"] { --cb-button-accent: var(--cb-fg); --cb-button-fg: var(--cb-bg); }
619
- .cb-button[data-tone="info"] { --cb-button-accent: var(--cb-tone-info); }
620
- .cb-button[data-tone="success"] { --cb-button-accent: var(--cb-tone-success); }
621
- .cb-button[data-tone="warning"] { --cb-button-accent: var(--cb-tone-warning); --cb-button-fg: var(--cb-on-warning); }
622
- .cb-button[data-tone="danger"] { --cb-button-accent: var(--cb-tone-danger); }
623
-
624
- .cb-button--sm { height: var(--cb-control-height-sm); padding-inline: var(--cb-space-3); font-size: var(--cb-text-sm); }
625
- .cb-button--md { height: var(--cb-control-height-md); padding-inline: var(--cb-space-4); font-size: var(--cb-text-sm); }
626
- .cb-button--lg { height: var(--cb-control-height-lg); padding-inline: var(--cb-space-5); font-size: var(--cb-text-md); }
627
-
628
- .cb-button--solid { background: var(--cb-button-accent); color: var(--cb-button-fg); }
629
- .cb-button--solid:hover:not(:disabled) { background: color-mix(in oklch, var(--cb-button-accent) 88%, black); }
630
-
631
- .cb-button--soft {
632
- background: color-mix(in oklch, var(--cb-button-accent) 14%, transparent);
633
- color: var(--cb-button-accent);
634
- }
635
- .cb-button--soft:hover:not(:disabled) { background: color-mix(in oklch, var(--cb-button-accent) 22%, transparent); }
636
-
637
- .cb-button--outline { border-color: var(--cb-border-strong); color: var(--cb-fg); background: transparent; }
638
- .cb-button--outline:hover:not(:disabled) { border-color: var(--cb-button-accent); color: var(--cb-button-accent); }
639
-
640
- .cb-button--ghost { background: transparent; color: var(--cb-fg-muted); }
641
- .cb-button--ghost:hover:not(:disabled) { background: var(--cb-bg-subtle); color: var(--cb-fg); }
642
-
643
- /* Square, no text padding, no gap: the glyph sits on the centre of the control. */
644
- .cb-button--icon { padding-inline: 0; gap: 0; }
645
- .cb-button--icon.cb-button--sm { width: var(--cb-control-height-sm); }
646
- .cb-button--icon.cb-button--md { width: var(--cb-control-height-md); }
647
- .cb-button--icon.cb-button--lg { width: var(--cb-control-height-lg); }
651
+ .cb-palette__item[data-active] { background: color-mix(in oklch, var(--cb-tone-brand) 12%, transparent); }
652
+ .cb-palette__icon { display: inline-flex; color: var(--cb-fg-subtle); width: 1.25rem; justify-content: center; }
653
+ .cb-palette__label { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
654
+ .cb-palette__shortcut { margin: 0; padding: 0; border: none; background: none; font-family: var(--cb-font-mono); font-size: var(--cb-text-xs); color: var(--cb-fg-subtle); }
655
+ .cb-palette__empty { margin: 0; padding: var(--cb-space-5); text-align: center; font-size: var(--cb-text-sm); color: var(--cb-fg-subtle); }
648
656
 
649
- .cb-button__spinner {
650
- width: 1em;
651
- height: 1em;
652
- border-radius: var(--cb-radius-full);
653
- border: 2px solid currentColor;
654
- border-top-color: transparent;
655
- animation: cb-spin calc(var(--cb-duration-deliberate) * 1.5) linear infinite;
656
- }
657
- @keyframes cb-spin { to { transform: rotate(360deg); } }
658
- /* Reduced motion: the spinner stops turning but the busy state stays visible and announced. */
657
+ /* data/donut.css */
658
+ .cb-donut { position: relative; display: inline-grid; place-items: center; }
659
+ .cb-donut svg { position: absolute; inset: 0; }
660
+ .cb-donut__track { stroke: color-mix(in oklch, var(--cb-fg) 8%, transparent); }
661
+ .cb-donut__arc { transition: stroke-dasharray var(--cb-duration-deliberate) var(--cb-ease-entrance); }
662
+ /* Reduced motion: the arcs are drawn at their final length rather than growing into place. */
659
663
  @media (prefers-reduced-motion: reduce) {
660
- /* Square, no text padding, no gap: the glyph sits on the centre of the control. */
661
- .cb-button--icon { padding-inline: 0; gap: 0; }
662
- .cb-button--icon.cb-button--sm { width: var(--cb-control-height-sm); }
663
- .cb-button--icon.cb-button--md { width: var(--cb-control-height-md); }
664
- .cb-button--icon.cb-button--lg { width: var(--cb-control-height-lg); }
665
-
666
- .cb-button__spinner { animation: none; opacity: 0.6; }
667
- }
668
-
669
- /* An anchor does not inherit a button's reset, so the two only match once the
670
- browser's own link styling is taken back off. */
671
- .cb-link-button { text-decoration: none; }
672
-
673
- /* form/choice.css */
674
- .cb-choice { display: flex; align-items: flex-start; gap: var(--cb-space-3); }
675
- /* A row whose text is a single line centres on the control instead of hanging from its top. */
676
- .cb-choice:not(:has(.cb-choice__description)) { align-items: center; }
677
- .cb-choice--justified { align-items: center; justify-content: space-between; width: 100%; }
678
- .cb-choice__text { display: flex; flex-direction: column; gap: var(--cb-space-1); }
679
- .cb-choice__label {
664
+ .cb-donut__arc { transition: none; }
665
+ }
666
+ .cb-donut__arc[data-hue="violet"] { stroke: var(--cb-decor-violet); }
667
+ .cb-donut__arc[data-hue="blue"] { stroke: var(--cb-decor-blue); }
668
+ .cb-donut__arc[data-hue="teal"] { stroke: var(--cb-decor-teal); }
669
+ .cb-donut__arc[data-hue="green"] { stroke: var(--cb-decor-green); }
670
+ .cb-donut__arc[data-hue="amber"] { stroke: var(--cb-decor-amber); }
671
+ .cb-donut__arc[data-hue="rose"] { stroke: var(--cb-decor-rose); }
672
+ .cb-donut__center {
680
673
  font-family: var(--cb-font-sans);
681
- font-size: var(--cb-text-sm);
674
+ font-variant-numeric: tabular-nums;
675
+ text-align: center;
682
676
  color: var(--cb-fg);
683
- cursor: pointer;
684
- line-height: 1.35;
685
- }
686
- .cb-choice__description { margin: 0; font-family: var(--cb-font-sans); font-size: var(--cb-text-xs); color: var(--cb-fg-subtle); }
687
-
688
- .cb-checkbox,
689
- .cb-radio {
690
- position: relative;
691
- flex: none;
692
- display: inline-flex;
693
- align-items: center;
694
- justify-content: center;
695
- width: 1.125rem;
696
- height: 1.125rem;
697
- margin-top: 0.0625rem;
698
- padding: 0;
699
- background: var(--cb-surface);
700
- border: var(--cb-border-width) solid var(--cb-border-strong);
701
- color: var(--cb-fg-on-brand);
702
- cursor: pointer;
703
- transition: background-color var(--cb-duration-fast) var(--cb-ease-standard),
704
- border-color var(--cb-duration-fast) var(--cb-ease-standard);
705
- }
706
- .cb-checkbox { border-radius: 0.3125rem; }
707
-
708
- /* The pointer target is 24px even though the box reads as 18px. The switch is excluded: it is
709
- already 40x24, and without a positioned ancestor its pseudo-element grew to the width of a
710
- distant container and swallowed every click on the page. */
711
- .cb-checkbox::before,
712
- .cb-radio::before {
713
- content: "";
714
- position: absolute;
715
- inset: 50% auto auto 50%;
716
- width: max(100%, 1.5rem);
717
- height: max(100%, 1.5rem);
718
- translate: -50% -50%;
719
- }
720
- .cb-radio { border-radius: var(--cb-radius-full); }
721
-
722
- .cb-checkbox[data-checked],
723
- .cb-checkbox[data-indeterminate] {
724
- background: var(--cb-tone-brand);
725
- border-color: var(--cb-tone-brand);
726
- }
727
- .cb-radio[data-checked] { border-color: var(--cb-tone-brand); border-width: 2px; }
728
-
729
- .cb-checkbox:focus-visible,
730
- .cb-radio:focus-visible,
731
- .cb-switch:focus-visible {
732
- outline: var(--cb-focus-width) solid var(--cb-tone-brand);
733
- outline-offset: var(--cb-focus-offset);
734
- }
735
- /* Disabled has to be legible as a state, not merely dimmer: the control loses its fill, drops
736
- to a dashed edge, and takes the muted foreground with it. */
737
- .cb-checkbox[data-disabled],
738
- .cb-radio[data-disabled],
739
- .cb-switch[data-disabled] {
740
- cursor: not-allowed;
741
- opacity: 1;
742
- background: var(--cb-bg-subtle);
743
- border-style: dashed;
744
- border-color: var(--cb-border-strong);
745
- color: var(--cb-fg-subtle);
746
- }
747
- .cb-switch[data-disabled] { border-style: solid; background: color-mix(in oklch, var(--cb-fg) 12%, transparent); }
748
- .cb-switch[data-disabled] .cb-switch__thumb { background: var(--cb-bg-subtle); box-shadow: none; }
749
- .cb-radio[data-disabled] .cb-radio__indicator,
750
- .cb-checkbox[data-disabled] .cb-checkbox__indicator { color: var(--cb-fg-subtle); background: var(--cb-fg-subtle); }
751
- .cb-choice:has([data-disabled]) .cb-choice__label,
752
- .cb-choice:has([data-disabled]) .cb-choice__description { color: var(--cb-fg-subtle); cursor: not-allowed; }
753
-
754
- .cb-checkbox__indicator { display: inline-flex; }
755
- .cb-radio__indicator {
756
- width: 0.5rem;
757
- height: 0.5rem;
758
- border-radius: var(--cb-radius-full);
759
- background: var(--cb-tone-brand);
760
- transition: scale var(--cb-duration-fast) var(--cb-ease-emphasis);
761
- }
762
- .cb-radio__indicator[data-starting-style] { scale: 0; }
763
- @media (prefers-reduced-motion: reduce) {
764
- .cb-radio__indicator { transition: none; }
765
- }
766
-
767
- .cb-radio-group { display: flex; gap: var(--cb-space-3); }
768
- .cb-radio-group--column { flex-direction: column; }
769
- .cb-radio-group--row { flex-direction: row; flex-wrap: wrap; gap: var(--cb-space-5); }
770
-
771
- .cb-switch {
772
- /* Geometry is derived, not hand-tuned: the thumb size and its travel both come from the
773
- track's own dimensions, so changing one number keeps the whole control symmetrical. */
774
- --cb-switch-width: 2.5rem;
775
- --cb-switch-height: 1.5rem;
776
- --cb-switch-inset: 0.1875rem;
777
- --cb-switch-thumb: calc(var(--cb-switch-height) - var(--cb-switch-inset) * 2);
778
- flex: none;
779
- display: inline-flex;
780
- align-items: center;
781
- width: var(--cb-switch-width);
782
- height: var(--cb-switch-height);
783
- padding: var(--cb-switch-inset);
784
- box-sizing: border-box;
785
- border: none;
786
- border-radius: var(--cb-radius-full);
787
- background: color-mix(in oklch, var(--cb-fg) 25%, transparent);
788
- cursor: pointer;
789
- transition: background-color var(--cb-duration-base) var(--cb-ease-standard);
790
- }
791
- .cb-switch[data-checked] { background: var(--cb-tone-brand); }
792
- .cb-switch__thumb {
793
- display: block;
794
- width: var(--cb-switch-thumb);
795
- height: var(--cb-switch-thumb);
796
- border-radius: var(--cb-radius-full);
797
- background: var(--cb-surface-raised);
798
- box-shadow: var(--cb-shadow-sm);
799
- transition: translate var(--cb-duration-base) var(--cb-ease-emphasis);
800
- }
801
- .cb-switch[data-checked] .cb-switch__thumb {
802
- translate: calc(var(--cb-switch-width) - var(--cb-switch-height)) 0;
803
- }
804
- /* Reduced motion: the thumb still moves — that is the state — it just stops easing. */
805
- @media (prefers-reduced-motion: reduce) {
806
- .cb-switch__thumb { transition: none; }
807
- }
808
-
809
- /* Segmented: the same radiogroup, drawn as one track.
810
-
811
- The dot is not hidden with `display: none` — a removed control cannot be
812
- focused or hit. It is stretched over its whole cell at zero opacity instead,
813
- so the cell IS the radio: pointer, focus ring and keyboard all keep working
814
- and only the drawing changes. */
815
- .cb-radio-group--segmented {
816
- display: inline-flex;
817
- align-items: stretch;
818
- gap: var(--cb-space-hair, 2px);
819
- padding: 2px;
820
- background: var(--cb-bg-subtle);
821
- border: var(--cb-border-width) solid var(--cb-border);
822
- border-radius: var(--cb-radius-md);
823
- }
824
- .cb-radio-group--segmented .cb-choice {
825
- position: relative;
826
- align-items: center;
827
- gap: 0;
828
- min-width: 0;
829
- }
830
- .cb-radio-group--segmented .cb-radio {
831
- position: absolute;
832
- inset: 0;
833
- z-index: 1;
834
- width: 100%;
835
- height: 100%;
836
- margin: 0;
837
- border: 0;
838
- background: transparent;
839
- border-radius: var(--cb-radius-sm);
840
- opacity: 0;
841
- }
842
- .cb-radio-group--segmented .cb-radio::before { content: none; }
843
- .cb-radio-group--segmented .cb-radio__indicator { display: none; }
844
- .cb-radio-group--segmented .cb-choice__text { width: 100%; }
845
- .cb-radio-group--segmented .cb-choice__label {
846
- display: block;
847
- padding: var(--cb-space-2) var(--cb-space-3);
848
- border-radius: var(--cb-radius-sm);
849
- font-weight: var(--cb-weight-medium);
850
- color: var(--cb-fg-muted);
851
- text-align: center;
852
- white-space: nowrap;
853
- transition: background-color var(--cb-duration-fast) var(--cb-ease-standard),
854
- color var(--cb-duration-fast) var(--cb-ease-standard);
855
- }
856
- .cb-radio-group--segmented .cb-radio[data-checked] ~ .cb-choice__text .cb-choice__label {
857
- background: var(--cb-surface-raised);
858
- color: var(--cb-fg);
859
- box-shadow: var(--cb-shadow-sm);
860
- }
861
- .cb-radio-group--segmented .cb-radio:focus-visible ~ .cb-choice__text .cb-choice__label {
862
- outline: var(--cb-focus-width) solid var(--cb-tone-brand);
863
- outline-offset: var(--cb-focus-offset);
864
- }
865
- .cb-radio-group--segmented .cb-radio[data-disabled] ~ .cb-choice__text .cb-choice__label {
866
- opacity: 0.55;
867
- cursor: not-allowed;
868
- }
869
-
870
- @media (prefers-reduced-motion: reduce) {
871
- .cb-radio-group--segmented .cb-choice__label { transition: none; }
872
- }
873
-
874
- /* form/date-picker.css */
875
- .cb-date {
876
- display: flex;
877
- align-items: center;
878
- width: 100%;
879
- box-sizing: border-box;
880
- background: var(--cb-surface);
881
- border: var(--cb-border-width) solid var(--cb-border-strong);
882
- border-radius: var(--cb-radius-md);
883
- padding-inline: var(--cb-space-3) var(--cb-space-1);
884
- transition: border-color var(--cb-duration-fast) var(--cb-ease-standard),
885
- box-shadow var(--cb-duration-fast) var(--cb-ease-standard);
886
- }
887
- .cb-date--sm { height: var(--cb-control-height-sm); }
888
- .cb-date--md { height: var(--cb-control-height-md); }
889
- .cb-date--lg { height: var(--cb-control-height-lg); }
890
- .cb-date:focus-within {
891
- border-color: var(--cb-tone-brand);
892
- box-shadow: 0 0 0 var(--cb-focus-width) color-mix(in oklch, var(--cb-tone-brand) 30%, transparent);
893
- }
894
- .cb-date[data-disabled] { opacity: 0.55; }
895
- .cb-date:has(.cb-date__input[aria-invalid="true"]) { border-color: var(--cb-tone-danger); }
896
-
897
- .cb-date__input {
898
- flex: 1;
899
- min-width: 0;
900
- border: none;
901
- background: transparent;
902
- color: var(--cb-fg);
903
- font-family: var(--cb-font-sans);
904
- font-size: var(--cb-text-sm);
905
- font-variant-numeric: tabular-nums;
906
- outline: none;
907
- }
908
- .cb-date__input::placeholder { color: var(--cb-fg-subtle); }
909
- .cb-date__trigger {
910
- flex: none;
911
- display: inline-flex;
912
- align-items: center;
913
- justify-content: center;
914
- width: 1.75rem;
915
- height: 1.75rem;
916
- border: none;
917
- border-radius: var(--cb-radius-sm);
918
- background: transparent;
919
- color: var(--cb-fg-subtle);
920
- cursor: pointer;
921
- }
922
- .cb-date__trigger:hover { color: var(--cb-fg); background: var(--cb-bg-subtle); }
923
- .cb-date__trigger:focus-visible { outline: var(--cb-focus-width) solid var(--cb-tone-brand); outline-offset: var(--cb-focus-offset-inset); }
924
-
925
- .cb-calendar {
926
- padding: var(--cb-space-3);
927
- background: var(--cb-surface-raised);
928
- border: var(--cb-border-width) solid var(--cb-border);
929
- border-radius: var(--cb-radius-md);
930
- box-shadow: var(--cb-shadow-md);
931
- font-family: var(--cb-font-sans);
932
- transition: opacity var(--cb-duration-fast) var(--cb-ease-entrance);
933
- }
934
- .cb-calendar[data-starting-style],
935
- .cb-calendar[data-ending-style] { opacity: 0; }
936
-
937
- .cb-calendar__head { display: flex; align-items: center; justify-content: space-between; gap: var(--cb-space-2); margin-bottom: var(--cb-space-2); }
938
- .cb-calendar__month { margin: 0; font-size: var(--cb-text-sm); font-weight: var(--cb-weight-medium); color: var(--cb-fg); }
939
- .cb-calendar__nav {
940
- display: inline-flex;
941
- align-items: center;
942
- justify-content: center;
943
- width: 1.75rem;
944
- height: 1.75rem;
945
- border: none;
946
- border-radius: var(--cb-radius-sm);
947
- background: transparent;
948
- color: var(--cb-fg-muted);
949
- cursor: pointer;
950
- }
951
- .cb-calendar__nav:hover { background: var(--cb-bg-subtle); color: var(--cb-fg); }
952
- .cb-calendar__nav:focus-visible { outline: var(--cb-focus-width) solid var(--cb-tone-brand); outline-offset: var(--cb-focus-offset); }
953
-
954
- .cb-calendar__grid { border-collapse: collapse; }
955
- .cb-calendar__grid th {
956
- font-size: 0.6875rem;
957
- font-weight: var(--cb-weight-medium);
958
- color: var(--cb-fg-subtle);
959
- padding-bottom: var(--cb-space-1);
960
- }
961
- .cb-calendar__day {
962
- width: 2rem;
963
- height: 2rem;
964
- border: none;
965
- border-radius: var(--cb-radius-sm);
966
- background: transparent;
967
- color: var(--cb-fg);
968
- font-family: inherit;
969
- font-size: var(--cb-text-sm);
970
- font-variant-numeric: tabular-nums;
971
- cursor: pointer;
972
- }
973
- .cb-calendar__day:hover:not(:disabled) { background: var(--cb-bg-subtle); }
974
- .cb-calendar__day[data-outside] { color: var(--cb-fg-subtle); }
975
- .cb-calendar__day[data-today] { box-shadow: inset 0 0 0 1px var(--cb-border-strong); }
976
- .cb-calendar__day[data-selected] { background: var(--cb-tone-brand); color: var(--cb-fg-on-brand); font-weight: var(--cb-weight-medium); }
977
- .cb-calendar__day:disabled { opacity: 0.3; cursor: not-allowed; }
978
- .cb-calendar__day:focus-visible { outline: var(--cb-focus-width) solid var(--cb-tone-brand); outline-offset: var(--cb-focus-offset-inset); }
979
-
980
- .cb-times {
981
- max-height: 15rem;
982
- overflow-y: auto;
983
- padding: var(--cb-space-1);
984
- background: var(--cb-surface-raised);
985
- border: var(--cb-border-width) solid var(--cb-border);
986
- border-radius: var(--cb-radius-md);
987
- box-shadow: var(--cb-shadow-md);
988
- font-family: var(--cb-font-sans);
989
- }
990
- .cb-times__list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 0.125rem; min-width: 7rem; }
991
- .cb-times__option {
992
- width: 100%;
993
- padding: var(--cb-space-2) var(--cb-space-3);
994
- border: none;
995
- border-radius: var(--cb-radius-sm);
996
- background: transparent;
997
- color: var(--cb-fg);
998
- font-family: inherit;
999
- font-size: var(--cb-text-sm);
1000
- font-variant-numeric: tabular-nums;
1001
- text-align: start;
1002
- cursor: pointer;
1003
- }
1004
- .cb-times__option:hover { background: var(--cb-bg-subtle); }
1005
- .cb-times__option[data-selected] { background: color-mix(in oklch, var(--cb-tone-brand) 16%, transparent); color: var(--cb-tone-brand); font-weight: var(--cb-weight-medium); }
1006
- .cb-times__option:focus-visible { outline: var(--cb-focus-width) solid var(--cb-tone-brand); outline-offset: var(--cb-focus-offset-inset); }
1007
- .cb-calendar__positioner,
1008
- .cb-times__positioner { z-index: var(--cb-z-dropdown); }
1009
-
1010
- /* form/field.css */
1011
- .cb-field { display: flex; flex-direction: column; gap: var(--cb-space-2); }
1012
- .cb-field__label {
1013
- font-family: var(--cb-font-sans);
1014
- font-size: var(--cb-text-sm);
1015
- font-weight: var(--cb-weight-medium);
1016
- color: var(--cb-fg);
1017
- }
1018
- .cb-field__required { color: var(--cb-tone-danger); margin-inline-start: var(--cb-space-1); }
1019
- .cb-field__hint { margin: 0; font-family: var(--cb-font-sans); font-size: var(--cb-text-xs); color: var(--cb-fg-subtle); }
1020
- .cb-field__error { margin: 0; font-family: var(--cb-font-sans); font-size: var(--cb-text-xs); color: var(--cb-tone-danger); }
1021
-
1022
- .cb-visually-hidden {
1023
- position: absolute;
1024
- width: 1px;
1025
- height: 1px;
1026
- margin: -1px;
1027
- padding: 0;
1028
- overflow: hidden;
1029
- clip-path: inset(50%);
1030
- white-space: nowrap;
1031
- }
1032
-
1033
- .cb-input {
1034
- width: 100%;
1035
- box-sizing: border-box;
1036
- background: var(--cb-surface);
1037
- color: var(--cb-fg);
1038
- border: var(--cb-border-width) solid var(--cb-border-strong);
1039
- border-radius: var(--cb-radius-md);
1040
- font-family: var(--cb-font-sans);
1041
- font-size: var(--cb-text-sm);
1042
- padding-inline: var(--cb-space-3);
1043
- transition: border-color var(--cb-duration-fast) var(--cb-ease-standard),
1044
- box-shadow var(--cb-duration-fast) var(--cb-ease-standard);
1045
- }
1046
- .cb-input--sm { height: var(--cb-control-height-sm); }
1047
- .cb-input--md { height: var(--cb-control-height-md); }
1048
- .cb-input--lg { height: var(--cb-control-height-lg); }
1049
- .cb-input--textarea { height: auto; padding-block: var(--cb-space-3); min-height: 6rem; resize: vertical; }
1050
- .cb-input::placeholder { color: var(--cb-fg-subtle); }
1051
- .cb-input:focus-visible {
1052
- outline: none;
1053
- border-color: var(--cb-tone-brand);
1054
- box-shadow: 0 0 0 var(--cb-focus-width) color-mix(in oklch, var(--cb-tone-brand) 30%, transparent);
1055
- }
1056
- .cb-input[aria-invalid="true"] { border-color: var(--cb-tone-danger); }
1057
- .cb-input[aria-invalid="true"]:focus-visible {
1058
- box-shadow: 0 0 0 var(--cb-focus-width) color-mix(in oklch, var(--cb-tone-danger) 30%, transparent);
1059
- }
1060
-
1061
- /* form/input-number.css */
1062
- .cb-number {
1063
- display: inline-flex;
1064
- align-items: center;
1065
- gap: var(--cb-space-1);
1066
- width: 100%;
1067
- box-sizing: border-box;
1068
- background: var(--cb-surface);
1069
- border: var(--cb-border-width) solid var(--cb-border-strong);
1070
- border-radius: var(--cb-radius-md);
1071
- padding-inline: var(--cb-space-3) var(--cb-space-1);
1072
- transition: border-color var(--cb-duration-fast) var(--cb-ease-standard),
1073
- box-shadow var(--cb-duration-fast) var(--cb-ease-standard);
1074
- }
1075
- .cb-number--sm { height: var(--cb-control-height-sm); }
1076
- .cb-number--md { height: var(--cb-control-height-md); }
1077
- .cb-number--lg { height: var(--cb-control-height-lg); }
1078
- .cb-number:focus-within {
1079
- border-color: var(--cb-tone-brand);
1080
- box-shadow: 0 0 0 var(--cb-focus-width) color-mix(in oklch, var(--cb-tone-brand) 30%, transparent);
1081
- }
1082
- .cb-number[data-disabled] { opacity: 0.55; }
1083
- .cb-number:has(.cb-number__input[aria-invalid="true"]) { border-color: var(--cb-tone-danger); }
1084
-
1085
- .cb-number__input {
1086
- flex: 1;
1087
- min-width: 0;
1088
- border: none;
1089
- background: transparent;
1090
- color: var(--cb-fg);
1091
- font-family: var(--cb-font-sans);
1092
- font-size: var(--cb-text-sm);
1093
- font-variant-numeric: tabular-nums;
1094
- outline: none;
1095
- }
1096
- .cb-number__suffix { font-family: var(--cb-font-sans); font-size: var(--cb-text-xs); color: var(--cb-fg-subtle); }
1097
-
1098
- .cb-number__steppers { display: inline-flex; flex: none; gap: 0.125rem; }
1099
-
1100
- .cb-number__step {
1101
- flex: none;
1102
- display: inline-flex;
1103
- align-items: center;
1104
- justify-content: center;
1105
- width: 1.75rem;
1106
- height: 1.75rem;
1107
- border: none;
1108
- border-radius: var(--cb-radius-sm);
1109
- background: transparent;
1110
- color: var(--cb-fg-muted);
1111
- cursor: pointer;
1112
- transition: background-color var(--cb-duration-fast) var(--cb-ease-standard);
1113
- }
1114
- .cb-number__step:hover:not(:disabled) { background: var(--cb-bg-subtle); color: var(--cb-fg); }
1115
- .cb-number__step:disabled { opacity: 0.35; cursor: not-allowed; }
1116
- .cb-number__step:focus-visible { outline: var(--cb-focus-width) solid var(--cb-tone-brand); outline-offset: var(--cb-focus-offset-inset); }
1117
-
1118
- /* form/rate.css */
1119
- .cb-rate {
1120
- display: inline-flex;
1121
- align-items: center;
1122
- gap: var(--cb-space-1);
1123
- color: var(--cb-tone-warning);
1124
- line-height: 0;
1125
- }
1126
-
1127
- .cb-rate__star {
1128
- padding: 0;
1129
- border: 0;
1130
- background: none;
1131
- color: inherit;
1132
- cursor: pointer;
1133
- line-height: 0;
1134
- border-radius: var(--cb-radius-sm);
1135
- transition: transform var(--cb-duration-fast) var(--cb-ease-standard);
1136
- }
1137
- .cb-rate__star:hover { transform: scale(1.12); }
1138
- .cb-rate__star:focus-visible {
1139
- outline: var(--cb-focus-width) solid var(--cb-tone-brand);
1140
- outline-offset: var(--cb-focus-offset);
1141
- }
1142
-
1143
- /* Reduced motion drops the transform and keeps the state visible: the star is
1144
- already filled or not, which is the whole feedback. */
1145
- @media (prefers-reduced-motion: reduce) {
1146
- .cb-rate__star { transition: none; }
1147
- .cb-rate__star:hover { transform: none; }
1148
- }
1149
-
1150
- /* form/select.css */
1151
- .cb-select__positioner { z-index: var(--cb-z-dropdown); }
1152
-
1153
- .cb-select {
1154
- display: inline-flex;
1155
- align-items: center;
1156
- justify-content: space-between;
1157
- gap: var(--cb-space-2);
1158
- width: 100%;
1159
- box-sizing: border-box;
1160
- background: var(--cb-surface);
1161
- color: var(--cb-fg);
1162
- border: var(--cb-border-width) solid var(--cb-border-strong);
1163
- border-radius: var(--cb-radius-md);
1164
- font-family: var(--cb-font-sans);
1165
- font-size: var(--cb-text-sm);
1166
- padding-inline: var(--cb-space-3);
1167
- cursor: pointer;
1168
- text-align: start;
1169
- transition: border-color var(--cb-duration-fast) var(--cb-ease-standard),
1170
- box-shadow var(--cb-duration-fast) var(--cb-ease-standard);
1171
- }
1172
- .cb-select--sm { height: var(--cb-control-height-sm); }
1173
- .cb-select--md { height: var(--cb-control-height-md); }
1174
- .cb-select--lg { height: var(--cb-control-height-lg); }
1175
- .cb-select:hover:not(:disabled) { border-color: var(--cb-fg-subtle); }
1176
- .cb-select:focus-visible {
1177
- outline: none;
1178
- border-color: var(--cb-tone-brand);
1179
- box-shadow: 0 0 0 var(--cb-focus-width) color-mix(in oklch, var(--cb-tone-brand) 30%, transparent);
1180
- }
1181
- .cb-select[aria-invalid="true"] { border-color: var(--cb-tone-danger); }
1182
- .cb-select[data-disabled] { opacity: 0.55; cursor: not-allowed; }
1183
- .cb-select__icon { display: inline-flex; color: var(--cb-fg-subtle); }
1184
-
1185
- /* As wide as its longest option, and never wider than the screen.
1186
- *
1187
- * Pinned to the anchor's width, a popup dropping from a field that is half a
1188
- * filter row is 175px on a phone — and the options in it are place names.
1189
- * "Kabupaten Tangerang Selatan (5)" wrapped to three lines there, the one below
1190
- * it to two, and the list read as a cramped column of broken phrases rather
1191
- * than as a set of choices.
1192
- *
1193
- * So the anchor's width becomes the floor rather than the value: still never
1194
- * narrower than the field it belongs to, because a popup narrower than its
1195
- * field reads as belonging to something else. `--available-width` is the room
1196
- * the positioner measured between the anchor and the edge of the screen, so
1197
- * the ceiling moves with the viewport instead of being a number written here.
1198
- */
1199
- .cb-select__popup {
1200
- box-sizing: border-box;
1201
- width: max-content;
1202
- min-width: var(--anchor-width, 10rem);
1203
- max-width: var(--available-width, 100vw);
1204
- max-height: min(18rem, var(--available-height, 18rem));
1205
- overflow-y: auto;
1206
- background: var(--cb-surface-raised);
1207
- border: var(--cb-border-width) solid var(--cb-border);
1208
- border-radius: var(--cb-radius-md);
1209
- box-shadow: var(--cb-shadow-md);
1210
- padding: var(--cb-space-1);
1211
- font-family: var(--cb-font-sans);
1212
- font-size: var(--cb-text-sm);
1213
- transition: opacity var(--cb-duration-fast) var(--cb-ease-entrance),
1214
- transform var(--cb-duration-fast) var(--cb-ease-entrance);
1215
- }
1216
- .cb-select__popup[data-starting-style],
1217
- .cb-select__popup[data-ending-style] { opacity: 0; transform: scale(0.98); }
1218
- @media (prefers-reduced-motion: reduce) {
1219
- .cb-select__popup { transition: opacity var(--cb-duration-fast) linear; }
1220
- .cb-select__popup[data-starting-style],
1221
- .cb-select__popup[data-ending-style] { transform: none; }
1222
- }
1223
-
1224
- .cb-select__item {
1225
- display: grid;
1226
- grid-template-columns: 1fr 1.25rem;
1227
- align-items: center;
1228
- gap: var(--cb-space-2);
1229
- padding: var(--cb-space-2) var(--cb-space-2);
1230
- border-radius: var(--cb-radius-sm);
1231
- cursor: pointer;
1232
- outline: none;
1233
- color: var(--cb-fg);
1234
- }
1235
- .cb-select__item[data-highlighted] { background: color-mix(in oklch, var(--cb-tone-brand) 12%, transparent); }
1236
- .cb-select__item[data-selected] { font-weight: var(--cb-weight-medium); }
1237
- .cb-select__item[data-disabled] { color: var(--cb-fg-subtle); text-decoration: line-through; cursor: not-allowed; }
1238
- .cb-select__check { order: 2; display: inline-flex; justify-content: center; color: var(--cb-tone-brand); }
1239
-
1240
- /* form/upload.css */
1241
- .cb-filedrop { display: flex; flex-direction: column; gap: var(--cb-space-3); font-family: var(--cb-font-sans); }
1242
- .cb-filedrop__zone {
1243
- cursor: pointer;
1244
- display: flex;
1245
- flex-direction: column;
1246
- align-items: center;
1247
- gap: var(--cb-space-2);
1248
- padding: var(--cb-space-6) var(--cb-space-4);
1249
- border: 1px dashed var(--cb-border-strong);
1250
- border-radius: var(--cb-radius-lg);
1251
- background: var(--cb-surface);
1252
- text-align: center;
1253
- transition: border-color var(--cb-duration-fast) var(--cb-ease-standard),
1254
- background-color var(--cb-duration-fast) var(--cb-ease-standard);
1255
- }
1256
- .cb-filedrop__zone[data-over] {
1257
- border-color: var(--cb-tone-brand);
1258
- background: color-mix(in oklch, var(--cb-tone-brand) 8%, var(--cb-surface));
1259
- }
1260
- .cb-filedrop__zone[data-disabled] { opacity: 0.55; }
1261
- .cb-filedrop__icon { color: var(--cb-fg-subtle); }
1262
- .cb-filedrop__button {
1263
- color: var(--cb-tone-brand);
1264
- font-size: var(--cb-text-sm);
1265
- font-weight: var(--cb-weight-medium);
1266
- border-radius: var(--cb-radius-sm);
1267
- padding: var(--cb-space-1) var(--cb-space-2);
1268
- }
1269
- .cb-filedrop__zone:hover .cb-filedrop__button { background: color-mix(in oklch, var(--cb-tone-brand) 12%, transparent); }
1270
- /* The input is what receives focus, so the ring is drawn on the zone around it. */
1271
- .cb-filedrop__zone:has(input:focus-visible) {
1272
- outline: var(--cb-focus-width) solid var(--cb-tone-brand);
1273
- outline-offset: var(--cb-focus-offset);
1274
- }
1275
- .cb-filedrop__zone[data-disabled] { cursor: not-allowed; }
1276
- .cb-filedrop__hint { margin: 0; font-size: var(--cb-text-xs); color: var(--cb-fg-subtle); }
1277
-
1278
- .cb-filedrop__list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: var(--cb-space-2); }
1279
- .cb-filedrop__file {
1280
- margin: 0;
1281
- display: flex;
1282
- align-items: center;
1283
- gap: var(--cb-space-3);
1284
- padding: var(--cb-space-2) var(--cb-space-3);
1285
- border: var(--cb-border-width) solid var(--cb-border);
1286
- border-radius: var(--cb-radius-md);
1287
- background: var(--cb-surface);
1288
- font-size: var(--cb-text-sm);
1289
- }
1290
- .cb-filedrop__name { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--cb-fg); }
1291
- .cb-filedrop__size { font-size: var(--cb-text-xs); color: var(--cb-fg-subtle); font-variant-numeric: tabular-nums; }
1292
- .cb-filedrop__remove {
1293
- border: none;
1294
- background: transparent;
1295
- color: var(--cb-fg-subtle);
1296
- cursor: pointer;
1297
- display: inline-flex;
1298
- padding: var(--cb-space-1);
1299
- border-radius: var(--cb-radius-sm);
1300
- }
1301
- .cb-filedrop__remove:hover { color: var(--cb-tone-danger); background: color-mix(in oklch, var(--cb-tone-danger) 10%, transparent); }
1302
- .cb-filedrop__remove:focus-visible { outline: var(--cb-focus-width) solid var(--cb-tone-danger); outline-offset: var(--cb-focus-offset); }
1303
-
1304
- /* feedback/badge.css */
1305
- .cb-badge {
1306
- --cb-badge-accent: var(--cb-fg-muted);
1307
- display: inline-flex;
1308
- align-items: center;
1309
- gap: var(--cb-space-1);
1310
- border-radius: var(--cb-radius-full);
1311
- font-family: var(--cb-font-sans);
1312
- font-weight: var(--cb-weight-medium);
1313
- /* The line box must not out-measure the height above. Left at its default a
1314
- word sits in an 18px box and a 12px glyph in a 22px one, so two badges in a
1315
- row ended up two pixels apart for a reason neither of them chose. */
1316
- line-height: 1;
1317
- white-space: nowrap;
1318
- border: var(--cb-border-width) solid transparent;
1319
- }
1320
- /* A height, not just padding. Padding alone makes the height a function of the
1321
- content, so a badge carrying a glyph stands taller than the plain one beside
1322
- it — and a row of them then disagrees about its own size for a reason nobody
1323
- chose. One number per size, and the padding sits inside it. */
1324
- .cb-badge--sm {
1325
- font-size: 0.6875rem;
1326
- min-height: 1.375rem;
1327
- padding: 0.0625rem var(--cb-space-2);
1328
- }
1329
- .cb-badge--md {
1330
- font-size: var(--cb-text-xs);
1331
- min-height: 1.75rem;
1332
- padding: var(--cb-space-1) var(--cb-space-3);
1333
- }
1334
-
1335
- .cb-badge[data-tone="brand"] { --cb-badge-accent: var(--cb-tone-brand); }
1336
- .cb-badge[data-tone="info"] { --cb-badge-accent: var(--cb-tone-info); }
1337
- .cb-badge[data-tone="success"] { --cb-badge-accent: var(--cb-tone-success); }
1338
- .cb-badge[data-tone="warning"] { --cb-badge-accent: var(--cb-tone-warning); }
1339
- .cb-badge[data-tone="danger"] { --cb-badge-accent: var(--cb-tone-danger); }
1340
-
1341
- .cb-badge--soft { background: color-mix(in oklch, var(--cb-badge-accent) 14%, transparent); color: var(--cb-badge-accent); }
1342
- .cb-badge--solid { background: var(--cb-badge-accent); color: var(--cb-fg-on-brand); }
1343
- .cb-badge--outline { border-color: color-mix(in oklch, var(--cb-badge-accent) 45%, transparent); color: var(--cb-badge-accent); }
1344
- .cb-badge__dot { width: 0.375rem; height: 0.375rem; border-radius: var(--cb-radius-full); background: currentColor; }
1345
-
1346
- .cb-alert {
1347
- --cb-alert-accent: var(--cb-tone-info);
1348
- display: flex;
1349
- gap: var(--cb-space-3);
1350
- padding: var(--cb-space-4);
1351
- border-radius: var(--cb-radius-md);
1352
- border: var(--cb-border-width) solid color-mix(in oklch, var(--cb-alert-accent) 30%, transparent);
1353
- background: color-mix(in oklch, var(--cb-alert-accent) 9%, var(--cb-surface));
1354
- font-family: var(--cb-font-sans);
1355
- }
1356
- .cb-alert[data-tone="neutral"] { --cb-alert-accent: var(--cb-fg-muted); }
1357
- .cb-alert[data-tone="brand"] { --cb-alert-accent: var(--cb-tone-brand); }
1358
- .cb-alert[data-tone="success"] { --cb-alert-accent: var(--cb-tone-success); }
1359
- .cb-alert[data-tone="warning"] { --cb-alert-accent: var(--cb-tone-warning); }
1360
- .cb-alert[data-tone="danger"] { --cb-alert-accent: var(--cb-tone-danger); }
1361
-
1362
- .cb-alert__icon { flex: none; color: var(--cb-alert-accent); display: inline-flex; margin-top: 0.0625rem; }
1363
- .cb-alert__body { flex: 1; display: flex; flex-direction: column; gap: var(--cb-space-1); min-width: 0; }
1364
- .cb-alert__title { margin: 0; font-size: var(--cb-text-sm); font-weight: var(--cb-weight-semibold); color: var(--cb-fg); }
1365
- .cb-alert__text { font-size: var(--cb-text-sm); color: var(--cb-fg-muted); line-height: var(--cb-leading-normal); }
1366
- .cb-alert__actions { display: flex; gap: var(--cb-space-2); margin-top: var(--cb-space-2); }
1367
- .cb-alert__close {
1368
- flex: none; border: none; background: transparent; color: var(--cb-fg-subtle);
1369
- cursor: pointer; border-radius: var(--cb-radius-sm); padding: var(--cb-space-1); height: fit-content;
1370
- }
1371
- .cb-alert__close:hover { color: var(--cb-fg); background: color-mix(in oklch, var(--cb-fg) 8%, transparent); }
1372
- .cb-alert__close:focus-visible { outline: var(--cb-focus-width) solid var(--cb-alert-accent); outline-offset: var(--cb-focus-offset); }
1373
-
1374
- .cb-empty {
1375
- display: flex;
1376
- flex-direction: column;
1377
- align-items: center;
1378
- text-align: center;
1379
- gap: var(--cb-space-2);
1380
- padding: var(--cb-space-7) var(--cb-space-5);
1381
- font-family: var(--cb-font-sans);
1382
- }
1383
- .cb-empty__icon {
1384
- display: inline-flex;
1385
- align-items: center;
1386
- justify-content: center;
1387
- width: 3rem;
1388
- height: 3rem;
1389
- border-radius: var(--cb-radius-full);
1390
- background: var(--cb-bg-subtle);
1391
- color: var(--cb-fg-subtle);
1392
- margin-bottom: var(--cb-space-2);
1393
- }
1394
- .cb-empty[data-variant="error"] .cb-empty__icon {
1395
- background: color-mix(in oklch, var(--cb-tone-danger) 12%, transparent);
1396
- color: var(--cb-tone-danger);
1397
- }
1398
- .cb-empty__title { margin: 0; font-size: var(--cb-text-md); font-weight: var(--cb-weight-semibold); color: var(--cb-fg); }
1399
- .cb-empty__description { margin: 0; font-size: var(--cb-text-sm); color: var(--cb-fg-muted); max-width: 32rem; }
1400
- .cb-empty__actions { display: flex; gap: var(--cb-space-2); margin-top: var(--cb-space-3); }
1401
-
1402
- /* feedback/progress.css */
1403
- .cb-spin {
1404
- --cb-spin-accent: var(--cb-tone-brand);
1405
- display: inline-block;
1406
- border-radius: var(--cb-radius-full);
1407
- border: 2px solid color-mix(in oklch, var(--cb-spin-accent) 25%, transparent);
1408
- border-top-color: var(--cb-spin-accent);
1409
- animation: cb-spin calc(var(--cb-duration-deliberate) * 1.4) linear infinite;
1410
- }
1411
- .cb-spin[data-tone="neutral"] { --cb-spin-accent: var(--cb-fg-muted); }
1412
- .cb-spin[data-tone="info"] { --cb-spin-accent: var(--cb-tone-info); }
1413
- .cb-spin[data-tone="success"] { --cb-spin-accent: var(--cb-tone-success); }
1414
- .cb-spin[data-tone="warning"] { --cb-spin-accent: var(--cb-tone-warning); }
1415
- .cb-spin[data-tone="danger"] { --cb-spin-accent: var(--cb-tone-danger); }
1416
- .cb-spin--sm { width: 0.875rem; height: 0.875rem; }
1417
- .cb-spin--md { width: 1.25rem; height: 1.25rem; border-width: 2px; }
1418
- .cb-spin--lg { width: 2rem; height: 2rem; border-width: 3px; }
1419
- /* Reduced motion: it stops turning and reads as a ring — the surrounding text says "loading". */
1420
- @media (prefers-reduced-motion: reduce) {
1421
- .cb-spin { animation: none; opacity: 0.6; }
1422
- }
1423
-
1424
- .cb-progress {
1425
- --cb-progress-accent: var(--cb-tone-brand);
1426
- display: flex;
1427
- align-items: center;
1428
- gap: var(--cb-space-3);
1429
- width: 100%;
1430
- font-family: var(--cb-font-sans);
1431
- }
1432
- .cb-progress[data-tone="neutral"] { --cb-progress-accent: var(--cb-fg-muted); }
1433
- .cb-progress[data-tone="info"] { --cb-progress-accent: var(--cb-tone-info); }
1434
- .cb-progress[data-tone="success"] { --cb-progress-accent: var(--cb-tone-success); }
1435
- .cb-progress[data-tone="warning"] { --cb-progress-accent: var(--cb-tone-warning); }
1436
- .cb-progress[data-tone="danger"] { --cb-progress-accent: var(--cb-tone-danger); }
1437
-
1438
- .cb-progress__track {
1439
- flex: 1;
1440
- overflow: hidden;
1441
- border-radius: var(--cb-radius-full);
1442
- background: color-mix(in oklch, var(--cb-fg) 10%, transparent);
1443
- }
1444
- .cb-progress[data-size="sm"] .cb-progress__track { height: 0.25rem; }
1445
- .cb-progress[data-size="md"] .cb-progress__track { height: 0.5rem; }
1446
-
1447
- .cb-progress__fill {
1448
- height: 100%;
1449
- border-radius: inherit;
1450
- background: var(--cb-progress-accent);
1451
- transition: width var(--cb-duration-base) var(--cb-ease-standard);
1452
- }
1453
- .cb-progress__fill[data-indeterminate] {
1454
- width: 40%;
1455
- animation: cb-progress-slide calc(var(--cb-duration-deliberate) * 2) var(--cb-ease-standard) infinite;
1456
- }
1457
- @keyframes cb-progress-slide {
1458
- 0% { transform: translateX(-100%); }
1459
- 100% { transform: translateX(250%); }
1460
- }
1461
- /* Reduced motion: an indeterminate bar sits still at partial width rather than sliding forever. */
1462
- @media (prefers-reduced-motion: reduce) {
1463
- .cb-progress__fill { transition: none; }
1464
- .cb-progress__fill[data-indeterminate] { animation: none; width: 100%; opacity: 0.4; }
1465
- }
1466
-
1467
- .cb-progress__value {
1468
- font-size: var(--cb-text-xs);
1469
- color: var(--cb-fg-muted);
1470
- font-variant-numeric: tabular-nums;
1471
- min-width: 2.5rem;
1472
- text-align: end;
1473
- }
1474
-
1475
- /* feedback/skeleton.css */
1476
- .cb-skeleton {
1477
- display: block;
1478
- width: var(--cb-skeleton-w);
1479
- height: var(--cb-skeleton-h);
1480
- position: relative;
1481
- overflow: hidden;
1482
- background: color-mix(in oklch, var(--cb-fg) 8%, var(--cb-surface));
1483
- }
1484
- .cb-skeleton::after {
1485
- content: "";
1486
- position: absolute;
1487
- inset: 0;
1488
- transform: translateX(-100%);
1489
- background: linear-gradient(
1490
- 90deg,
1491
- transparent,
1492
- color-mix(in oklch, var(--cb-fg) 6%, transparent),
1493
- transparent
1494
- );
1495
- animation: cb-skeleton-sweep calc(var(--cb-duration-deliberate) * 2) var(--cb-ease-standard) infinite;
1496
- }
1497
- @keyframes cb-skeleton-sweep {
1498
- 100% { transform: translateX(100%); }
1499
- }
1500
-
1501
- /* Reduced motion keeps the shape and drops the sweep — the placeholder still reads as loading. */
1502
- @media (prefers-reduced-motion: reduce) {
1503
- .cb-skeleton::after { animation: none; }
1504
- }
1505
-
1506
- .cb-skeleton-text { display: flex; flex-direction: column; gap: var(--cb-space-2); }
1507
-
1508
- /* feedback/tag.css */
1509
- /* The look is Badge's, literally — the same `cb-badge` classes rather than a
1510
- second set that would agree today and drift apart later. Only what a Tag can
1511
- do that a Badge cannot lives here. */
1512
- .cb-tag { max-width: 100%; }
1513
-
1514
- .cb-tag--pressable {
1515
- border-width: var(--cb-border-width);
1516
- cursor: pointer;
1517
- text-decoration: none;
1518
- /* NOT `font: inherit`. The shorthand resets size and line-height too, so a
1519
- pressable tag took the page's 16px and stood two pixels taller than the
1520
- badge beside it — the size classes were being overruled by a reset meant
1521
- only to undo the browser's button face. */
1522
- font-family: inherit;
1523
- font-weight: inherit;
1524
- transition: border-color var(--cb-duration-fast) var(--cb-ease-standard),
1525
- background-color var(--cb-duration-fast) var(--cb-ease-standard);
1526
- }
1527
- .cb-tag--pressable:hover { border-color: var(--cb-tone-brand); }
1528
- .cb-tag--pressable:focus-visible {
1529
- outline: var(--cb-focus-width) solid var(--cb-tone-brand);
1530
- outline-offset: var(--cb-focus-offset);
1531
- }
1532
- .cb-tag--pressable[aria-pressed="true"] { border-color: var(--cb-tone-brand); }
1533
-
1534
- .cb-tag__close {
1535
- display: inline-flex;
1536
- align-items: center;
1537
- justify-content: center;
1538
- margin-inline-start: var(--cb-space-1);
1539
- margin-inline-end: calc(var(--cb-space-1) * -1);
1540
- padding: 0;
1541
- border: 0;
1542
- border-radius: var(--cb-radius-full);
1543
- background: none;
1544
- color: inherit;
1545
- opacity: 0.7;
1546
- cursor: pointer;
1547
- }
1548
- .cb-tag__close:hover { opacity: 1; }
1549
- .cb-tag__close:focus-visible {
1550
- outline: var(--cb-focus-width) solid currentColor;
1551
- outline-offset: 1px;
1552
- opacity: 1;
1553
- }
1554
-
1555
- @media (prefers-reduced-motion: reduce) {
1556
- .cb-tag--pressable { transition: none; }
1557
- }
1558
-
1559
- /* feedback/toast.css */
1560
- .cb-toast__viewport {
1561
- position: fixed;
1562
- z-index: var(--cb-z-toast);
1563
- display: flex;
1564
- flex-direction: column;
1565
- gap: var(--cb-space-2);
1566
- width: min(22rem, calc(100vw - var(--cb-space-6)));
1567
- }
1568
- .cb-toast__viewport[data-position^="bottom"] { inset-block-end: var(--cb-space-4); }
1569
- .cb-toast__viewport[data-position^="top"] { inset-block-start: var(--cb-space-4); }
1570
- .cb-toast__viewport[data-position$="end"] { inset-inline-end: var(--cb-space-4); }
1571
- .cb-toast__viewport[data-position$="start"] { inset-inline-start: var(--cb-space-4); }
1572
- .cb-toast__viewport[data-position$="center"] { inset-inline-start: 50%; translate: -50% 0; }
1573
- /* A stack at the top should enter from above, not slide up from below. */
1574
- .cb-toast__viewport[data-position^="top"] .cb-toast[data-starting-style],
1575
- .cb-toast__viewport[data-position^="top"] .cb-toast[data-ending-style] { transform: translateY(-8px); }
1576
-
1577
- .cb-toast {
1578
- --cb-toast-accent: var(--cb-tone-info);
1579
- display: grid;
1580
- grid-template-columns: auto minmax(0, 1fr) auto;
1581
- grid-template-areas:
1582
- "icon content close"
1583
- ". action .";
1584
- align-items: start;
1585
- column-gap: var(--cb-space-3);
1586
- row-gap: var(--cb-space-2);
1587
- box-sizing: border-box;
1588
- width: 100%;
1589
- padding: var(--cb-space-3) var(--cb-space-4);
1590
- border-radius: var(--cb-radius-md);
1591
- border: var(--cb-border-width) solid var(--cb-border);
1592
- background: var(--cb-surface-raised);
1593
- box-shadow: var(--cb-shadow-md);
1594
- font-family: var(--cb-font-sans);
1595
- transition: opacity var(--cb-duration-base) var(--cb-ease-entrance),
1596
- transform var(--cb-duration-base) var(--cb-ease-entrance);
1597
- }
1598
- .cb-toast[data-tone="success"] { --cb-toast-accent: var(--cb-tone-success); }
1599
- .cb-toast[data-tone="warning"] { --cb-toast-accent: var(--cb-tone-warning); }
1600
- .cb-toast[data-tone="danger"] { --cb-toast-accent: var(--cb-tone-danger); }
1601
- .cb-toast[data-starting-style],
1602
- .cb-toast[data-ending-style] { opacity: 0; transform: translateY(8px); }
1603
- @media (prefers-reduced-motion: reduce) {
1604
- .cb-toast { transition: opacity var(--cb-duration-fast) linear; }
1605
- .cb-toast[data-starting-style],
1606
- .cb-toast[data-ending-style] { transform: none; }
1607
- }
1608
-
1609
- .cb-toast__icon { grid-area: icon; color: var(--cb-toast-accent); display: inline-flex; margin-top: 0.125rem; }
1610
- .cb-toast__content { grid-area: content; display: flex; flex-direction: column; gap: 0.125rem; min-width: 0; }
1611
- /* Base UI renders these as <h2> and <p>, which inherit the host app's heading and paragraph
1612
- margins — without this reset a two-line toast is twice as tall in one app as in another. */
1613
- .cb-toast__title { margin: 0; font-size: var(--cb-text-sm); font-weight: var(--cb-weight-semibold); color: var(--cb-fg); }
1614
- .cb-toast__description { margin: 0; font-size: var(--cb-text-sm); color: var(--cb-fg-muted); }
1615
- /* A bare text action reads as misaligned until it is hovered: its padding pushes the label off
1616
- the line the title sits on, and nothing explains the gap. Carrying the soft Button treatment
1617
- at rest makes the padding part of a control instead of stray space. */
1618
- .cb-toast__action {
1619
- grid-area: action;
1620
- justify-self: start;
1621
- display: inline-flex;
1622
- align-items: center;
1623
- height: var(--cb-control-height-sm);
1624
- padding-inline: var(--cb-space-3);
1625
- border: none;
1626
- border-radius: var(--cb-radius-md);
1627
- background: color-mix(in oklch, var(--cb-toast-accent) 16%, transparent);
1628
- color: var(--cb-toast-accent);
1629
- font-family: var(--cb-font-sans);
1630
- font-size: var(--cb-text-sm);
1631
- font-weight: var(--cb-weight-medium);
1632
- cursor: pointer;
1633
- transition: background-color var(--cb-duration-fast) var(--cb-ease-standard);
1634
- }
1635
- .cb-toast__action:hover { background: color-mix(in oklch, var(--cb-toast-accent) 26%, transparent); }
1636
- /* An action-less toast must not reserve the row it would have sat in. */
1637
- .cb-toast:not(:has(.cb-toast__action)) { grid-template-areas: "icon content close"; }
1638
- .cb-toast__close {
1639
- grid-area: close;
1640
- border: none;
1641
- background: transparent;
1642
- color: var(--cb-fg-subtle);
1643
- cursor: pointer;
1644
- padding: var(--cb-space-1);
1645
- border-radius: var(--cb-radius-sm);
1646
- }
1647
- .cb-toast__close:hover { color: var(--cb-fg); }
1648
- .cb-toast__close:focus-visible,
1649
- .cb-toast__action:focus-visible { outline: var(--cb-focus-width) solid var(--cb-toast-accent); outline-offset: var(--cb-focus-offset); }
1650
-
1651
- /* overlay/command-palette.css */
1652
- .cb-palette__backdrop {
1653
- position: fixed;
1654
- inset: 0;
1655
- z-index: var(--cb-z-command-backdrop);
1656
- background: var(--cb-scrim);
1657
- backdrop-filter: blur(2px);
1658
- transition: opacity var(--cb-duration-base) var(--cb-ease-entrance);
1659
- }
1660
- .cb-palette__backdrop[data-starting-style],
1661
- .cb-palette__backdrop[data-ending-style] { opacity: 0; }
1662
-
1663
- .cb-palette {
1664
- position: fixed;
1665
- top: 12vh;
1666
- left: 50%;
1667
- translate: -50% 0;
1668
- z-index: var(--cb-z-command);
1669
- display: flex;
1670
- flex-direction: column;
1671
- width: min(34rem, calc(100vw - var(--cb-space-6)));
1672
- max-height: 60vh;
1673
- box-sizing: border-box;
1674
- background: var(--cb-surface-raised);
1675
- border: var(--cb-border-width) solid var(--cb-border);
1676
- border-radius: var(--cb-radius-lg);
1677
- box-shadow: var(--cb-shadow-lg);
1678
- overflow: hidden;
1679
- font-family: var(--cb-font-sans);
1680
- transition: opacity var(--cb-duration-base) var(--cb-ease-entrance),
1681
- translate var(--cb-duration-base) var(--cb-ease-entrance);
1682
- }
1683
- .cb-palette[data-starting-style],
1684
- .cb-palette[data-ending-style] { opacity: 0; translate: -50% -0.5rem; }
1685
- @media (prefers-reduced-motion: reduce) {
1686
- .cb-palette__backdrop { transition: opacity var(--cb-duration-fast) linear; }
1687
- .cb-palette { transition: opacity var(--cb-duration-fast) linear; }
1688
- .cb-palette[data-starting-style],
1689
- .cb-palette[data-ending-style] { translate: -50% 0; }
1690
- }
1691
-
1692
- .cb-palette__search {
1693
- display: flex;
1694
- align-items: center;
1695
- gap: var(--cb-space-3);
1696
- padding: var(--cb-space-4);
1697
- border-bottom: var(--cb-border-width) solid var(--cb-border);
1698
- }
1699
- .cb-palette__search-icon { color: var(--cb-fg-subtle); flex: none; }
1700
- .cb-palette__input {
1701
- flex: 1;
1702
- border: none;
1703
- background: transparent;
1704
- color: var(--cb-fg);
1705
- font-family: inherit;
1706
- font-size: var(--cb-text-md);
1707
- outline: none;
1708
- }
1709
- .cb-palette__input::placeholder { color: var(--cb-fg-subtle); }
1710
-
1711
- .cb-palette__list { overflow-y: auto; padding: var(--cb-space-2); }
1712
- .cb-palette__group + .cb-palette__group { margin-top: var(--cb-space-2); }
1713
- .cb-palette__group-label {
1714
- margin: 0 0 var(--cb-space-1);
1715
- padding-inline: var(--cb-space-2);
1716
- font-size: 0.6875rem;
1717
- text-transform: uppercase;
1718
- letter-spacing: 0.08em;
1719
- color: var(--cb-fg-subtle);
1720
- }
1721
- .cb-palette__item {
1722
- display: flex;
1723
- align-items: center;
1724
- gap: var(--cb-space-3);
1725
- padding: var(--cb-space-2) var(--cb-space-3);
1726
- border-radius: var(--cb-radius-sm);
1727
- font-size: var(--cb-text-sm);
1728
- color: var(--cb-fg);
1729
- cursor: pointer;
1730
- }
1731
- .cb-palette__item[data-active] { background: color-mix(in oklch, var(--cb-tone-brand) 12%, transparent); }
1732
- .cb-palette__icon { display: inline-flex; color: var(--cb-fg-subtle); width: 1.25rem; justify-content: center; }
1733
- .cb-palette__label { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
1734
- .cb-palette__shortcut { margin: 0; padding: 0; border: none; background: none; font-family: var(--cb-font-mono); font-size: var(--cb-text-xs); color: var(--cb-fg-subtle); }
1735
- .cb-palette__empty { margin: 0; padding: var(--cb-space-5); text-align: center; font-size: var(--cb-text-sm); color: var(--cb-fg-subtle); }
1736
-
1737
- /* overlay/drawer.css */
1738
- .cb-drawer__backdrop {
1739
- position: fixed;
1740
- inset: 0;
1741
- z-index: var(--cb-z-modal-backdrop);
1742
- background: var(--cb-scrim);
1743
- backdrop-filter: blur(2px);
1744
- transition: opacity var(--cb-duration-base) var(--cb-ease-standard);
1745
- }
1746
- .cb-drawer__backdrop[data-starting-style],
1747
- .cb-drawer__backdrop[data-ending-style] { opacity: 0; }
1748
-
1749
- .cb-drawer {
1750
- position: fixed;
1751
- z-index: var(--cb-z-modal);
1752
- inset-block: 0;
1753
- inset-inline-end: 0;
1754
- display: flex;
1755
- flex-direction: column;
1756
- gap: var(--cb-space-3);
1757
- box-sizing: border-box;
1758
- width: min(22rem, calc(100vw - var(--cb-space-6)));
1759
- height: 100dvh;
1760
- padding: var(--cb-space-5);
1761
- overflow: hidden;
1762
- background: var(--cb-surface-raised);
1763
- color: var(--cb-fg);
1764
- border-inline-start: var(--cb-border-width) solid var(--cb-border);
1765
- border-radius: var(--cb-radius-lg) 0 0 var(--cb-radius-lg);
1766
- box-shadow: var(--cb-shadow-lg);
1767
- transform: translateX(0);
1768
- transition: opacity var(--cb-duration-base) var(--cb-ease-entrance),
1769
- transform var(--cb-duration-base) var(--cb-ease-entrance);
1770
- }
1771
- .cb-drawer[data-starting-style],
1772
- .cb-drawer[data-ending-style] { opacity: 0; transform: translateX(100%); }
1773
-
1774
- @media (prefers-reduced-motion: reduce) {
1775
- .cb-drawer { transition: opacity var(--cb-duration-fast) linear; }
1776
- .cb-drawer[data-starting-style],
1777
- .cb-drawer[data-ending-style] { transform: translateX(0); }
1778
- }
1779
-
1780
- .cb-drawer__title { margin: 0; font-family: var(--cb-font-sans); font-size: var(--cb-text-lg); font-weight: var(--cb-weight-semibold); }
1781
- .cb-drawer__description { margin: 0; font-family: var(--cb-font-sans); font-size: var(--cb-text-sm); color: var(--cb-fg-muted); }
1782
- /* Same scrollbar as the Modal's body, same answer — see modal.css. */
1783
- .cb-drawer__body {
1784
- min-height: 0;
1785
- flex: 1;
1786
- overflow-y: auto;
1787
- scrollbar-gutter: stable;
1788
- margin-inline: calc(-1 * var(--cb-space-5));
1789
- padding-inline: var(--cb-space-5);
1790
- font-family: var(--cb-font-sans);
1791
- font-size: var(--cb-text-sm);
1792
- }
1793
- .cb-drawer__footer { display: flex; justify-content: flex-end; gap: var(--cb-space-2); }
1794
-
1795
- /* overlay/modal.css */
1796
- .cb-modal__backdrop {
1797
- position: fixed;
1798
- inset: 0;
1799
- z-index: var(--cb-z-modal-backdrop);
1800
- background: var(--cb-scrim);
1801
- backdrop-filter: blur(2px);
1802
- transition: opacity var(--cb-duration-base) var(--cb-ease-standard);
1803
- }
1804
- .cb-modal__backdrop[data-starting-style],
1805
- .cb-modal__backdrop[data-ending-style] { opacity: 0; }
1806
-
1807
- .cb-modal {
1808
- position: fixed;
1809
- z-index: var(--cb-z-modal);
1810
- display: flex;
1811
- flex-direction: column;
1812
- gap: var(--cb-space-3);
1813
- box-sizing: border-box;
1814
- background: var(--cb-surface-raised);
1815
- color: var(--cb-fg);
1816
- border: var(--cb-border-width) solid var(--cb-border);
1817
- border-radius: var(--cb-radius-lg);
1818
- box-shadow: var(--cb-shadow-lg);
1819
- padding: var(--cb-space-5);
1820
- width: calc(100vw - var(--cb-space-6));
1821
- max-height: calc(100dvh - var(--cb-space-6));
1822
- transition: opacity var(--cb-duration-base) var(--cb-ease-entrance),
1823
- transform var(--cb-duration-base) var(--cb-ease-entrance);
1824
- }
1825
- .cb-modal--sm { max-width: 24rem; }
1826
- .cb-modal--md { max-width: 32rem; }
1827
- .cb-modal--lg { max-width: 46rem; }
1828
-
1829
- .cb-modal--center { top: 50%; left: 50%; transform: translate(-50%, -50%) scale(1); }
1830
- .cb-modal--center[data-starting-style],
1831
- .cb-modal--center[data-ending-style] { opacity: 0; transform: translate(-50%, -48%) scale(0.96); }
1832
-
1833
- .cb-modal--end { inset-inline-end: var(--cb-space-4); inset-block-end: var(--cb-space-4); transform: translateY(0); }
1834
- .cb-modal--end[data-starting-style],
1835
- .cb-modal--end[data-ending-style] { opacity: 0; transform: translateY(12px); }
1836
-
1837
- /* Reduced motion: the dialog still fades so its arrival is not invisible, but it stops moving. */
1838
- @media (prefers-reduced-motion: reduce) {
1839
- .cb-modal { transition: opacity var(--cb-duration-fast) linear; }
1840
- .cb-modal--center[data-starting-style],
1841
- .cb-modal--center[data-ending-style] { transform: translate(-50%, -50%) scale(1); }
1842
- .cb-modal--end[data-starting-style],
1843
- .cb-modal--end[data-ending-style] { transform: translateY(0); }
1844
- }
1845
-
1846
- .cb-modal__title { margin: 0; font-family: var(--cb-font-sans); font-size: var(--cb-text-lg); font-weight: var(--cb-weight-semibold); }
1847
- .cb-modal__description { margin: 0; font-family: var(--cb-font-sans); font-size: var(--cb-text-sm); color: var(--cb-fg-muted); }
1848
- /* The body is the only scrolling part of the dialog, and a scroller draws its
1849
- bar at its own inline edge — which, with the body running to the content edge,
1850
- is the right edge of every field inside it. Platforms differ in how that looks
1851
- and neither way is acceptable: macOS and Android float an overlay bar over the
1852
- field, Windows reserves real width and squeezes it.
1853
-
1854
- So both halves are needed. `scrollbar-gutter: stable` keeps the reserved bar
1855
- out of the content box — always, not only while the content overflows, so a
1856
- field appearing does not shift the rest sideways. The bleed-and-pad puts a
1857
- space-5 margin between the content and the edge where an overlay bar is drawn,
1858
- and hands the width back to the dialog so the padding costs nothing. It also
1859
- stops a focused field's ring being clipped at the scroller's edge. */
1860
- .cb-modal__body {
1861
- min-height: 0;
1862
- overflow-y: auto;
1863
- scrollbar-gutter: stable;
1864
- margin-inline: calc(-1 * var(--cb-space-5));
1865
- padding-inline: var(--cb-space-5);
1866
- font-family: var(--cb-font-sans);
1867
- font-size: var(--cb-text-sm);
1868
- }
1869
- .cb-modal__footer { flex: none; display: flex; justify-content: flex-end; gap: var(--cb-space-2); margin-top: var(--cb-space-2); }
1870
-
1871
- /* overlay/popover.css */
1872
- .cb-popover-positioner { z-index: var(--cb-z-popover); }
1873
- .cb-tooltip-positioner { z-index: var(--cb-z-tooltip); }
1874
-
1875
- .cb-popover {
1876
- box-sizing: border-box;
1877
- max-width: 22rem;
1878
- background: var(--cb-surface-raised);
1879
- color: var(--cb-fg);
1880
- border: var(--cb-border-width) solid var(--cb-border);
1881
- border-radius: var(--cb-radius-md);
1882
- box-shadow: var(--cb-shadow-md);
1883
- padding: var(--cb-space-4);
1884
- font-family: var(--cb-font-sans);
1885
- font-size: var(--cb-text-sm);
1886
- transition: opacity var(--cb-duration-fast) var(--cb-ease-entrance),
1887
- transform var(--cb-duration-fast) var(--cb-ease-entrance);
1888
- }
1889
- .cb-popover[data-starting-style],
1890
- .cb-popover[data-ending-style] { opacity: 0; transform: scale(0.96); }
1891
- @media (prefers-reduced-motion: reduce) {
1892
- .cb-popover { transition: opacity var(--cb-duration-fast) linear; }
1893
- .cb-popover[data-starting-style],
1894
- .cb-popover[data-ending-style] { transform: none; }
1895
- }
1896
-
1897
- /* Base UI positions this wrapper along the anchor edge. The SVG fill overlaps the popup edge by
1898
- one pixel, hiding its border below the tail; only the two outward edges receive a stroke. */
1899
- .cb-popover__arrow,
1900
- .cb-tooltip__arrow {
1901
- --cb-arrow-bg: var(--cb-surface-raised);
1902
- --cb-arrow-border: var(--cb-border);
1903
- position: absolute;
1904
- display: block;
1905
- width: 16px;
1906
- height: 8px;
1907
- overflow: visible;
1908
- pointer-events: none;
1909
- }
1910
- .cb-popover__arrow[data-side="bottom"],
1911
- .cb-tooltip__arrow[data-side="bottom"] { top: -7px; }
1912
- .cb-popover__arrow[data-side="top"],
1913
- .cb-tooltip__arrow[data-side="top"] { bottom: -7px; rotate: 180deg; }
1914
- .cb-popover__arrow[data-side="left"],
1915
- .cb-tooltip__arrow[data-side="left"] { right: -11px; rotate: 90deg; }
1916
- .cb-popover__arrow[data-side="right"],
1917
- .cb-tooltip__arrow[data-side="right"] { left: -11px; rotate: -90deg; }
1918
-
1919
- .cb-arrow {
1920
- display: block;
1921
- width: 100%;
1922
- height: 100%;
1923
- overflow: visible;
1924
- }
1925
- .cb-arrow__fill { fill: var(--cb-arrow-bg); }
1926
- .cb-arrow__edge {
1927
- fill: none;
1928
- stroke: var(--cb-arrow-border);
1929
- stroke-width: var(--cb-border-width);
1930
- stroke-linecap: round;
1931
- stroke-linejoin: round;
1932
- vector-effect: non-scaling-stroke;
1933
- }
1934
-
1935
- .cb-tooltip {
1936
- background: var(--cb-fg);
1937
- color: var(--cb-bg);
1938
- font-family: var(--cb-font-sans);
1939
- font-size: var(--cb-text-xs);
1940
- padding: var(--cb-space-1) var(--cb-space-2);
1941
- border-radius: var(--cb-radius-sm);
1942
- transition: opacity var(--cb-duration-fast) var(--cb-ease-standard);
1943
- }
1944
- .cb-tooltip__arrow {
1945
- --cb-arrow-bg: var(--cb-fg);
1946
- --cb-arrow-border: var(--cb-fg);
1947
- }
1948
- .cb-tooltip[data-starting-style],
1949
- .cb-tooltip[data-ending-style] { opacity: 0; }
1950
-
1951
- /* data/donut.css */
1952
- .cb-donut { position: relative; display: inline-grid; place-items: center; }
1953
- .cb-donut svg { position: absolute; inset: 0; }
1954
- .cb-donut__track { stroke: color-mix(in oklch, var(--cb-fg) 8%, transparent); }
1955
- .cb-donut__arc { transition: stroke-dasharray var(--cb-duration-deliberate) var(--cb-ease-entrance); }
1956
- /* Reduced motion: the arcs are drawn at their final length rather than growing into place. */
1957
- @media (prefers-reduced-motion: reduce) {
1958
- .cb-donut__arc { transition: none; }
1959
- }
1960
- .cb-donut__arc[data-hue="violet"] { stroke: var(--cb-decor-violet); }
1961
- .cb-donut__arc[data-hue="blue"] { stroke: var(--cb-decor-blue); }
1962
- .cb-donut__arc[data-hue="teal"] { stroke: var(--cb-decor-teal); }
1963
- .cb-donut__arc[data-hue="green"] { stroke: var(--cb-decor-green); }
1964
- .cb-donut__arc[data-hue="amber"] { stroke: var(--cb-decor-amber); }
1965
- .cb-donut__arc[data-hue="rose"] { stroke: var(--cb-decor-rose); }
1966
- .cb-donut__center {
1967
- font-family: var(--cb-font-sans);
1968
- font-variant-numeric: tabular-nums;
1969
- text-align: center;
1970
- color: var(--cb-fg);
1971
- z-index: 1;
677
+ z-index: 1;
1972
678
  }
1973
679
 
1974
680
  .cb-sparkline { --cb-spark-accent: var(--cb-tone-brand); display: inline-flex; }
@@ -1997,469 +703,90 @@ html, body { background: var(--cb-bg); color: var(--cb-fg); }
1997
703
  display: flex;
1998
704
  align-items: center;
1999
705
  gap: var(--cb-space-3);
2000
- padding: var(--cb-space-2) var(--cb-space-3);
2001
- border-radius: var(--cb-radius-md);
2002
- border: var(--cb-border-width) solid transparent;
2003
- }
2004
- .cb-leaderboard__row[data-rank="1"] { --cb-rank-accent: var(--cb-decor-amber); }
2005
- .cb-leaderboard__row[data-rank="2"] { --cb-rank-accent: var(--cb-fg-subtle); }
2006
- .cb-leaderboard__row[data-rank="3"] { --cb-rank-accent: var(--cb-decor-rose); }
2007
- .cb-leaderboard__row[data-rank] {
2008
- background: color-mix(in oklch, var(--cb-rank-accent) 12%, transparent);
2009
- }
2010
- .cb-leaderboard__row[data-you] {
2011
- border-color: color-mix(in oklch, var(--cb-tone-brand) 45%, transparent);
2012
- background: color-mix(in oklch, var(--cb-tone-brand) 10%, transparent);
2013
- }
2014
-
2015
- .cb-leaderboard__rank {
2016
- flex: none;
2017
- width: 1.5rem;
2018
- text-align: center;
2019
- font-size: var(--cb-text-sm);
2020
- font-weight: var(--cb-weight-semibold);
2021
- font-variant-numeric: tabular-nums;
2022
- color: var(--cb-fg-subtle);
2023
- }
2024
- .cb-leaderboard__row[data-rank] .cb-leaderboard__rank { color: color-mix(in oklch, var(--cb-rank-accent) 70%, var(--cb-fg)); }
2025
-
2026
- .cb-leaderboard__text { flex: 1; display: flex; flex-direction: column; gap: 0.0625rem; min-width: 0; }
2027
- .cb-leaderboard__name { display: flex; align-items: center; gap: var(--cb-space-2); font-size: var(--cb-text-sm); color: var(--cb-fg); }
2028
- .cb-leaderboard__you {
2029
- font-size: 0.625rem;
2030
- text-transform: uppercase;
2031
- letter-spacing: 0.06em;
2032
- color: var(--cb-tone-brand);
2033
- background: color-mix(in oklch, var(--cb-tone-brand) 14%, transparent);
2034
- border-radius: var(--cb-radius-full);
2035
- padding: 0 var(--cb-space-2);
2036
- }
2037
- .cb-leaderboard__detail { font-size: var(--cb-text-xs); color: var(--cb-fg-subtle); }
2038
- .cb-leaderboard__delta { font-size: var(--cb-text-xs); font-variant-numeric: tabular-nums; }
2039
- .cb-leaderboard__delta[data-direction="up"] { color: var(--cb-tone-success); }
2040
- .cb-leaderboard__delta[data-direction="down"] { color: var(--cb-tone-danger); }
2041
- .cb-leaderboard__delta[data-direction="flat"] { color: var(--cb-fg-subtle); }
2042
- .cb-leaderboard__score { font-size: var(--cb-text-sm); font-weight: var(--cb-weight-semibold); font-variant-numeric: tabular-nums; color: var(--cb-fg); }
2043
-
2044
- /* data/progress-ring.css */
2045
- .cb-ring {
2046
- --cb-ring-accent: var(--cb-tone-brand);
2047
- position: relative;
2048
- width: var(--cb-ring-size);
2049
- height: var(--cb-ring-size);
2050
- display: inline-grid;
2051
- place-items: center;
2052
- }
2053
- .cb-ring[data-tone="neutral"] { --cb-ring-accent: var(--cb-tone-neutral); }
2054
- .cb-ring[data-tone="info"] { --cb-ring-accent: var(--cb-tone-info); }
2055
- .cb-ring[data-tone="success"] { --cb-ring-accent: var(--cb-tone-success); }
2056
- .cb-ring[data-tone="warning"] { --cb-ring-accent: var(--cb-tone-warning); }
2057
- .cb-ring[data-tone="danger"] { --cb-ring-accent: var(--cb-tone-danger); }
2058
- .cb-ring[data-hue="violet"] { --cb-ring-accent: var(--cb-decor-violet); }
2059
- .cb-ring[data-hue="blue"] { --cb-ring-accent: var(--cb-decor-blue); }
2060
- .cb-ring[data-hue="teal"] { --cb-ring-accent: var(--cb-decor-teal); }
2061
- .cb-ring[data-hue="green"] { --cb-ring-accent: var(--cb-decor-green); }
2062
- .cb-ring[data-hue="amber"] { --cb-ring-accent: var(--cb-decor-amber); }
2063
- .cb-ring[data-hue="rose"] { --cb-ring-accent: var(--cb-decor-rose); }
2064
-
2065
- .cb-ring svg { position: absolute; inset: 0; }
2066
- .cb-ring__track { stroke: color-mix(in oklch, var(--cb-ring-accent) 16%, transparent); }
2067
- .cb-ring__value {
2068
- stroke: var(--cb-ring-accent);
2069
- animation: cb-ring-fill var(--cb-duration-deliberate) var(--cb-ease-entrance) both;
2070
- }
2071
- @keyframes cb-ring-fill {
2072
- from { stroke-dashoffset: var(--cb-ring-circumference); }
2073
- to { stroke-dashoffset: var(--cb-ring-offset); }
2074
- }
2075
- /* Reduced motion: the arc is drawn at its final length rather than swept into place. */
2076
- @media (prefers-reduced-motion: reduce) {
2077
- .cb-ring__value { animation: none; }
2078
- }
2079
-
2080
- .cb-ring__center {
2081
- font-family: var(--cb-font-sans);
2082
- font-variant-numeric: tabular-nums;
2083
- font-weight: var(--cb-weight-semibold);
2084
- font-size: var(--cb-text-lg);
2085
- color: var(--cb-fg);
2086
- }
2087
-
2088
- /* data/statistic.css */
2089
- .cb-stat { display: flex; flex-direction: column; gap: var(--cb-space-3); }
2090
- .cb-stat__head { display: flex; align-items: center; justify-content: space-between; gap: var(--cb-space-2); }
2091
- .cb-stat__icon { display: inline-flex; color: var(--cb-surface-accent); }
2092
- .cb-stat__body { display: flex; align-items: center; justify-content: space-between; gap: var(--cb-space-4); }
2093
- .cb-stat__skeleton-col { display: flex; flex-direction: column; gap: var(--cb-space-2); }
2094
-
2095
- .cb-stat__value {
2096
- margin: 0;
2097
- font-family: var(--cb-font-sans);
2098
- font-size: var(--cb-text-2xl);
2099
- font-weight: var(--cb-weight-semibold);
2100
- line-height: var(--cb-leading-tight);
2101
- color: var(--cb-fg);
2102
- }
2103
-
2104
- .cb-stat__delta {
2105
- display: inline-block;
2106
- margin-top: var(--cb-space-1);
2107
- font-family: var(--cb-font-sans);
2108
- font-size: var(--cb-text-xs);
2109
- font-weight: var(--cb-weight-medium);
2110
- font-variant-numeric: tabular-nums;
2111
- padding: var(--cb-space-1) var(--cb-space-2);
2112
- border-radius: var(--cb-radius-full);
2113
- }
2114
- .cb-stat__delta[data-direction="up"] {
2115
- color: var(--cb-tone-success);
2116
- background: color-mix(in oklch, var(--cb-tone-success) 14%, transparent);
2117
- }
2118
- .cb-stat__delta[data-direction="down"] {
2119
- color: var(--cb-tone-danger);
2120
- background: color-mix(in oklch, var(--cb-tone-danger) 14%, transparent);
2121
- }
2122
- .cb-stat__delta[data-direction="flat"] {
2123
- color: var(--cb-fg-muted);
2124
- background: color-mix(in oklch, var(--cb-fg-muted) 12%, transparent);
2125
- }
2126
- .cb-stat__caption { margin-top: var(--cb-space-2); }
2127
-
2128
- /* data/table.css */
2129
- .cb-table__scroll {
2130
- width: 100%;
2131
- overflow-x: auto;
2132
- border: var(--cb-border-width) solid var(--cb-border);
2133
- border-radius: var(--cb-radius-lg);
2134
- background: var(--cb-surface);
2135
- }
2136
- .cb-table { width: 100%; border-collapse: collapse; font-family: var(--cb-font-sans); font-size: var(--cb-text-sm); }
2137
-
2138
- .cb-table th {
2139
- text-align: start;
2140
- font-size: var(--cb-text-xs);
2141
- font-weight: var(--cb-weight-medium);
2142
- color: var(--cb-fg-subtle);
2143
- text-transform: uppercase;
2144
- letter-spacing: 0.05em;
2145
- padding: var(--cb-space-2) var(--cb-space-3);
2146
- border-bottom: var(--cb-border-width) solid var(--cb-border);
2147
- white-space: nowrap;
2148
- background: var(--cb-bg-subtle);
2149
- }
2150
- .cb-table td {
2151
- padding: var(--cb-space-2) var(--cb-space-3);
2152
- height: 3rem;
2153
- border-bottom: var(--cb-border-width) solid var(--cb-border);
2154
- color: var(--cb-fg);
2155
- vertical-align: middle;
2156
- }
2157
- .cb-table tbody tr:last-child td { border-bottom: none; }
2158
- .cb-table [data-align="end"] { text-align: end; }
2159
- /* Truncation needs a bound to truncate against, which a table cell only gets from max-width. */
2160
- .cb-table td[data-truncate] {
2161
- max-width: 1px;
2162
- overflow: hidden;
2163
- text-overflow: ellipsis;
2164
- white-space: nowrap;
2165
- }
2166
-
2167
- /* First and last cells keep the table's own gutter, so content lines up with the panel edge
2168
- rather than floating a second inset inside it. */
2169
- .cb-table th:first-child,
2170
- .cb-table td:first-child { padding-inline-start: var(--cb-space-4); }
2171
- .cb-table th:last-child,
2172
- .cb-table td:last-child { padding-inline-end: var(--cb-space-2); }
2173
-
2174
- /* A cell holding only a control does not need text padding around it. */
2175
- .cb-table td:has(> .cb-button--icon),
2176
- .cb-table td:has(> .cb-menu-anchor) { padding-block: 0; }
2177
-
2178
- .cb-table tbody tr[data-clickable] { cursor: pointer; }
2179
- .cb-table tbody tr[data-clickable]:hover td { background: var(--cb-bg-subtle); }
2180
-
2181
- .cb-table__sort {
2182
- display: inline-flex;
2183
- align-items: center;
2184
- min-height: 1.5rem;
2185
- margin-block: calc(var(--cb-space-1) * -1);
2186
- padding-block: var(--cb-space-1);
2187
- gap: var(--cb-space-1);
2188
- border: none;
2189
- background: transparent;
2190
- color: inherit;
2191
- font: inherit;
2192
- letter-spacing: inherit;
2193
- text-transform: inherit;
2194
- cursor: pointer;
2195
- padding: 0;
2196
- border-radius: var(--cb-radius-sm);
2197
- }
2198
- .cb-table__sort:hover { color: var(--cb-fg); }
2199
- .cb-table__sort:focus-visible { outline: var(--cb-focus-width) solid var(--cb-tone-brand); outline-offset: var(--cb-focus-offset); }
2200
- .cb-table__sort-idle { opacity: 0.4; }
2201
-
2202
- .cb-table__empty {
2203
- border: var(--cb-border-width) solid var(--cb-border);
2204
- border-radius: var(--cb-radius-lg);
2205
- background: var(--cb-surface);
2206
- }
2207
-
2208
- @media (max-width: 720px) {
2209
- .cb-table [data-secondary] { display: none; }
2210
- }
2211
-
2212
- .cb-pagination {
2213
- display: flex;
2214
- align-items: center;
2215
- justify-content: space-between;
2216
- gap: var(--cb-space-4);
2217
- flex-wrap: wrap;
2218
- font-family: var(--cb-font-sans);
2219
- }
2220
- .cb-pagination__summary { margin: 0; font-size: var(--cb-text-xs); color: var(--cb-fg-subtle); font-variant-numeric: tabular-nums; }
2221
- .cb-pagination__controls { display: flex; align-items: center; gap: var(--cb-space-1); }
2222
-
2223
- .cb-pagination__page,
2224
- .cb-pagination__step {
2225
- display: inline-flex;
2226
- align-items: center;
2227
- justify-content: center;
2228
- min-width: 2rem;
2229
- height: 2rem;
2230
- padding-inline: var(--cb-space-2);
2231
- border: var(--cb-border-width) solid transparent;
2232
- border-radius: var(--cb-radius-sm);
2233
- background: transparent;
2234
- color: var(--cb-fg-muted);
2235
- font-family: inherit;
2236
- font-size: var(--cb-text-sm);
2237
- font-variant-numeric: tabular-nums;
2238
- cursor: pointer;
2239
- transition: background-color var(--cb-duration-fast) var(--cb-ease-standard),
2240
- color var(--cb-duration-fast) var(--cb-ease-standard);
2241
- }
2242
- .cb-pagination__page:hover:not([data-active]),
2243
- .cb-pagination__step:hover:not(:disabled) { background: var(--cb-bg-subtle); color: var(--cb-fg); }
2244
- .cb-pagination__page[data-active] {
2245
- background: color-mix(in oklch, var(--cb-tone-brand) 14%, transparent);
2246
- border-color: color-mix(in oklch, var(--cb-tone-brand) 35%, transparent);
2247
- color: var(--cb-tone-brand);
2248
- font-weight: var(--cb-weight-medium);
2249
- }
2250
- .cb-pagination__step:disabled { opacity: 0.35; cursor: not-allowed; }
2251
- .cb-pagination__page:focus-visible,
2252
- .cb-pagination__step:focus-visible { outline: var(--cb-focus-width) solid var(--cb-tone-brand); outline-offset: var(--cb-focus-offset); }
2253
- .cb-pagination__gap { color: var(--cb-fg-subtle); padding-inline: var(--cb-space-1); }
2254
-
2255
- /* data/timeline.css */
2256
- .cb-timeline { list-style: none; margin: 0; padding: 0; font-family: var(--cb-font-sans); }
2257
- .cb-timeline__entry { margin: 0; --cb-timeline-accent: var(--cb-fg-subtle); display: flex; gap: var(--cb-space-3); }
2258
- .cb-timeline__entry[data-tone="brand"] { --cb-timeline-accent: var(--cb-tone-brand); }
2259
- .cb-timeline__entry[data-tone="info"] { --cb-timeline-accent: var(--cb-tone-info); }
2260
- .cb-timeline__entry[data-tone="success"] { --cb-timeline-accent: var(--cb-tone-success); }
2261
- .cb-timeline__entry[data-tone="warning"] { --cb-timeline-accent: var(--cb-tone-warning); }
2262
- .cb-timeline__entry[data-tone="danger"] { --cb-timeline-accent: var(--cb-tone-danger); }
2263
-
2264
- .cb-timeline__rail { position: relative; display: flex; justify-content: center; width: 1.5rem; flex: none; }
2265
- /* The connecting line is drawn on every entry but the last, so the rail ends with the last event. */
2266
- .cb-timeline__entry:not(:last-child) .cb-timeline__rail::after {
2267
- content: "";
2268
- position: absolute;
2269
- top: 1.5rem;
2270
- bottom: -0.25rem;
2271
- width: 1px;
2272
- background: var(--cb-border);
2273
- }
2274
- .cb-timeline__marker {
2275
- display: inline-flex;
2276
- align-items: center;
2277
- justify-content: center;
2278
- width: 1.5rem;
2279
- height: 1.5rem;
2280
- border-radius: var(--cb-radius-full);
2281
- background: color-mix(in oklch, var(--cb-timeline-accent) 16%, var(--cb-surface));
2282
- color: var(--cb-timeline-accent);
2283
- border: var(--cb-border-width) solid color-mix(in oklch, var(--cb-timeline-accent) 35%, transparent);
2284
- }
2285
-
2286
- .cb-timeline__body { flex: 1; padding-bottom: var(--cb-space-5); min-width: 0; }
2287
- .cb-timeline__entry:last-child .cb-timeline__body { padding-bottom: 0; }
2288
- .cb-timeline__head { display: flex; align-items: baseline; justify-content: space-between; gap: var(--cb-space-3); }
2289
- .cb-timeline__title { margin: 0; font-size: var(--cb-text-sm); font-weight: var(--cb-weight-medium); color: var(--cb-fg); }
2290
- .cb-timeline__time { font-size: var(--cb-text-xs); color: var(--cb-fg-subtle); white-space: nowrap; font-variant-numeric: tabular-nums; }
2291
- .cb-timeline__description { margin: var(--cb-space-1) 0 0; font-size: var(--cb-text-sm); color: var(--cb-fg-muted); line-height: var(--cb-leading-normal); }
2292
-
2293
- /* media/avatar.css */
2294
- .cb-avatar {
2295
- --cb-avatar-accent: var(--cb-decor-violet);
2296
- position: relative;
2297
- display: inline-flex;
2298
- align-items: center;
2299
- justify-content: center;
2300
- flex: none;
2301
- border-radius: var(--cb-radius-full);
2302
- background: color-mix(in oklch, var(--cb-avatar-accent) 22%, var(--cb-surface));
2303
- color: color-mix(in oklch, var(--cb-avatar-accent) 70%, var(--cb-fg));
2304
- font-family: var(--cb-font-sans);
2305
- font-weight: var(--cb-weight-semibold);
2306
- overflow: visible;
2307
- }
2308
- .cb-avatar[data-hue="violet"] { --cb-avatar-accent: var(--cb-decor-violet); }
2309
- .cb-avatar[data-hue="blue"] { --cb-avatar-accent: var(--cb-decor-blue); }
2310
- .cb-avatar[data-hue="teal"] { --cb-avatar-accent: var(--cb-decor-teal); }
2311
- .cb-avatar[data-hue="green"] { --cb-avatar-accent: var(--cb-decor-green); }
2312
- .cb-avatar[data-hue="amber"] { --cb-avatar-accent: var(--cb-decor-amber); }
2313
- .cb-avatar[data-hue="rose"] { --cb-avatar-accent: var(--cb-decor-rose); }
2314
-
2315
- .cb-avatar--sm { width: 1.75rem; height: 1.75rem; font-size: 0.625rem; }
2316
- .cb-avatar--md { width: 2.25rem; height: 2.25rem; font-size: var(--cb-text-xs); }
2317
- .cb-avatar--lg { width: 3rem; height: 3rem; font-size: var(--cb-text-sm); }
2318
- .cb-avatar--xl { width: 4rem; height: 4rem; font-size: var(--cb-text-lg); }
2319
-
2320
- .cb-avatar__image {
2321
- position: absolute;
2322
- inset: 0;
2323
- width: 100%;
2324
- height: 100%;
2325
- object-fit: cover;
2326
- border-radius: inherit;
2327
- }
2328
- .cb-avatar__initials { line-height: 1; }
2329
- .cb-avatar--overflow {
2330
- background: var(--cb-bg-subtle);
2331
- color: var(--cb-fg-muted);
2332
- }
2333
-
2334
- .cb-avatar__status {
2335
- position: absolute;
2336
- right: -1px;
2337
- bottom: -1px;
2338
- width: 0.6em;
2339
- height: 0.6em;
2340
- min-width: 0.5rem;
2341
- min-height: 0.5rem;
2342
- border-radius: var(--cb-radius-full);
2343
- border: 2px solid var(--cb-surface);
2344
- }
2345
- .cb-avatar__status[data-status="online"] { background: var(--cb-tone-success); }
2346
- .cb-avatar__status[data-status="busy"] { background: var(--cb-tone-danger); }
2347
- .cb-avatar__status[data-status="away"] { background: var(--cb-tone-warning); }
2348
- .cb-avatar__status[data-status="offline"] { background: var(--cb-fg-subtle); }
2349
-
2350
- .cb-avatar-group { display: inline-flex; }
2351
- .cb-avatar-group > .cb-avatar { box-shadow: 0 0 0 2px var(--cb-surface); }
2352
- .cb-avatar-group > .cb-avatar + .cb-avatar { margin-inline-start: -0.5rem; }
2353
-
2354
- /* media/carousel.css */
2355
- .cb-carousel { position: relative; }
2356
- .cb-carousel:focus-visible {
2357
- outline: var(--cb-focus-width) solid var(--cb-tone-brand);
2358
- outline-offset: var(--cb-focus-offset);
2359
- border-radius: var(--cb-radius-lg);
2360
- }
2361
- .cb-carousel__viewport { overflow: hidden; }
2362
- .cb-carousel__track { display: flex; gap: var(--cb-carousel-gap); }
2363
- .cb-carousel__slide {
2364
- flex: 0 0 var(--cb-carousel-slide);
2365
- min-width: 0;
2366
- }
2367
-
2368
- .cb-carousel__arrows {
2369
- position: absolute;
2370
- inset-block-start: 50%;
2371
- inset-inline: calc(var(--cb-space-3) * -1);
2372
- translate: 0 -50%;
2373
- display: flex;
2374
- justify-content: space-between;
2375
- pointer-events: none;
2376
- }
2377
- .cb-carousel__arrow {
2378
- pointer-events: auto;
2379
- display: inline-flex;
2380
- align-items: center;
2381
- justify-content: center;
2382
- width: 2.25rem;
2383
- height: 2.25rem;
2384
- border-radius: var(--cb-radius-full);
2385
- border: var(--cb-border-width) solid var(--cb-border);
2386
- background: var(--cb-surface-raised);
2387
- color: var(--cb-fg);
2388
- box-shadow: var(--cb-shadow-sm);
2389
- cursor: pointer;
2390
- transition: background-color var(--cb-duration-fast) var(--cb-ease-standard),
2391
- opacity var(--cb-duration-fast) var(--cb-ease-standard);
2392
- }
2393
- .cb-carousel__arrow:hover:not(:disabled) { background: var(--cb-bg-subtle); }
2394
- .cb-carousel__arrow:disabled { opacity: 0.35; cursor: not-allowed; }
2395
- .cb-carousel__arrow:focus-visible {
2396
- outline: var(--cb-focus-width) solid var(--cb-tone-brand);
2397
- outline-offset: var(--cb-focus-offset);
2398
- }
2399
-
2400
- .cb-carousel__dots { display: flex; gap: var(--cb-space-2); justify-content: center; margin-top: var(--cb-space-4); }
2401
- .cb-carousel__dot {
2402
- width: 0.5rem;
2403
- height: 0.5rem;
2404
- padding: 0;
2405
- border: none;
2406
- border-radius: var(--cb-radius-full);
2407
- background: color-mix(in oklch, var(--cb-fg) 22%, transparent);
2408
- cursor: pointer;
2409
- transition: width var(--cb-duration-base) var(--cb-ease-emphasis),
2410
- background-color var(--cb-duration-base) var(--cb-ease-standard);
706
+ padding: var(--cb-space-2) var(--cb-space-3);
707
+ border-radius: var(--cb-radius-md);
708
+ border: var(--cb-border-width) solid transparent;
2411
709
  }
2412
- .cb-carousel__dot[data-active] { width: 1.5rem; background: var(--cb-tone-brand); }
2413
- .cb-carousel__dot:focus-visible {
2414
- outline: var(--cb-focus-width) solid var(--cb-tone-brand);
2415
- outline-offset: var(--cb-focus-offset);
710
+ .cb-leaderboard__row[data-rank="1"] { --cb-rank-accent: var(--cb-decor-amber); }
711
+ .cb-leaderboard__row[data-rank="2"] { --cb-rank-accent: var(--cb-fg-subtle); }
712
+ .cb-leaderboard__row[data-rank="3"] { --cb-rank-accent: var(--cb-decor-rose); }
713
+ .cb-leaderboard__row[data-rank] {
714
+ background: color-mix(in oklch, var(--cb-rank-accent) 12%, transparent);
2416
715
  }
2417
- /* Reduced motion: the active dot still changes colour, it just stops stretching. */
2418
- @media (prefers-reduced-motion: reduce) {
2419
- .cb-carousel__dot { transition: background-color var(--cb-duration-fast) linear; }
716
+ .cb-leaderboard__row[data-you] {
717
+ border-color: color-mix(in oklch, var(--cb-tone-brand) 45%, transparent);
718
+ background: color-mix(in oklch, var(--cb-tone-brand) 10%, transparent);
2420
719
  }
2421
720
 
2422
- /* media/image.css */
2423
- .cb-image {
2424
- position: relative;
2425
- display: block;
2426
- overflow: hidden;
2427
- background-color: var(--cb-bg-subtle);
2428
- background-size: cover;
2429
- background-position: center;
721
+ .cb-leaderboard__rank {
722
+ flex: none;
723
+ width: 1.5rem;
724
+ text-align: center;
725
+ font-size: var(--cb-text-sm);
726
+ font-weight: var(--cb-weight-semibold);
727
+ font-variant-numeric: tabular-nums;
728
+ color: var(--cb-fg-subtle);
2430
729
  }
2431
- /* The placeholder is blurred hard and scaled up, so its edges never show through. */
2432
- .cb-image[data-blurred]::before {
2433
- content: "";
2434
- position: absolute;
2435
- inset: -5%;
2436
- background: inherit;
2437
- background-size: cover;
2438
- background-position: center;
2439
- filter: blur(16px);
2440
- transform: scale(1.05);
2441
- transition: opacity var(--cb-duration-slow) var(--cb-ease-standard);
730
+ .cb-leaderboard__row[data-rank] .cb-leaderboard__rank { color: color-mix(in oklch, var(--cb-rank-accent) 70%, var(--cb-fg)); }
731
+
732
+ .cb-leaderboard__text { flex: 1; display: flex; flex-direction: column; gap: 0.0625rem; min-width: 0; }
733
+ .cb-leaderboard__name { display: flex; align-items: center; gap: var(--cb-space-2); font-size: var(--cb-text-sm); color: var(--cb-fg); }
734
+ .cb-leaderboard__you {
735
+ font-size: 0.625rem;
736
+ text-transform: uppercase;
737
+ letter-spacing: 0.06em;
738
+ color: var(--cb-tone-brand);
739
+ background: color-mix(in oklch, var(--cb-tone-brand) 14%, transparent);
740
+ border-radius: var(--cb-radius-full);
741
+ padding: 0 var(--cb-space-2);
2442
742
  }
2443
- .cb-image[data-loaded][data-blurred]::before { opacity: 0; }
743
+ .cb-leaderboard__detail { font-size: var(--cb-text-xs); color: var(--cb-fg-subtle); }
744
+ .cb-leaderboard__delta { font-size: var(--cb-text-xs); font-variant-numeric: tabular-nums; }
745
+ .cb-leaderboard__delta[data-direction="up"] { color: var(--cb-tone-success); }
746
+ .cb-leaderboard__delta[data-direction="down"] { color: var(--cb-tone-danger); }
747
+ .cb-leaderboard__delta[data-direction="flat"] { color: var(--cb-fg-subtle); }
748
+ .cb-leaderboard__score { font-size: var(--cb-text-sm); font-weight: var(--cb-weight-semibold); font-variant-numeric: tabular-nums; color: var(--cb-fg); }
2444
749
 
2445
- .cb-image__img {
750
+ /* The row's own initials bubble. Leaderboard is server-safe, so it draws this itself rather than
751
+ reaching for Ant's Avatar, which is a client component. */
752
+ .cb-leaderboard__avatar {
753
+ --cb-leaderboard-avatar-accent: var(--cb-decor-violet);
2446
754
  position: relative;
2447
- display: block;
2448
- width: 100%;
2449
- height: 100%;
2450
- opacity: 0;
2451
- transition: opacity var(--cb-duration-slow) var(--cb-ease-entrance);
755
+ display: inline-flex;
756
+ flex: none;
757
+ align-items: center;
758
+ justify-content: center;
759
+ inline-size: 1.75rem;
760
+ block-size: 1.75rem;
761
+ border-radius: var(--cb-radius-full);
762
+ background: color-mix(in oklch, var(--cb-leaderboard-avatar-accent) 22%, var(--cb-surface));
763
+ color: color-mix(in oklch, var(--cb-leaderboard-avatar-accent) 70%, var(--cb-fg));
764
+ font-weight: var(--cb-weight-semibold);
765
+ font-size: 0.625rem;
2452
766
  }
2453
- .cb-image[data-loaded] .cb-image__img { opacity: 1; }
2454
-
2455
- /* Reduced motion: the image appears rather than fading, and the placeholder still holds the space. */
2456
- @media (prefers-reduced-motion: reduce) {
2457
- .cb-image__img,
2458
- .cb-image[data-blurred]::before { transition: none; }
767
+ .cb-leaderboard__avatar[data-hue="violet"] { --cb-leaderboard-avatar-accent: var(--cb-decor-violet); }
768
+ .cb-leaderboard__avatar[data-hue="blue"] { --cb-leaderboard-avatar-accent: var(--cb-decor-blue); }
769
+ .cb-leaderboard__avatar[data-hue="teal"] { --cb-leaderboard-avatar-accent: var(--cb-decor-teal); }
770
+ .cb-leaderboard__avatar[data-hue="green"] { --cb-leaderboard-avatar-accent: var(--cb-decor-green); }
771
+ .cb-leaderboard__avatar[data-hue="amber"] { --cb-leaderboard-avatar-accent: var(--cb-decor-amber); }
772
+ .cb-leaderboard__avatar[data-hue="rose"] { --cb-leaderboard-avatar-accent: var(--cb-decor-rose); }
773
+ .cb-leaderboard__photo {
774
+ position: absolute;
775
+ inset: 0;
776
+ inline-size: 100%;
777
+ block-size: 100%;
778
+ border-radius: inherit;
779
+ object-fit: cover;
2459
780
  }
2460
781
 
2461
782
  /* nav/nav.css */
2462
- .cb-menu-positioner { z-index: var(--cb-z-dropdown); }
783
+ .cb-menu-positioner {
784
+ position: absolute;
785
+ z-index: var(--cb-z-dropdown);
786
+ inline-size: max-content;
787
+ max-inline-size: calc(100vw - var(--cb-space-4));
788
+ }
789
+ .cb-dropdown-engine-hidden { display: none; }
2463
790
 
2464
791
  .cb-menu {
2465
792
  box-sizing: border-box;
@@ -2521,6 +848,116 @@ html, body { background: var(--cb-bg); color: var(--cb-fg); }
2521
848
  }
2522
849
  .cb-menu__separator { height: 1px; background: var(--cb-border); margin: var(--cb-space-1) 0; }
2523
850
 
851
+ .cb-dropdown-engine-menu,
852
+ .cb-dropdown-engine-menu-submenu-popup ul {
853
+ margin: 0;
854
+ padding: var(--cb-space-1);
855
+ list-style: none;
856
+ }
857
+ .cb-dropdown-engine-menu-item,
858
+ .cb-dropdown-engine-menu-submenu-title {
859
+ display: flex;
860
+ align-items: center;
861
+ min-height: var(--cb-control-height-sm);
862
+ padding-inline: var(--cb-space-2);
863
+ border-radius: var(--cb-radius-sm);
864
+ color: var(--cb-fg);
865
+ cursor: pointer;
866
+ outline: none;
867
+ }
868
+ .cb-menu__item-content {
869
+ display: grid;
870
+ grid-template-columns: auto minmax(0, 1fr) auto;
871
+ align-items: center;
872
+ gap: var(--cb-space-2);
873
+ inline-size: 100%;
874
+ }
875
+ .cb-dropdown-engine-menu-item-active,
876
+ .cb-dropdown-engine-menu-submenu-active > .cb-dropdown-engine-menu-submenu-title,
877
+ .cb-dropdown-engine-menu-item-selected { background: color-mix(in oklch, var(--cb-tone-brand) 12%, transparent); }
878
+ .cb-menu__item--danger { color: var(--cb-tone-danger); }
879
+ .cb-menu__item--danger.cb-dropdown-engine-menu-item-active { background: color-mix(in oklch, var(--cb-tone-danger) 12%, transparent); }
880
+ .cb-dropdown-engine-menu-item-disabled,
881
+ .cb-dropdown-engine-menu-submenu-disabled > .cb-dropdown-engine-menu-submenu-title { color: var(--cb-fg-subtle); cursor: not-allowed; }
882
+ .cb-dropdown-engine-menu-item-divider {
883
+ block-size: var(--cb-border-width);
884
+ margin-block: var(--cb-space-1);
885
+ background: var(--cb-border);
886
+ }
887
+ .cb-dropdown-engine-menu-item-group-title {
888
+ padding: var(--cb-space-2) var(--cb-space-2) var(--cb-space-1);
889
+ color: var(--cb-fg-subtle);
890
+ font-size: var(--cb-text-xs);
891
+ font-weight: var(--cb-weight-semibold);
892
+ }
893
+ .cb-dropdown-engine-menu-submenu-title { justify-content: space-between; gap: var(--cb-space-2); }
894
+ .cb-menu__submenu-arrow { inline-size: var(--cb-space-3); block-size: var(--cb-space-3); }
895
+ .cb-dropdown-engine-menu-submenu-popup {
896
+ position: absolute;
897
+ z-index: var(--cb-z-dropdown);
898
+ inline-size: max-content;
899
+ max-inline-size: calc(100vw - var(--cb-space-4));
900
+ }
901
+ .cb-dropdown-engine-menu-submenu-popup > .cb-dropdown-engine-menu {
902
+ min-inline-size: calc(var(--cb-control-height-md) * 3);
903
+ border: var(--cb-border-width) solid var(--cb-border);
904
+ border-radius: var(--cb-radius-md);
905
+ background: var(--cb-surface-raised);
906
+ box-shadow: var(--cb-shadow-md);
907
+ }
908
+ .cb-dropdown-engine-menu-submenu-hidden { display: none; }
909
+ .cb-menu-positioner--motionless,
910
+ .cb-menu-positioner--motionless * { transition: none !important; animation: none !important; }
911
+ .cb-dropdown-engine-arrow {
912
+ position: absolute;
913
+ z-index: -1;
914
+ inline-size: var(--cb-space-2);
915
+ block-size: var(--cb-space-2);
916
+ border: var(--cb-border-width) solid var(--cb-border);
917
+ background: var(--cb-surface-raised);
918
+ rotate: 45deg;
919
+ }
920
+ .cb-dropdown-motion-enter,
921
+ .cb-dropdown-motion-appear { opacity: 0; }
922
+ .cb-dropdown-motion-enter .cb-menu,
923
+ .cb-dropdown-motion-appear .cb-menu { transform: scale(0.97); }
924
+ .cb-dropdown-motion-enter-active,
925
+ .cb-dropdown-motion-appear-active {
926
+ opacity: 1;
927
+ transition: opacity var(--cb-duration-fast) var(--cb-ease-entrance);
928
+ }
929
+ .cb-dropdown-motion-enter-active .cb-menu,
930
+ .cb-dropdown-motion-appear-active .cb-menu { transform: scale(1); }
931
+ .cb-dropdown-engine-placement-bottomLeft .cb-menu { transform-origin: top left; }
932
+ .cb-dropdown-engine-placement-bottom .cb-menu { transform-origin: top center; }
933
+ .cb-dropdown-engine-placement-bottomRight .cb-menu { transform-origin: top right; }
934
+ .cb-dropdown-engine-placement-topLeft .cb-menu { transform-origin: bottom left; }
935
+ .cb-dropdown-engine-placement-top .cb-menu { transform-origin: bottom center; }
936
+ .cb-dropdown-engine-placement-topRight .cb-menu { transform-origin: bottom right; }
937
+ .cb-dropdown-engine-placement-leftTop .cb-menu,
938
+ .cb-dropdown-engine-placement-left .cb-menu,
939
+ .cb-dropdown-engine-placement-leftBottom .cb-menu { transform-origin: right center; }
940
+ .cb-dropdown-engine-placement-rightTop .cb-menu,
941
+ .cb-dropdown-engine-placement-right .cb-menu,
942
+ .cb-dropdown-engine-placement-rightBottom .cb-menu { transform-origin: left center; }
943
+ .cb-dropdown-motion-leave { opacity: 1; }
944
+ .cb-dropdown-motion-leave-active { opacity: 0; transition: opacity var(--cb-duration-fast) var(--cb-ease-exit); }
945
+ @media (prefers-reduced-motion: reduce) {
946
+ .cb-dropdown-motion-enter,
947
+ .cb-dropdown-motion-appear { transform: none; }
948
+ .cb-dropdown-motion-enter .cb-menu,
949
+ .cb-dropdown-motion-appear .cb-menu { transform: none; }
950
+ .cb-dropdown-motion-enter-active,
951
+ .cb-dropdown-motion-appear-active { transform: none; transition-property: opacity; }
952
+ }
953
+ .cb-dropdown-button { display: inline-flex; }
954
+ .cb-dropdown-button > :first-child { border-start-end-radius: 0; border-end-end-radius: 0; }
955
+ .cb-dropdown-button > :last-child { margin-inline-start: calc(var(--cb-border-width) * -1); border-start-start-radius: 0; border-end-start-radius: 0; }
956
+ .cb-dropdown__skeleton { display: inline-flex; flex-direction: column; gap: var(--cb-space-2); }
957
+ .cb-dropdown__skeleton-trigger { inline-size: calc(var(--cb-control-height-lg) * 2); block-size: var(--cb-control-height-md); }
958
+ .cb-dropdown__skeleton-menu { display: flex; flex-direction: column; gap: var(--cb-space-2); }
959
+ .cb-dropdown__skeleton-item { inline-size: calc(var(--cb-control-height-lg) * 3); block-size: var(--cb-space-4); }
960
+
2524
961
  .cb-crumbs__list {
2525
962
  display: flex;
2526
963
  flex-wrap: wrap;
@@ -2533,12 +970,29 @@ html, body { background: var(--cb-bg); color: var(--cb-fg); }
2533
970
  font-size: var(--cb-text-sm);
2534
971
  }
2535
972
  .cb-crumbs__item { margin: 0; display: inline-flex; align-items: center; gap: var(--cb-space-1); }
2536
- .cb-crumbs__link { color: var(--cb-fg-muted); text-decoration: none; border-radius: var(--cb-radius-sm); }
2537
- .cb-crumbs__link:hover { color: var(--cb-fg); text-decoration: underline; }
973
+ .cb-crumbs__link {
974
+ display: inline-flex;
975
+ align-items: center;
976
+ gap: var(--cb-space-1);
977
+ color: var(--cb-fg-muted);
978
+ text-decoration: none;
979
+ border-radius: var(--cb-radius-sm);
980
+ }
981
+ .cb-crumbs__link > svg { flex: none; inline-size: var(--cb-space-4); block-size: var(--cb-space-4); }
982
+ .cb-crumbs__link a { color: inherit; text-decoration: none; }
983
+ @media (hover: hover) {
984
+ a.cb-crumbs__link:hover,
985
+ .cb-crumbs__link a:hover { color: var(--cb-fg); }
986
+ }
2538
987
  .cb-crumbs__link:focus-visible { outline: var(--cb-focus-width) solid var(--cb-tone-brand); outline-offset: var(--cb-focus-offset); }
2539
988
  .cb-crumbs__text { color: var(--cb-fg-subtle); }
2540
- .cb-crumbs__current { color: var(--cb-fg); font-weight: var(--cb-weight-medium); }
989
+ .cb-crumbs__current,
990
+ .cb-crumbs__item[aria-current="page"] .cb-crumbs__link { color: var(--cb-fg); }
2541
991
  .cb-crumbs__separator { color: var(--cb-fg-subtle); flex: none; }
992
+ .cb-crumbs__overlay-link { display: inline-flex; align-items: center; gap: var(--cb-space-1); cursor: pointer; }
993
+ .cb-crumbs__overlay-link > svg { inline-size: var(--cb-space-3); block-size: var(--cb-space-3); }
994
+ .cb-menu.cb-crumbs__menu { min-width: calc(var(--cb-control-height-md) * 3); }
995
+ .cb-menu__label > a { color: inherit; text-decoration: none; }
2542
996
 
2543
997
  .cb-steps { list-style: none; margin: 0; padding: 0; font-family: var(--cb-font-sans); display: flex; }
2544
998
  .cb-steps--horizontal { flex-direction: row; gap: var(--cb-space-5); flex-wrap: wrap; }
@@ -2568,11 +1022,310 @@ html, body { background: var(--cb-bg); color: var(--cb-fg); }
2568
1022
  color: var(--cb-tone-brand);
2569
1023
  box-shadow: 0 0 0 3px color-mix(in oklch, var(--cb-tone-brand) 16%, transparent);
2570
1024
  }
2571
- .cb-steps__text { display: flex; flex-direction: column; gap: 0.125rem; }
1025
+ .cb-steps__text { display: flex; flex-direction: column; gap: var(--cb-space-1); }
2572
1026
  .cb-steps__label { font-size: var(--cb-text-sm); font-weight: var(--cb-weight-medium); color: var(--cb-fg-muted); }
2573
1027
  .cb-steps__step[data-state="current"] .cb-steps__label { color: var(--cb-fg); }
2574
1028
  .cb-steps__description { font-size: var(--cb-text-xs); color: var(--cb-fg-subtle); }
2575
1029
 
1030
+ /* Ant-compatible interactive Steps. The rc engine owns status, item activation, and keyboard handling. */
1031
+ .cb-steps-engine.cb-steps {
1032
+ --cb-steps-icon-size: var(--cb-control-height-sm);
1033
+ display: flex;
1034
+ flex-wrap: nowrap;
1035
+ width: 100%;
1036
+ color: var(--cb-fg);
1037
+ font-family: var(--cb-font-sans);
1038
+ font-size: var(--cb-text-sm);
1039
+ line-height: var(--cb-leading-normal);
1040
+ }
1041
+ .cb-steps-engine.cb-steps.cb-steps--small { --cb-steps-icon-size: calc(var(--cb-control-height-sm) - var(--cb-space-2)); font-size: var(--cb-text-xs); }
1042
+ .cb-steps-engine-item { position: relative; min-width: var(--cb-steps-icon-size); box-sizing: border-box; flex: 1 1 auto; overflow: visible; }
1043
+ .cb-steps-engine-item:last-child { flex: 0 1 auto; }
1044
+ .cb-steps-engine-item-wrapper { display: flex; align-items: flex-start; gap: var(--cb-space-2); }
1045
+ .cb-steps-engine-item-icon {
1046
+ position: relative;
1047
+ z-index: 1;
1048
+ display: inline-flex;
1049
+ box-sizing: border-box;
1050
+ flex: none;
1051
+ width: var(--cb-steps-icon-size);
1052
+ height: var(--cb-steps-icon-size);
1053
+ align-items: center;
1054
+ justify-content: center;
1055
+ border: var(--cb-border-width) solid var(--cb-border-strong);
1056
+ border-radius: var(--cb-radius-full);
1057
+ background: var(--cb-surface);
1058
+ color: var(--cb-fg-muted);
1059
+ line-height: var(--cb-steps-icon-size);
1060
+ transition: border-color var(--cb-duration-base) var(--cb-ease-standard), background-color var(--cb-duration-base) var(--cb-ease-standard), color var(--cb-duration-base) var(--cb-ease-standard);
1061
+ }
1062
+ .cb-steps-engine-item-icon svg { width: var(--cb-text-sm); height: var(--cb-text-sm); }
1063
+ .cb-steps-engine-item-section { min-width: 0; flex: 1; }
1064
+ .cb-steps-engine-item-header { display: flex; min-height: var(--cb-steps-icon-size); align-items: center; white-space: nowrap; }
1065
+ .cb-steps-engine-item-title { color: var(--cb-fg); font-weight: var(--cb-weight-medium); }
1066
+ .cb-steps-engine-item-subtitle { overflow: hidden; margin-inline-start: var(--cb-space-2); color: var(--cb-fg-subtle); text-overflow: ellipsis; }
1067
+ .cb-steps-engine-item-content { max-width: calc(var(--cb-space-8) * 6); margin-block-start: var(--cb-space-1); color: var(--cb-fg-muted); }
1068
+ .cb-steps-engine-item-rail { min-width: var(--cb-space-5); flex: 1; margin-inline: var(--cb-space-4) 0; border-block-start: var(--cb-border-width) solid var(--cb-border); }
1069
+
1070
+ .cb-steps-engine-item-finish .cb-steps-engine-item-icon { border-color: var(--cb-tone-brand); color: var(--cb-tone-brand); }
1071
+ .cb-steps--filled .cb-steps-engine-item-finish .cb-steps-engine-item-icon { background: var(--cb-tone-brand); color: var(--cb-fg-on-brand); }
1072
+ .cb-steps--filled .cb-steps-engine-item-process .cb-steps-engine-item-icon { border-color: var(--cb-tone-brand); background: var(--cb-tone-brand); color: var(--cb-fg-on-brand); }
1073
+ .cb-steps--outlined .cb-steps-engine-item-process .cb-steps-engine-item-icon { border-color: var(--cb-tone-brand); color: var(--cb-tone-brand); }
1074
+ .cb-steps-engine-item-error .cb-steps-engine-item-icon { border-color: var(--cb-tone-danger); color: var(--cb-tone-danger); }
1075
+ .cb-steps-engine-item-error .cb-steps-engine-item-title,
1076
+ .cb-steps-engine-item-error .cb-steps-engine-item-subtitle,
1077
+ .cb-steps-engine-item-error .cb-steps-engine-item-content { color: var(--cb-tone-danger); }
1078
+ .cb-steps-engine-item-custom .cb-steps-engine-item-icon { border-color: transparent; background: transparent; }
1079
+ .cb-steps--filled .cb-steps-engine-item-custom.cb-steps-engine-item-finish .cb-steps-engine-item-icon,
1080
+ .cb-steps--filled .cb-steps-engine-item-custom.cb-steps-engine-item-process .cb-steps-engine-item-icon { background: transparent; color: var(--cb-tone-brand); }
1081
+ .cb-steps-engine-item-finish .cb-steps-engine-item-rail { border-color: var(--cb-tone-brand); }
1082
+ .cb-steps-engine-item .cb-steps-engine-item-rail-error { border-color: var(--cb-tone-danger); }
1083
+ .cb-steps-engine-item-wait .cb-steps-engine-item-title { color: var(--cb-fg-muted); }
1084
+ .cb-steps-engine-item-disabled { cursor: not-allowed; }
1085
+ .cb-steps-engine-item[role="button"] { cursor: pointer; }
1086
+ @media (hover: hover) {
1087
+ .cb-steps-engine-item[role="button"]:not(.cb-steps-engine-item-active):hover .cb-steps-engine-item-title { color: var(--cb-tone-brand); }
1088
+ .cb-steps-engine-item[role="button"]:not(.cb-steps-engine-item-active):hover .cb-steps-engine-item-icon {
1089
+ border-color: var(--cb-tone-brand);
1090
+ background: color-mix(in oklch, var(--cb-tone-brand) calc(var(--cb-tint-strength) * 100%), var(--cb-surface));
1091
+ color: var(--cb-tone-brand);
1092
+ }
1093
+ }
1094
+ .cb-steps-engine-item[role="button"]:focus-visible { outline: var(--cb-focus-width) solid var(--cb-tone-brand); outline-offset: var(--cb-focus-offset); border-radius: var(--cb-radius-sm); }
1095
+
1096
+ .cb-steps--title-vertical.cb-steps--horizontal .cb-steps-engine-item { overflow: visible; text-align: center; }
1097
+ .cb-steps--title-vertical.cb-steps--horizontal .cb-steps-engine-item:last-child { flex: 1 1 auto; }
1098
+ .cb-steps--title-vertical.cb-steps--horizontal .cb-steps-engine-item-wrapper { flex-direction: column; align-items: center; gap: var(--cb-space-3); }
1099
+ .cb-steps--title-vertical.cb-steps--horizontal .cb-steps-engine-item-section { width: 100%; margin: 0; align-self: stretch; }
1100
+ .cb-steps--title-vertical.cb-steps--horizontal .cb-steps-engine-item-header { flex-direction: column; align-items: center; justify-content: center; }
1101
+ .cb-steps--title-vertical.cb-steps--horizontal .cb-steps-engine-item-subtitle { margin: 0; }
1102
+ .cb-steps--title-vertical.cb-steps--horizontal .cb-steps-engine-item-content { margin-inline: auto; }
1103
+ .cb-steps--title-vertical.cb-steps--horizontal .cb-steps-engine-item-rail {
1104
+ position: absolute;
1105
+ inset-block-start: calc(var(--cb-steps-icon-size) / 2 - var(--cb-border-width));
1106
+ inset-inline-start: calc(50% + var(--cb-steps-icon-size) / 2 + var(--cb-space-1));
1107
+ width: calc(100% - var(--cb-steps-icon-size) - var(--cb-space-2));
1108
+ margin: 0;
1109
+ }
1110
+
1111
+ .cb-steps--title-horizontal.cb-steps--vertical .cb-steps-engine-item-wrapper { gap: var(--cb-space-4); }
1112
+
1113
+ .cb-steps--vertical { flex-direction: column; }
1114
+ .cb-steps--vertical .cb-steps-engine-item { min-height: calc(var(--cb-control-height-md) * 1.5); flex: none; padding-block-end: var(--cb-space-3); overflow: visible; }
1115
+ .cb-steps--vertical .cb-steps-engine-item:last-child { min-height: 0; }
1116
+ .cb-steps--vertical .cb-steps-engine-item-rail {
1117
+ position: absolute;
1118
+ inset-block-start: calc(var(--cb-steps-icon-size) + var(--cb-space-2));
1119
+ inset-block-end: var(--cb-space-2);
1120
+ inset-inline-start: calc(var(--cb-steps-icon-size) / 2);
1121
+ width: 0;
1122
+ min-width: 0;
1123
+ margin: 0;
1124
+ border-block-start: 0;
1125
+ border-inline-start: var(--cb-border-width) solid var(--cb-border);
1126
+ }
1127
+ .cb-steps--vertical .cb-steps-engine-item-finish .cb-steps-engine-item-rail { border-color: var(--cb-tone-brand); }
1128
+ .cb-steps--vertical .cb-steps-engine-item-rail-error { border-color: var(--cb-tone-danger); }
1129
+
1130
+ .cb-steps-engine.cb-steps.cb-steps--dot { --cb-steps-icon-size: var(--cb-space-2); }
1131
+ .cb-steps--dot .cb-steps-engine-item-icon { border: 0; background: var(--cb-border-strong); }
1132
+ .cb-steps--dot .cb-steps-engine-item-active .cb-steps-engine-item-icon { width: calc(var(--cb-steps-icon-size) + var(--cb-border-width) * 2); height: calc(var(--cb-steps-icon-size) + var(--cb-border-width) * 2); }
1133
+ .cb-steps--dot .cb-steps-engine-item-icon > * { display: none; }
1134
+ .cb-steps--dot .cb-steps-engine-item-process .cb-steps-engine-item-icon,
1135
+ .cb-steps--dot .cb-steps-engine-item-finish .cb-steps-engine-item-icon { background: var(--cb-tone-brand); }
1136
+ .cb-steps--dot.cb-steps--outlined .cb-steps-engine-item-icon { border: calc(var(--cb-border-width) * 2) solid var(--cb-border-strong); background: var(--cb-surface); }
1137
+ .cb-steps--dot.cb-steps--outlined .cb-steps-engine-item-process .cb-steps-engine-item-icon,
1138
+ .cb-steps--dot.cb-steps--outlined .cb-steps-engine-item-finish .cb-steps-engine-item-icon { border-color: var(--cb-tone-brand); background: var(--cb-surface); }
1139
+ .cb-steps--dot .cb-steps-engine-item-header { min-height: var(--cb-control-height-sm); }
1140
+ .cb-steps--dot .cb-steps-engine-item-rail { border-width: calc(var(--cb-border-width) * 2); }
1141
+ .cb-steps--dot.cb-steps--vertical .cb-steps-engine-item-icon { margin-inline-start: var(--cb-border-width); }
1142
+ .cb-steps--dot.cb-steps--vertical .cb-steps-engine-item-rail { inset-inline-start: calc((var(--cb-steps-icon-size) + var(--cb-border-width) * 2) / 2); }
1143
+
1144
+ .cb-steps--navigation { padding-block: var(--cb-space-1); }
1145
+ .cb-steps--navigation .cb-steps-engine-item { display: flex; flex: 1; justify-content: center; padding: var(--cb-space-3) var(--cb-space-6) var(--cb-space-3) var(--cb-space-4); overflow: visible; }
1146
+ .cb-steps--navigation .cb-steps-engine-item-rail { display: none; }
1147
+ .cb-steps--navigation .cb-steps-engine-item::before {
1148
+ position: absolute;
1149
+ inset-block-end: 0;
1150
+ inset-inline-start: 50%;
1151
+ display: block;
1152
+ width: 0;
1153
+ height: calc(var(--cb-border-width) * 2);
1154
+ background: var(--cb-tone-brand);
1155
+ content: "";
1156
+ transition: inset-inline-start var(--cb-duration-slow) var(--cb-ease-exit), width var(--cb-duration-slow) var(--cb-ease-exit);
1157
+ }
1158
+ .cb-steps--navigation .cb-steps-engine-item:not(:last-child)::after {
1159
+ position: absolute;
1160
+ inset-block-start: 50%;
1161
+ inset-inline-end: var(--cb-space-2);
1162
+ width: var(--cb-space-2);
1163
+ height: var(--cb-space-2);
1164
+ border-block-end: var(--cb-border-width) solid var(--cb-border-strong);
1165
+ border-inline-end: var(--cb-border-width) solid var(--cb-border-strong);
1166
+ content: "";
1167
+ transform: translateY(-50%) rotate(-45deg);
1168
+ }
1169
+ .cb-steps--navigation .cb-steps-engine-item-active { background: transparent; }
1170
+ .cb-steps--navigation .cb-steps-engine-item-active::before { inset-inline-start: 0; width: 100%; }
1171
+
1172
+ .cb-steps-engine.cb-steps.cb-steps--inline {
1173
+ --cb-steps-icon-size: calc(var(--cb-space-1) + var(--cb-border-width) * 2);
1174
+ display: inline-flex;
1175
+ width: auto;
1176
+ max-width: 100%;
1177
+ gap: 0;
1178
+ }
1179
+ .cb-steps--inline::before { content: ""; flex: var(--cb-steps-offset); }
1180
+ .cb-steps--inline .cb-steps-engine-item {
1181
+ flex: 1 1 0;
1182
+ min-width: max-content;
1183
+ padding: 0;
1184
+ overflow: visible;
1185
+ }
1186
+ .cb-steps--inline .cb-steps-engine-item:last-child { flex: 1 1 0; }
1187
+ .cb-steps--inline .cb-steps-engine-item-wrapper {
1188
+ padding-block-start: calc(var(--cb-space-2) + var(--cb-border-width));
1189
+ padding-inline: var(--cb-space-1);
1190
+ margin-inline: calc(var(--cb-space-1) / 2);
1191
+ border-radius: var(--cb-radius-sm);
1192
+ cursor: pointer;
1193
+ transition: background-color var(--cb-duration-base) var(--cb-ease-standard);
1194
+ }
1195
+ .cb-steps--inline.cb-steps--title-vertical .cb-steps-engine-item-wrapper { gap: var(--cb-space-2); }
1196
+ .cb-steps--inline .cb-steps-engine-item-active .cb-steps-engine-item-icon {
1197
+ width: var(--cb-steps-icon-size);
1198
+ height: var(--cb-steps-icon-size);
1199
+ }
1200
+ .cb-steps--inline .cb-steps-engine-item-title {
1201
+ font-size: var(--cb-text-xs);
1202
+ font-weight: var(--cb-weight-normal);
1203
+ line-height: var(--cb-leading-normal);
1204
+ white-space: nowrap;
1205
+ }
1206
+ .cb-steps--inline .cb-steps-engine-item-rail {
1207
+ inset-inline-start: calc(50% + var(--cb-steps-icon-size) / 2);
1208
+ width: calc(100% - var(--cb-steps-icon-size));
1209
+ }
1210
+ .cb-steps--inline .cb-steps-engine-item-content { display: none; }
1211
+ @media (hover: hover) {
1212
+ .cb-steps--inline .cb-steps-engine-item-wrapper:hover { background: var(--cb-bg-subtle); }
1213
+ }
1214
+
1215
+ .cb-steps--panel {
1216
+ --cb-steps-panel-padding: var(--cb-space-3);
1217
+ --cb-steps-panel-arrow-width: calc(
1218
+ var(--cb-steps-panel-padding) * 1.4142 +
1219
+ var(--cb-steps-icon-size) * 0.7071 +
1220
+ var(--cb-text-sm) * var(--cb-leading-normal) * 0.7071
1221
+ );
1222
+ align-items: stretch;
1223
+ gap: 0;
1224
+ border-radius: var(--cb-radius-sm);
1225
+ }
1226
+ .cb-steps--panel.cb-steps--small { --cb-steps-panel-padding: var(--cb-space-2); }
1227
+ .cb-steps--panel .cb-steps-engine-item {
1228
+ --cb-steps-panel-bg: var(--cb-bg-subtle);
1229
+ --cb-steps-panel-border: var(--cb-border-strong);
1230
+ min-height: calc(var(--cb-control-height-lg) + var(--cb-space-5));
1231
+ flex: 1;
1232
+ margin: 0;
1233
+ padding: var(--cb-steps-panel-padding);
1234
+ border-block: calc(var(--cb-border-width) * 2) solid var(--cb-steps-panel-border);
1235
+ border-radius: 0;
1236
+ background: var(--cb-steps-panel-bg);
1237
+ overflow: visible;
1238
+ transition: background-color var(--cb-duration-base) var(--cb-ease-standard), border-color var(--cb-duration-base) var(--cb-ease-standard);
1239
+ }
1240
+ .cb-steps--panel .cb-steps-engine-item:not(:first-child) { padding-inline-start: calc(var(--cb-steps-panel-padding) + var(--cb-steps-panel-arrow-width)); }
1241
+ .cb-steps--panel.cb-steps--filled .cb-steps-engine-item:not(:first-child) {
1242
+ clip-path: polygon(
1243
+ calc(var(--cb-border-width) * 2) 0,
1244
+ calc(100% + var(--cb-steps-panel-arrow-width)) 0,
1245
+ calc(100% + var(--cb-steps-panel-arrow-width)) 100%,
1246
+ calc(var(--cb-border-width) * 2) 100%,
1247
+ calc(var(--cb-steps-panel-arrow-width) + var(--cb-border-width) * 2) 50%
1248
+ );
1249
+ }
1250
+ .cb-steps--panel .cb-steps-engine-item:first-child { border-inline-start: calc(var(--cb-border-width) * 2) solid var(--cb-steps-panel-border); border-start-start-radius: var(--cb-radius-sm); border-end-start-radius: var(--cb-radius-sm); }
1251
+ .cb-steps--panel .cb-steps-engine-item:last-child { border-inline-end: calc(var(--cb-border-width) * 2) solid var(--cb-steps-panel-border); border-start-end-radius: var(--cb-radius-sm); border-end-end-radius: var(--cb-radius-sm); }
1252
+ .cb-steps--panel .cb-steps-engine-item-icon,
1253
+ .cb-steps--panel .cb-steps-engine-item-rail { display: none; }
1254
+ .cb-steps--panel .cb-steps-engine-item-wrapper { gap: 0; }
1255
+ .cb-steps--panel .cb-steps-engine-item-header { min-height: 0; }
1256
+ .cb-steps--panel .cb-steps-engine-item-content { margin-block-start: var(--cb-space-1); }
1257
+ .cb-steps-engine-panel-arrow {
1258
+ position: absolute;
1259
+ z-index: 1;
1260
+ inset-block-start: calc(var(--cb-border-width) * -2);
1261
+ inset-inline-start: 100%;
1262
+ width: var(--cb-steps-panel-arrow-width);
1263
+ height: calc(100% + var(--cb-border-width) * 4);
1264
+ overflow: visible;
1265
+ stroke-linecap: round;
1266
+ pointer-events: none;
1267
+ }
1268
+ .cb-steps-engine-panel-arrow path {
1269
+ fill: var(--cb-steps-panel-bg);
1270
+ stroke: var(--cb-steps-panel-border);
1271
+ stroke-width: calc(var(--cb-border-width) * 2);
1272
+ vector-effect: non-scaling-stroke;
1273
+ transition: fill var(--cb-duration-base) var(--cb-ease-standard), stroke var(--cb-duration-base) var(--cb-ease-standard);
1274
+ }
1275
+ .cb-steps--panel .cb-steps-engine-item:last-child .cb-steps-engine-panel-arrow { display: none; }
1276
+ .cb-steps--panel.cb-steps--filled .cb-steps-engine-item-active { --cb-steps-panel-bg: var(--cb-tone-brand); --cb-steps-panel-border: var(--cb-tone-brand); color: var(--cb-fg-on-brand); }
1277
+ .cb-steps--panel.cb-steps--filled .cb-steps-engine-item-active .cb-steps-engine-item-title,
1278
+ .cb-steps--panel.cb-steps--filled .cb-steps-engine-item-active .cb-steps-engine-item-subtitle,
1279
+ .cb-steps--panel.cb-steps--filled .cb-steps-engine-item-active .cb-steps-engine-item-content { color: var(--cb-fg-on-brand); }
1280
+ .cb-steps--panel .cb-steps-engine-item-error { --cb-steps-panel-bg: color-mix(in oklch, var(--cb-tone-danger) calc(var(--cb-tint-strength) * 100%), var(--cb-surface)); --cb-steps-panel-border: var(--cb-tone-danger); }
1281
+ .cb-steps--panel.cb-steps--outlined .cb-steps-engine-item { --cb-steps-panel-bg: var(--cb-surface); }
1282
+ .cb-steps--panel.cb-steps--outlined .cb-steps-engine-panel-arrow { inset-block-start: calc(var(--cb-border-width) * -1); height: calc(100% + var(--cb-border-width) * 2); }
1283
+ .cb-steps--panel.cb-steps--outlined .cb-steps-engine-item-active { --cb-steps-panel-bg: color-mix(in oklch, var(--cb-tone-brand) calc(var(--cb-tint-strength) * 100%), var(--cb-surface)); --cb-steps-panel-border: var(--cb-tone-brand); }
1284
+ .cb-steps--panel.cb-steps--outlined .cb-steps-engine-item-active .cb-steps-engine-item-title,
1285
+ .cb-steps--panel.cb-steps--outlined .cb-steps-engine-item-active .cb-steps-engine-item-subtitle,
1286
+ .cb-steps--panel.cb-steps--outlined .cb-steps-engine-item-active .cb-steps-engine-item-content { color: var(--cb-tone-brand); }
1287
+
1288
+ .cb-steps--with-progress .cb-steps-engine-item-process .cb-steps-engine-item-icon { position: relative; }
1289
+ .cb-steps-engine-item-icon > .cb-steps-engine-item-progress-icon-svg {
1290
+ position: absolute;
1291
+ inset: calc(var(--cb-border-width) * -4);
1292
+ width: calc(100% + var(--cb-border-width) * 8);
1293
+ height: calc(100% + var(--cb-border-width) * 8);
1294
+ overflow: visible;
1295
+ }
1296
+ .cb-steps-engine-item-progress-icon-circle {
1297
+ fill: none;
1298
+ stroke-width: calc(var(--cb-border-width) * 8);
1299
+ transition: stroke-dasharray var(--cb-duration-slow) var(--cb-ease-standard);
1300
+ }
1301
+ .cb-steps-engine-item-progress-icon-circle-rail { stroke: var(--cb-border); }
1302
+ .cb-steps-engine-item-progress-icon-circle-ptg { stroke: var(--cb-tone-brand); }
1303
+
1304
+ .cb-steps__ellipsis { pointer-events: none; }
1305
+ .cb-steps--ellipsis .cb-steps-engine-item-title,
1306
+ .cb-steps--ellipsis .cb-steps-engine-item-content { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
1307
+ .cb-steps--motionless *,
1308
+ .cb-steps--motionless *::before,
1309
+ .cb-steps--motionless *::after { transition: none !important; }
1310
+ @media (prefers-reduced-motion: reduce) {
1311
+ .cb-steps *,
1312
+ .cb-steps *::before,
1313
+ .cb-steps *::after { transition: none !important; }
1314
+ }
1315
+
1316
+ .cb-steps--skeleton { display: flex; gap: var(--cb-space-4); }
1317
+ .cb-steps--skeleton-vertical { flex-direction: column; }
1318
+ .cb-steps__skeleton-item { display: flex; min-width: 0; flex: 1; align-items: flex-start; gap: var(--cb-space-2); }
1319
+ .cb-steps__skeleton-copy { display: grid; min-width: 0; flex: 1; gap: var(--cb-space-2); }
1320
+
1321
+ @media (max-width: 720px) {
1322
+ .cb-steps--responsive.cb-steps--horizontal:not(.cb-steps--panel) { flex-direction: column; }
1323
+ .cb-steps--responsive.cb-steps--horizontal:not(.cb-steps--panel) .cb-steps-engine-item { flex: none; min-height: calc(var(--cb-control-height-lg) + var(--cb-space-5)); overflow: visible; text-align: start; }
1324
+ .cb-steps--responsive.cb-steps--horizontal:not(.cb-steps--panel) .cb-steps-engine-item-wrapper { flex-direction: row; align-items: flex-start; }
1325
+ .cb-steps--responsive.cb-steps--horizontal:not(.cb-steps--panel) .cb-steps-engine-item-section { width: auto; margin: 0 0 0 var(--cb-space-2); }
1326
+ .cb-steps--responsive.cb-steps--horizontal:not(.cb-steps--panel) .cb-steps-engine-item-header { justify-content: flex-start; }
1327
+ }
1328
+
2576
1329
  .cb-sidebar {
2577
1330
  display: flex;
2578
1331
  flex-direction: column;
@@ -2615,7 +1368,9 @@ html, body { background: var(--cb-bg); color: var(--cb-fg); }
2615
1368
  text-decoration: none;
2616
1369
  cursor: pointer;
2617
1370
  }
2618
- .cb-sidebar__item:hover { background: var(--cb-surface); color: var(--cb-fg); }
1371
+ @media (hover: hover) {
1372
+ .cb-sidebar__item:hover { background: var(--cb-surface); color: var(--cb-fg); }
1373
+ }
2619
1374
  .cb-sidebar__item[data-active] { background: var(--cb-surface); color: var(--cb-fg); font-weight: var(--cb-weight-medium); }
2620
1375
  .cb-sidebar__item:focus-visible { outline: var(--cb-focus-width) solid var(--cb-tone-brand); outline-offset: var(--cb-focus-offset-inset); }
2621
1376
  .cb-sidebar__icon { display: inline-flex; flex: none; }
@@ -2641,7 +1396,9 @@ html, body { background: var(--cb-bg); color: var(--cb-fg); }
2641
1396
  color: var(--cb-fg-subtle);
2642
1397
  cursor: pointer;
2643
1398
  }
2644
- .cb-sidebar__toggle:hover { background: var(--cb-surface); color: var(--cb-fg); }
1399
+ @media (hover: hover) {
1400
+ .cb-sidebar__toggle:hover { background: var(--cb-surface); color: var(--cb-fg); }
1401
+ }
2645
1402
  .cb-sidebar__toggle:focus-visible { outline: var(--cb-focus-width) solid var(--cb-tone-brand); outline-offset: var(--cb-focus-offset); }
2646
1403
 
2647
1404
  .cb-topbar {
@@ -2713,65 +1470,6 @@ html, body { background: var(--cb-bg); color: var(--cb-fg); }
2713
1470
  border-top: var(--cb-border-width) solid var(--cb-border);
2714
1471
  }
2715
1472
 
2716
- /* nav/tabs.css */
2717
- .cb-tabs { display: flex; flex-direction: column; gap: var(--cb-space-4); }
2718
- .cb-tabs__list { position: relative; display: flex; gap: var(--cb-space-1); }
2719
- .cb-tabs--underline .cb-tabs__list { border-bottom: var(--cb-border-width) solid var(--cb-border); }
2720
-
2721
- .cb-tabs__tab {
2722
- display: inline-flex;
2723
- align-items: center;
2724
- gap: var(--cb-space-2);
2725
- border: none;
2726
- background: transparent;
2727
- color: var(--cb-fg-muted);
2728
- font-family: var(--cb-font-sans);
2729
- font-size: var(--cb-text-sm);
2730
- font-weight: var(--cb-weight-medium);
2731
- padding: var(--cb-space-2) var(--cb-space-3);
2732
- cursor: pointer;
2733
- border-radius: var(--cb-radius-sm);
2734
- transition: color var(--cb-duration-fast) var(--cb-ease-standard),
2735
- background-color var(--cb-duration-fast) var(--cb-ease-standard);
2736
- }
2737
- .cb-tabs__tab:hover:not([data-disabled]) { color: var(--cb-fg); }
2738
- .cb-tabs__tab[data-selected] { color: var(--cb-fg); }
2739
- .cb-tabs__tab[data-disabled] { opacity: 0.45; cursor: not-allowed; }
2740
- .cb-tabs__tab:focus-visible { outline: var(--cb-focus-width) solid var(--cb-tone-brand); outline-offset: var(--cb-focus-offset-inset); }
2741
- .cb-tabs__adornment { display: inline-flex; }
2742
-
2743
- .cb-tabs--pill .cb-tabs__list { background: var(--cb-bg-subtle); padding: var(--cb-space-1); border-radius: var(--cb-radius-md); }
2744
- .cb-tabs--pill .cb-tabs__tab[data-selected] { color: var(--cb-fg); }
2745
-
2746
- /* The indicator is positioned by Base UI's own custom properties; we only style it. */
2747
- .cb-tabs__indicator {
2748
- position: absolute;
2749
- transition: translate var(--cb-duration-base) var(--cb-ease-emphasis),
2750
- width var(--cb-duration-base) var(--cb-ease-emphasis);
2751
- translate: var(--active-tab-left) 0;
2752
- width: var(--active-tab-width);
2753
- }
2754
- .cb-tabs--underline .cb-tabs__indicator {
2755
- bottom: -1px;
2756
- height: 2px;
2757
- background: var(--cb-tone-brand);
2758
- border-radius: var(--cb-radius-full);
2759
- }
2760
- .cb-tabs--pill .cb-tabs__indicator {
2761
- top: var(--cb-space-1);
2762
- height: calc(100% - var(--cb-space-2));
2763
- background: var(--cb-surface-raised);
2764
- border-radius: var(--cb-radius-sm);
2765
- box-shadow: var(--cb-shadow-sm);
2766
- z-index: 0;
2767
- }
2768
- .cb-tabs--pill .cb-tabs__tab { position: relative; z-index: 1; }
2769
- @media (prefers-reduced-motion: reduce) {
2770
- .cb-tabs__indicator { transition: none; }
2771
- }
2772
-
2773
- .cb-tabs__panel:focus-visible { outline: var(--cb-focus-width) solid var(--cb-tone-brand); outline-offset: var(--cb-focus-offset); }
2774
-
2775
1473
  /* onboarding/checklist.css */
2776
1474
  .cb-checklist {
2777
1475
  display: flex;
@@ -2803,7 +1501,9 @@ html, body { background: var(--cb-bg); color: var(--cb-fg); }
2803
1501
  cursor: pointer;
2804
1502
  }
2805
1503
  .cb-checklist__task:disabled { cursor: default; }
2806
- .cb-checklist__task:hover:not(:disabled) { background: var(--cb-bg-subtle); }
1504
+ @media (hover: hover) {
1505
+ .cb-checklist__task:hover:not(:disabled) { background: var(--cb-bg-subtle); }
1506
+ }
2807
1507
  .cb-checklist__task:focus-visible { outline: var(--cb-focus-width) solid var(--cb-tone-brand); outline-offset: var(--cb-focus-offset-inset); }
2808
1508
 
2809
1509
  .cb-checklist__marker {
@@ -2826,74 +1526,3 @@ html, body { background: var(--cb-bg); color: var(--cb-fg); }
2826
1526
  .cb-checklist__description { font-size: var(--cb-text-xs); color: var(--cb-fg-subtle); }
2827
1527
  .cb-checklist__chevron { flex: none; color: var(--cb-fg-subtle); align-self: center; }
2828
1528
  .cb-checklist__complete { padding: var(--cb-space-2) 0; }
2829
-
2830
- /* onboarding/coachmark.css */
2831
- /* The hole is a box-shadow spread rather than an SVG mask: it stays crisp at any size and
2832
- costs no extra element, and the shadow colour is the same token the dialog backdrop uses. */
2833
- .cb-spotlight {
2834
- position: fixed;
2835
- z-index: var(--cb-z-coachmark-spotlight);
2836
- left: var(--cb-spotlight-x);
2837
- top: var(--cb-spotlight-y);
2838
- width: var(--cb-spotlight-w);
2839
- height: var(--cb-spotlight-h);
2840
- border-radius: var(--cb-radius-md);
2841
- box-shadow: 0 0 0 9999px var(--cb-scrim-strong);
2842
- pointer-events: auto;
2843
- transition: left var(--cb-duration-base) var(--cb-ease-standard),
2844
- top var(--cb-duration-base) var(--cb-ease-standard),
2845
- width var(--cb-duration-base) var(--cb-ease-standard),
2846
- height var(--cb-duration-base) var(--cb-ease-standard);
2847
- }
2848
- /* Reduced motion: the hole jumps to the next target instead of gliding to it. */
2849
- @media (prefers-reduced-motion: reduce) {
2850
- .cb-spotlight { transition: none; }
2851
- }
2852
-
2853
- /* The positioner is what the portal places, so the stacking order has to live here; a z-index
2854
- on the popup alone loses to the spotlight's own layer. */
2855
- .cb-coachmark__positioner { z-index: var(--cb-z-coachmark); }
2856
-
2857
- .cb-coachmark {
2858
- box-sizing: border-box;
2859
- width: 20rem;
2860
- max-width: calc(100vw - var(--cb-space-6));
2861
- background: var(--cb-surface-raised);
2862
- color: var(--cb-fg);
2863
- border: var(--cb-border-width) solid var(--cb-border);
2864
- border-radius: var(--cb-radius-lg);
2865
- box-shadow: var(--cb-shadow-lg);
2866
- padding: var(--cb-space-4);
2867
- font-family: var(--cb-font-sans);
2868
- display: flex;
2869
- flex-direction: column;
2870
- gap: var(--cb-space-3);
2871
- transition: opacity var(--cb-duration-base) var(--cb-ease-entrance),
2872
- transform var(--cb-duration-base) var(--cb-ease-entrance);
2873
- }
2874
- .cb-coachmark[data-starting-style],
2875
- .cb-coachmark[data-ending-style] { opacity: 0; transform: scale(0.96); }
2876
- @media (prefers-reduced-motion: reduce) {
2877
- .cb-coachmark { transition: opacity var(--cb-duration-fast) linear; }
2878
- .cb-coachmark[data-starting-style],
2879
- .cb-coachmark[data-ending-style] { transform: none; }
2880
- }
2881
-
2882
- .cb-coachmark__head { display: flex; align-items: flex-start; justify-content: space-between; gap: var(--cb-space-2); }
2883
- .cb-coachmark__title { margin: 0; font-size: var(--cb-text-md); font-weight: var(--cb-weight-semibold); }
2884
- .cb-coachmark__close {
2885
- border: none;
2886
- background: transparent;
2887
- color: var(--cb-fg-subtle);
2888
- cursor: pointer;
2889
- padding: var(--cb-space-1);
2890
- border-radius: var(--cb-radius-sm);
2891
- display: inline-flex;
2892
- }
2893
- .cb-coachmark__close:hover { color: var(--cb-fg); background: var(--cb-bg-subtle); }
2894
- .cb-coachmark__close:focus-visible { outline: var(--cb-focus-width) solid var(--cb-tone-brand); outline-offset: var(--cb-focus-offset); }
2895
-
2896
- .cb-coachmark__body { font-size: var(--cb-text-sm); color: var(--cb-fg-muted); line-height: var(--cb-leading-normal); }
2897
- .cb-coachmark__foot { display: flex; align-items: center; justify-content: space-between; gap: var(--cb-space-3); }
2898
- .cb-coachmark__progress { font-size: var(--cb-text-xs); color: var(--cb-fg-subtle); font-variant-numeric: tabular-nums; }
2899
- .cb-coachmark__actions { display: flex; gap: var(--cb-space-2); }