@stridge/noctis 1.0.0-beta.3 → 1.0.0-beta.5

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
@@ -481,7 +481,7 @@
481
481
  }
482
482
 
483
483
  /* ── Authored static palettes (accent-independent; switch on the resolved mode) ─────────
484
- * Chart and avatar series stay categorically stable regardless of the accent (re-theming
484
+ * Chart and categorical-palette series stay categorically stable regardless of the accent (re-theming
485
485
  * them would break legend↔series identity), so they are authored — not engine-derived. Dark
486
486
  * values sit on `:root`; light values under `[data-theme="light"]`, set by the app shell and the
487
487
  * theme provider from the resolved mode. Hues are spread across the wheel and separated in
@@ -497,17 +497,17 @@
497
497
  --noctis-color-chart-7: oklch(0.7 0.17 310);
498
498
  --noctis-color-chart-8: oklch(0.76 0.14 350);
499
499
 
500
- --noctis-color-avatar-1: oklch(0.62 0.17 264);
501
- --noctis-color-avatar-2: oklch(0.62 0.15 196);
502
- --noctis-color-avatar-3: oklch(0.62 0.16 152);
503
- --noctis-color-avatar-4: oklch(0.64 0.15 130);
504
- --noctis-color-avatar-5: oklch(0.66 0.16 70);
505
- --noctis-color-avatar-6: oklch(0.62 0.18 40);
506
- --noctis-color-avatar-7: oklch(0.6 0.2 18);
507
- --noctis-color-avatar-8: oklch(0.6 0.18 330);
508
- --noctis-color-avatar-9: oklch(0.6 0.18 300);
509
- --noctis-color-avatar-10: oklch(0.6 0.15 285);
510
- --noctis-color-avatar-foreground: oklch(0.99 0 0);
500
+ --noctis-color-palette-1: oklch(0.62 0.17 264);
501
+ --noctis-color-palette-2: oklch(0.62 0.15 196);
502
+ --noctis-color-palette-3: oklch(0.62 0.16 152);
503
+ --noctis-color-palette-4: oklch(0.64 0.15 130);
504
+ --noctis-color-palette-5: oklch(0.66 0.16 70);
505
+ --noctis-color-palette-6: oklch(0.62 0.18 40);
506
+ --noctis-color-palette-7: oklch(0.6 0.2 18);
507
+ --noctis-color-palette-8: oklch(0.6 0.18 330);
508
+ --noctis-color-palette-9: oklch(0.6 0.18 300);
509
+ --noctis-color-palette-10: oklch(0.6 0.15 285);
510
+ --noctis-color-palette-foreground: oklch(0.99 0 0);
511
511
  }
512
512
 
513
513
  :root[data-theme="light"] {
@@ -520,16 +520,16 @@
520
520
  --noctis-color-chart-7: oklch(0.55 0.19 310);
521
521
  --noctis-color-chart-8: oklch(0.6 0.16 350);
522
522
 
523
- --noctis-color-avatar-1: oklch(0.58 0.18 264);
524
- --noctis-color-avatar-2: oklch(0.56 0.15 196);
525
- --noctis-color-avatar-3: oklch(0.56 0.16 152);
526
- --noctis-color-avatar-4: oklch(0.58 0.15 130);
527
- --noctis-color-avatar-5: oklch(0.62 0.16 70);
528
- --noctis-color-avatar-6: oklch(0.58 0.19 40);
529
- --noctis-color-avatar-7: oklch(0.56 0.21 18);
530
- --noctis-color-avatar-8: oklch(0.56 0.19 330);
531
- --noctis-color-avatar-9: oklch(0.56 0.19 300);
532
- --noctis-color-avatar-10: oklch(0.56 0.16 285);
523
+ --noctis-color-palette-1: oklch(0.58 0.18 264);
524
+ --noctis-color-palette-2: oklch(0.56 0.15 196);
525
+ --noctis-color-palette-3: oklch(0.56 0.16 152);
526
+ --noctis-color-palette-4: oklch(0.58 0.15 130);
527
+ --noctis-color-palette-5: oklch(0.62 0.16 70);
528
+ --noctis-color-palette-6: oklch(0.58 0.19 40);
529
+ --noctis-color-palette-7: oklch(0.56 0.21 18);
530
+ --noctis-color-palette-8: oklch(0.56 0.19 330);
531
+ --noctis-color-palette-9: oklch(0.56 0.19 300);
532
+ --noctis-color-palette-10: oklch(0.56 0.16 285);
533
533
  }
534
534
 
535
535
  /* ── Light-mode shadows ─────────────────────────────────────────────────────────────────
@@ -1705,6 +1705,29 @@
1705
1705
  --_toolbar-input-height: var(--noctis-toolbar-input-height, var(--noctis-size-control-xs));
1706
1706
  --_toolbar-input-padding-inline: var(--noctis-toolbar-input-padding-inline, var(--noctis-space-1\.5));
1707
1707
  }
1708
+ [data-slot="noctis-pagination"] {
1709
+ --_pagination-gap: var(--noctis-pagination-gap, var(--noctis-space-3));
1710
+ }
1711
+ [data-slot="noctis-pagination-info"] {
1712
+ --_pagination-info-font-size: var(--noctis-pagination-info-font-size, var(--noctis-text-small));
1713
+ --_pagination-info-color: var(--noctis-pagination-info-color, var(--noctis-color-muted));
1714
+ }
1715
+ [data-slot="noctis-pagination-page-size"] {
1716
+ --_pagination-page-size-gap: var(--noctis-pagination-page-size-gap, var(--noctis-space-2));
1717
+ }
1718
+ [data-slot="noctis-pagination-page"] {
1719
+ --_pagination-page-gap: var(--noctis-pagination-page-gap, var(--noctis-space-2));
1720
+ --_pagination-page-inline-size: var(--noctis-pagination-page-inline-size, 3.5rem);
1721
+ --_pagination-page-block-size: var(--noctis-pagination-page-block-size, var(--noctis-size-control-md));
1722
+ }
1723
+ [data-slot="noctis-pagination-separator"] {
1724
+ --_pagination-separator-color: var(--noctis-pagination-separator-color, var(--noctis-color-border));
1725
+ --_pagination-separator-inline-size: var(--noctis-pagination-separator-inline-size, 1px);
1726
+ --_pagination-separator-block-size: var(--noctis-pagination-separator-block-size, 1.5rem);
1727
+ }
1728
+ [data-slot="noctis-pagination"][data-size="sm"] [data-slot="noctis-pagination-page"] {
1729
+ --_pagination-page-block-size: var(--noctis-pagination-page-block-size, var(--noctis-size-control-sm));
1730
+ }
1708
1731
  [data-slot="noctis-accordion-trigger"] {
1709
1732
  --_accordion-trigger-padding-inline: var(--noctis-accordion-trigger-padding-inline, 0);
1710
1733
  --_accordion-trigger-padding-block: var(--noctis-accordion-trigger-padding-block, var(--noctis-space-4));
@@ -2441,6 +2464,31 @@
2441
2464
  [data-slot="noctis-avatar"][data-size="xl"] [data-slot="noctis-avatar-indicator"] {
2442
2465
  --_avatar-indicator-size: var(--noctis-avatar-indicator-size, 1rem);
2443
2466
  }
2467
+ [data-slot="noctis-badge"] {
2468
+ --_badge-padding-inline: var(--noctis-badge-padding-inline, 0.5rem);
2469
+ --_badge-padding-block: var(--noctis-badge-padding-block, 0.1875rem);
2470
+ --_badge-gap: var(--noctis-badge-gap, 0.3125rem);
2471
+ --_badge-font-size: var(--noctis-badge-font-size, var(--noctis-text-mini));
2472
+ --_badge-border-radius: var(--noctis-badge-border-radius, var(--noctis-radius-full));
2473
+ }
2474
+ [data-slot="noctis-badge-dot"] {
2475
+ --_badge-dot-size: var(--noctis-badge-dot-size, 0.375rem);
2476
+ }
2477
+ [data-slot="noctis-badge-icon"] {
2478
+ --_badge-icon-size: var(--noctis-badge-icon-size, 0.875rem);
2479
+ }
2480
+ [data-slot="noctis-badge"][data-size="sm"] {
2481
+ --_badge-padding-inline: var(--noctis-badge-padding-inline, 0.4375rem);
2482
+ --_badge-padding-block: var(--noctis-badge-padding-block, 0.125rem);
2483
+ --_badge-gap: var(--noctis-badge-gap, 0.25rem);
2484
+ --_badge-font-size: var(--noctis-badge-font-size, var(--noctis-text-micro));
2485
+ }
2486
+ [data-slot="noctis-badge"][data-size="sm"] [data-slot="noctis-badge-dot"] {
2487
+ --_badge-dot-size: var(--noctis-badge-dot-size, 0.3125rem);
2488
+ }
2489
+ [data-slot="noctis-badge"][data-size="sm"] [data-slot="noctis-badge-icon"] {
2490
+ --_badge-icon-size: var(--noctis-badge-icon-size, 0.75rem);
2491
+ }
2444
2492
  [data-slot="noctis-otp-field"] {
2445
2493
  --_otp-field-gap: var(--noctis-otp-field-gap, 0.5rem);
2446
2494
  }
@@ -3402,7 +3450,7 @@
3402
3450
  * box-shadow rings) can extend past the edge without being cut off.
3403
3451
  *
3404
3452
  * Avatars are static-identity and accent-independent: the fallback fill is one of ten authored
3405
- * `--noctis-color-avatar-N` roles, selected by the `data-avatar-index` the component hashes from a
3453
+ * `--noctis-color-palette-N` roles, selected by the `data-avatar-index` the component hashes from a
3406
3454
  * stable seed — so categorical identity holds across themes and the fill never re-themes on the accent.
3407
3455
  */
3408
3456
 
@@ -3456,48 +3504,48 @@
3456
3504
  font-weight: 500;
3457
3505
  line-height: 1;
3458
3506
  text-transform: uppercase;
3459
- color: var(--noctis-color-avatar-foreground);
3507
+ color: var(--noctis-color-palette-foreground);
3460
3508
  background-color: var(--noctis-color-muted);
3461
3509
  }
3462
3510
 
3463
3511
  [data-slot="noctis-avatar-fallback"][data-avatar-index="1"] {
3464
- background-color: var(--noctis-color-avatar-1);
3512
+ background-color: var(--noctis-color-palette-1);
3465
3513
  }
3466
3514
 
3467
3515
  [data-slot="noctis-avatar-fallback"][data-avatar-index="2"] {
3468
- background-color: var(--noctis-color-avatar-2);
3516
+ background-color: var(--noctis-color-palette-2);
3469
3517
  }
3470
3518
 
3471
3519
  [data-slot="noctis-avatar-fallback"][data-avatar-index="3"] {
3472
- background-color: var(--noctis-color-avatar-3);
3520
+ background-color: var(--noctis-color-palette-3);
3473
3521
  }
3474
3522
 
3475
3523
  [data-slot="noctis-avatar-fallback"][data-avatar-index="4"] {
3476
- background-color: var(--noctis-color-avatar-4);
3524
+ background-color: var(--noctis-color-palette-4);
3477
3525
  }
3478
3526
 
3479
3527
  [data-slot="noctis-avatar-fallback"][data-avatar-index="5"] {
3480
- background-color: var(--noctis-color-avatar-5);
3528
+ background-color: var(--noctis-color-palette-5);
3481
3529
  }
3482
3530
 
3483
3531
  [data-slot="noctis-avatar-fallback"][data-avatar-index="6"] {
3484
- background-color: var(--noctis-color-avatar-6);
3532
+ background-color: var(--noctis-color-palette-6);
3485
3533
  }
3486
3534
 
3487
3535
  [data-slot="noctis-avatar-fallback"][data-avatar-index="7"] {
3488
- background-color: var(--noctis-color-avatar-7);
3536
+ background-color: var(--noctis-color-palette-7);
3489
3537
  }
3490
3538
 
3491
3539
  [data-slot="noctis-avatar-fallback"][data-avatar-index="8"] {
3492
- background-color: var(--noctis-color-avatar-8);
3540
+ background-color: var(--noctis-color-palette-8);
3493
3541
  }
3494
3542
 
3495
3543
  [data-slot="noctis-avatar-fallback"][data-avatar-index="9"] {
3496
- background-color: var(--noctis-color-avatar-9);
3544
+ background-color: var(--noctis-color-palette-9);
3497
3545
  }
3498
3546
 
3499
3547
  [data-slot="noctis-avatar-fallback"][data-avatar-index="10"] {
3500
- background-color: var(--noctis-color-avatar-10);
3548
+ background-color: var(--noctis-color-palette-10);
3501
3549
  }
3502
3550
 
3503
3551
  /*
@@ -3672,6 +3720,381 @@
3672
3720
  }
3673
3721
  }
3674
3722
 
3723
+ @layer noctis.components {
3724
+ /*
3725
+ * Badge is self-contained, so every rule keys off the element's own `data-slot`. The chip metrics
3726
+ * flow through the `--_badge-*` internals, whose per-size defaults live in the generated component
3727
+ * layer (`tokens.css`) keyed off the `data-size` the root stamps.
3728
+ *
3729
+ * Colour is a two-axis grid: `data-variant` (the emphasis — a `solid` fill, a `soft` tint, a
3730
+ * transparent `outline`, or a neutral `dot` chip) crossed with `data-tone` (the colour identity). In
3731
+ * every variant but `dot` the tone tints the whole chip and the dot/icon ride `currentColor`; the
3732
+ * `dot` variant keeps the chip neutral and colours the leading dot alone. Like Avatar's swatch rules,
3733
+ * the grid is hand-authored flat rules reading a declared role or palette swatch directly — no
3734
+ * `--_badge-*` colour internal and no mint re-point, so a global retheme of a status/accent role (or
3735
+ * the shared categorical palette) propagates for free, and the decorative tones never re-derive off
3736
+ * the accent.
3737
+ *
3738
+ * The six semantic tones (neutral/accent/success/warning/danger/info) paint from their role families
3739
+ * — `solid` from the role, `soft` from its `-muted` tint, `outline` from its `-border`. The eight
3740
+ * decorative tones (red…pink) map onto the accent-independent `--noctis-color-palette-N` palette,
3741
+ * authored for a white knockout, so a `solid` decorative chip stays legible; `soft` shows the swatch
3742
+ * as the label on the neutral chip tint and `outline` draws the swatch as the edge (the palette ships
3743
+ * no engine tint of its own, and a derived tint isn't expressible in component CSS).
3744
+ *
3745
+ * The dot and icon take no tone rules of their own: the dot fills with `currentColor` and the icon
3746
+ * inherits it, so both track the chip's text colour and stay legible in every variant automatically.
3747
+ */
3748
+
3749
+ /* root — the pill. A transparent 1px border holds the box geometry stable across variants, so the
3750
+ * `outline` variant (which colours that border) never shifts the chip's size. The base colours are
3751
+ * the default neutral `soft` look; the variant×tone rules below override them. */
3752
+ [data-slot="noctis-badge"] {
3753
+ display: inline-flex;
3754
+ align-items: center;
3755
+ justify-content: center;
3756
+ gap: var(--_badge-gap);
3757
+ inline-size: fit-content;
3758
+ max-inline-size: 100%;
3759
+ padding-block: var(--_badge-padding-block);
3760
+ padding-inline: var(--_badge-padding-inline);
3761
+ border: 1px solid transparent;
3762
+ border-radius: var(--_badge-border-radius);
3763
+ font-family: var(--noctis-font-sans);
3764
+ font-size: var(--_badge-font-size);
3765
+ font-weight: 500;
3766
+ line-height: 1;
3767
+ white-space: nowrap;
3768
+ vertical-align: middle;
3769
+ color: var(--noctis-color-foreground);
3770
+ background-color: var(--noctis-color-control);
3771
+ }
3772
+
3773
+ /* A badge rendered on an anchor joins the chip, not the link — keep the chip's own colour, drop the
3774
+ * underline. */
3775
+ a[data-slot="noctis-badge"] {
3776
+ text-decoration: none;
3777
+ }
3778
+
3779
+ /* dot — a small leading status dot. Fills with the chip's text colour, so it reads on the fill in
3780
+ * `solid` (a knockout dot) and shows the saturated tone in `soft`/`outline`. */
3781
+ [data-slot="noctis-badge-dot"] {
3782
+ flex-shrink: 0;
3783
+ inline-size: var(--_badge-dot-size);
3784
+ block-size: var(--_badge-dot-size);
3785
+ border-radius: var(--noctis-radius-full);
3786
+ background-color: currentcolor;
3787
+ }
3788
+
3789
+ /* icon — a leading glyph clamped to the chip's icon size; inherits the chip's text colour. */
3790
+ [data-slot="noctis-badge-icon"] {
3791
+ display: inline-flex;
3792
+ flex-shrink: 0;
3793
+ align-items: center;
3794
+ justify-content: center;
3795
+ }
3796
+
3797
+ [data-slot="noctis-badge-icon"] svg {
3798
+ inline-size: var(--_badge-icon-size);
3799
+ block-size: var(--_badge-icon-size);
3800
+ }
3801
+
3802
+ /* ─── solid: a filled chip with a knockout label ─────────────────────────────────────────────── */
3803
+
3804
+ [data-slot="noctis-badge"][data-variant="solid"][data-tone="neutral"] {
3805
+ background-color: var(--noctis-color-primary);
3806
+ color: var(--noctis-color-primary-foreground);
3807
+ }
3808
+
3809
+ [data-slot="noctis-badge"][data-variant="solid"][data-tone="accent"] {
3810
+ background-color: var(--noctis-color-accent);
3811
+ color: var(--noctis-color-accent-foreground);
3812
+ }
3813
+
3814
+ [data-slot="noctis-badge"][data-variant="solid"][data-tone="success"] {
3815
+ background-color: var(--noctis-color-success);
3816
+ color: var(--noctis-color-success-foreground);
3817
+ }
3818
+
3819
+ [data-slot="noctis-badge"][data-variant="solid"][data-tone="warning"] {
3820
+ background-color: var(--noctis-color-warning);
3821
+ color: var(--noctis-color-warning-foreground);
3822
+ }
3823
+
3824
+ [data-slot="noctis-badge"][data-variant="solid"][data-tone="danger"] {
3825
+ background-color: var(--noctis-color-danger);
3826
+ color: var(--noctis-color-danger-foreground);
3827
+ }
3828
+
3829
+ [data-slot="noctis-badge"][data-variant="solid"][data-tone="info"] {
3830
+ background-color: var(--noctis-color-info);
3831
+ color: var(--noctis-color-info-foreground);
3832
+ }
3833
+
3834
+ [data-slot="noctis-badge"][data-variant="solid"][data-tone="red"] {
3835
+ background-color: var(--noctis-color-palette-7);
3836
+ color: var(--noctis-color-palette-foreground);
3837
+ }
3838
+
3839
+ [data-slot="noctis-badge"][data-variant="solid"][data-tone="orange"] {
3840
+ background-color: var(--noctis-color-palette-6);
3841
+ color: var(--noctis-color-palette-foreground);
3842
+ }
3843
+
3844
+ [data-slot="noctis-badge"][data-variant="solid"][data-tone="amber"] {
3845
+ background-color: var(--noctis-color-palette-5);
3846
+ color: var(--noctis-color-palette-foreground);
3847
+ }
3848
+
3849
+ [data-slot="noctis-badge"][data-variant="solid"][data-tone="green"] {
3850
+ background-color: var(--noctis-color-palette-4);
3851
+ color: var(--noctis-color-palette-foreground);
3852
+ }
3853
+
3854
+ [data-slot="noctis-badge"][data-variant="solid"][data-tone="teal"] {
3855
+ background-color: var(--noctis-color-palette-3);
3856
+ color: var(--noctis-color-palette-foreground);
3857
+ }
3858
+
3859
+ [data-slot="noctis-badge"][data-variant="solid"][data-tone="blue"] {
3860
+ background-color: var(--noctis-color-palette-1);
3861
+ color: var(--noctis-color-palette-foreground);
3862
+ }
3863
+
3864
+ [data-slot="noctis-badge"][data-variant="solid"][data-tone="purple"] {
3865
+ background-color: var(--noctis-color-palette-9);
3866
+ color: var(--noctis-color-palette-foreground);
3867
+ }
3868
+
3869
+ [data-slot="noctis-badge"][data-variant="solid"][data-tone="pink"] {
3870
+ background-color: var(--noctis-color-palette-8);
3871
+ color: var(--noctis-color-palette-foreground);
3872
+ }
3873
+
3874
+ /* ─── soft: a quiet tint behind saturated text ──────────────────────────────────────────────── */
3875
+
3876
+ [data-slot="noctis-badge"][data-variant="soft"][data-tone="neutral"] {
3877
+ background-color: var(--noctis-color-control);
3878
+ color: var(--noctis-color-foreground);
3879
+ }
3880
+
3881
+ [data-slot="noctis-badge"][data-variant="soft"][data-tone="accent"] {
3882
+ background-color: var(--noctis-color-accent-muted);
3883
+ color: var(--noctis-color-accent);
3884
+ }
3885
+
3886
+ [data-slot="noctis-badge"][data-variant="soft"][data-tone="success"] {
3887
+ background-color: var(--noctis-color-success-muted);
3888
+ color: var(--noctis-color-success-muted-foreground);
3889
+ }
3890
+
3891
+ [data-slot="noctis-badge"][data-variant="soft"][data-tone="warning"] {
3892
+ background-color: var(--noctis-color-warning-muted);
3893
+ color: var(--noctis-color-warning-muted-foreground);
3894
+ }
3895
+
3896
+ [data-slot="noctis-badge"][data-variant="soft"][data-tone="danger"] {
3897
+ background-color: var(--noctis-color-danger-muted);
3898
+ color: var(--noctis-color-danger-muted-foreground);
3899
+ }
3900
+
3901
+ [data-slot="noctis-badge"][data-variant="soft"][data-tone="info"] {
3902
+ background-color: var(--noctis-color-info-muted);
3903
+ color: var(--noctis-color-info-muted-foreground);
3904
+ }
3905
+
3906
+ /* Decorative `soft` sits the saturated palette colour as text on the neutral chip tint — the
3907
+ * the palette swatches ship no engine tint of their own (unlike the semantic `-muted` roles), and a
3908
+ * faint tint can't be derived in component CSS (no `color-mix`), so the colour reads through the
3909
+ * label while the chip stays a quiet neutral. */
3910
+ [data-slot="noctis-badge"][data-variant="soft"][data-tone="red"] {
3911
+ color: var(--noctis-color-palette-7);
3912
+ }
3913
+
3914
+ [data-slot="noctis-badge"][data-variant="soft"][data-tone="orange"] {
3915
+ color: var(--noctis-color-palette-6);
3916
+ }
3917
+
3918
+ [data-slot="noctis-badge"][data-variant="soft"][data-tone="amber"] {
3919
+ color: var(--noctis-color-palette-5);
3920
+ }
3921
+
3922
+ [data-slot="noctis-badge"][data-variant="soft"][data-tone="green"] {
3923
+ color: var(--noctis-color-palette-4);
3924
+ }
3925
+
3926
+ [data-slot="noctis-badge"][data-variant="soft"][data-tone="teal"] {
3927
+ color: var(--noctis-color-palette-3);
3928
+ }
3929
+
3930
+ [data-slot="noctis-badge"][data-variant="soft"][data-tone="blue"] {
3931
+ color: var(--noctis-color-palette-1);
3932
+ }
3933
+
3934
+ [data-slot="noctis-badge"][data-variant="soft"][data-tone="purple"] {
3935
+ color: var(--noctis-color-palette-9);
3936
+ }
3937
+
3938
+ [data-slot="noctis-badge"][data-variant="soft"][data-tone="pink"] {
3939
+ color: var(--noctis-color-palette-8);
3940
+ }
3941
+
3942
+ /* ─── outline: a transparent chip with a coloured edge ──────────────────────────────────────── */
3943
+
3944
+ [data-slot="noctis-badge"][data-variant="outline"][data-tone="neutral"] {
3945
+ background-color: transparent;
3946
+ border-color: var(--noctis-color-border);
3947
+ color: var(--noctis-color-foreground);
3948
+ }
3949
+
3950
+ [data-slot="noctis-badge"][data-variant="outline"][data-tone="accent"] {
3951
+ background-color: transparent;
3952
+ border-color: var(--noctis-color-accent);
3953
+ color: var(--noctis-color-accent);
3954
+ }
3955
+
3956
+ [data-slot="noctis-badge"][data-variant="outline"][data-tone="success"] {
3957
+ background-color: transparent;
3958
+ border-color: var(--noctis-color-success-border);
3959
+ color: var(--noctis-color-success-muted-foreground);
3960
+ }
3961
+
3962
+ [data-slot="noctis-badge"][data-variant="outline"][data-tone="warning"] {
3963
+ background-color: transparent;
3964
+ border-color: var(--noctis-color-warning-border);
3965
+ color: var(--noctis-color-warning-muted-foreground);
3966
+ }
3967
+
3968
+ [data-slot="noctis-badge"][data-variant="outline"][data-tone="danger"] {
3969
+ background-color: transparent;
3970
+ border-color: var(--noctis-color-danger-border);
3971
+ color: var(--noctis-color-danger-muted-foreground);
3972
+ }
3973
+
3974
+ [data-slot="noctis-badge"][data-variant="outline"][data-tone="info"] {
3975
+ background-color: transparent;
3976
+ border-color: var(--noctis-color-info-border);
3977
+ color: var(--noctis-color-info-muted-foreground);
3978
+ }
3979
+
3980
+ /* Decorative `outline` draws the saturated palette swatch as both the edge and the label colour on a
3981
+ * transparent chip — the full swatch (no derived alpha) keeps the rule a declared-role read. */
3982
+ [data-slot="noctis-badge"][data-variant="outline"][data-tone="red"] {
3983
+ background-color: transparent;
3984
+ border-color: var(--noctis-color-palette-7);
3985
+ color: var(--noctis-color-palette-7);
3986
+ }
3987
+
3988
+ [data-slot="noctis-badge"][data-variant="outline"][data-tone="orange"] {
3989
+ background-color: transparent;
3990
+ border-color: var(--noctis-color-palette-6);
3991
+ color: var(--noctis-color-palette-6);
3992
+ }
3993
+
3994
+ [data-slot="noctis-badge"][data-variant="outline"][data-tone="amber"] {
3995
+ background-color: transparent;
3996
+ border-color: var(--noctis-color-palette-5);
3997
+ color: var(--noctis-color-palette-5);
3998
+ }
3999
+
4000
+ [data-slot="noctis-badge"][data-variant="outline"][data-tone="green"] {
4001
+ background-color: transparent;
4002
+ border-color: var(--noctis-color-palette-4);
4003
+ color: var(--noctis-color-palette-4);
4004
+ }
4005
+
4006
+ [data-slot="noctis-badge"][data-variant="outline"][data-tone="teal"] {
4007
+ background-color: transparent;
4008
+ border-color: var(--noctis-color-palette-3);
4009
+ color: var(--noctis-color-palette-3);
4010
+ }
4011
+
4012
+ [data-slot="noctis-badge"][data-variant="outline"][data-tone="blue"] {
4013
+ background-color: transparent;
4014
+ border-color: var(--noctis-color-palette-1);
4015
+ color: var(--noctis-color-palette-1);
4016
+ }
4017
+
4018
+ [data-slot="noctis-badge"][data-variant="outline"][data-tone="purple"] {
4019
+ background-color: transparent;
4020
+ border-color: var(--noctis-color-palette-9);
4021
+ color: var(--noctis-color-palette-9);
4022
+ }
4023
+
4024
+ [data-slot="noctis-badge"][data-variant="outline"][data-tone="pink"] {
4025
+ background-color: transparent;
4026
+ border-color: var(--noctis-color-palette-8);
4027
+ color: var(--noctis-color-palette-8);
4028
+ }
4029
+
4030
+ /* ─── dot: a neutral chip whose only colour is its leading status dot ───────────────────────────
4031
+ * Unlike the variants above (where the tone tints the whole chip), the `dot` variant keeps the chip
4032
+ * neutral — a transparent fill, a hairline border, neutral text for every tone — and lets the dot
4033
+ * alone carry the status colour. So the dot must NOT ride `currentColor` here (that would render it
4034
+ * neutral); each tone re-points the dot fill to its saturated role/swatch. */
4035
+ [data-slot="noctis-badge"][data-variant="dot"] {
4036
+ background-color: transparent;
4037
+ border-color: var(--noctis-color-border);
4038
+ color: var(--noctis-color-foreground);
4039
+ }
4040
+
4041
+ [data-slot="noctis-badge"][data-variant="dot"][data-tone="neutral"] [data-slot="noctis-badge-dot"] {
4042
+ background-color: var(--noctis-color-muted);
4043
+ }
4044
+
4045
+ [data-slot="noctis-badge"][data-variant="dot"][data-tone="accent"] [data-slot="noctis-badge-dot"] {
4046
+ background-color: var(--noctis-color-accent);
4047
+ }
4048
+
4049
+ [data-slot="noctis-badge"][data-variant="dot"][data-tone="success"] [data-slot="noctis-badge-dot"] {
4050
+ background-color: var(--noctis-color-success);
4051
+ }
4052
+
4053
+ [data-slot="noctis-badge"][data-variant="dot"][data-tone="warning"] [data-slot="noctis-badge-dot"] {
4054
+ background-color: var(--noctis-color-warning);
4055
+ }
4056
+
4057
+ [data-slot="noctis-badge"][data-variant="dot"][data-tone="danger"] [data-slot="noctis-badge-dot"] {
4058
+ background-color: var(--noctis-color-danger);
4059
+ }
4060
+
4061
+ [data-slot="noctis-badge"][data-variant="dot"][data-tone="info"] [data-slot="noctis-badge-dot"] {
4062
+ background-color: var(--noctis-color-info);
4063
+ }
4064
+
4065
+ [data-slot="noctis-badge"][data-variant="dot"][data-tone="red"] [data-slot="noctis-badge-dot"] {
4066
+ background-color: var(--noctis-color-palette-7);
4067
+ }
4068
+
4069
+ [data-slot="noctis-badge"][data-variant="dot"][data-tone="orange"] [data-slot="noctis-badge-dot"] {
4070
+ background-color: var(--noctis-color-palette-6);
4071
+ }
4072
+
4073
+ [data-slot="noctis-badge"][data-variant="dot"][data-tone="amber"] [data-slot="noctis-badge-dot"] {
4074
+ background-color: var(--noctis-color-palette-5);
4075
+ }
4076
+
4077
+ [data-slot="noctis-badge"][data-variant="dot"][data-tone="green"] [data-slot="noctis-badge-dot"] {
4078
+ background-color: var(--noctis-color-palette-4);
4079
+ }
4080
+
4081
+ [data-slot="noctis-badge"][data-variant="dot"][data-tone="teal"] [data-slot="noctis-badge-dot"] {
4082
+ background-color: var(--noctis-color-palette-3);
4083
+ }
4084
+
4085
+ [data-slot="noctis-badge"][data-variant="dot"][data-tone="blue"] [data-slot="noctis-badge-dot"] {
4086
+ background-color: var(--noctis-color-palette-1);
4087
+ }
4088
+
4089
+ [data-slot="noctis-badge"][data-variant="dot"][data-tone="purple"] [data-slot="noctis-badge-dot"] {
4090
+ background-color: var(--noctis-color-palette-9);
4091
+ }
4092
+
4093
+ [data-slot="noctis-badge"][data-variant="dot"][data-tone="pink"] [data-slot="noctis-badge-dot"] {
4094
+ background-color: var(--noctis-color-palette-8);
4095
+ }
4096
+ }
4097
+
3675
4098
  @layer noctis.components {
3676
4099
  /*
3677
4100
  * Button is a class-escape-hatch primitive: `Button.props()` styles a *foreign* element (the rail's
@@ -3912,8 +4335,9 @@
3912
4335
  * menu trigger's popup is open (and a `Menu.Trigger` rendered as a `Button` carries
3913
4336
  * `data-slot="noctis-menu-trigger"`, not `"noctis-button"`), so keying on the marker is what keeps the
3914
4337
  * seam on exactly the real segments. The general-sibling (`~`) and `:has()` selectors look through any
3915
- * guard between two segments. Logical properties throughout (`margin-inline-start`, `inset-inline-start`),
3916
- * so the whole thing mirrors under RTL. The divider's width and colour flow through the
4338
+ * guard between two segments. Logical properties throughout (`border-inline-start-width`,
4339
+ * `inset-inline-start`), so the whole thing mirrors under RTL. The divider's width and colour flow
4340
+ * through the
3917
4341
  * `--_button-group-seam-*` internals declared on the group slot in the generated layer, so
3918
4342
  * `--noctis-button-group-seam-*` retunes it; the high-contrast `strong` border token reads clearly
3919
4343
  * across every button variant.
@@ -3947,19 +4371,24 @@
3947
4371
  }
3948
4372
 
3949
4373
  /*
3950
- * Square each later segment's inner-start corner, and pull it onto the previous segment's border so
3951
- * the two share one edge. Anchored on the group root, reaching only its direct-child marked segments.
4374
+ * Weld the segments: square each junction's corners and DROP the touching (inner) borders, so the
4375
+ * seam drawn below is the single divider. A bordered variant (secondary/outline) used to keep its
4376
+ * own 1px border at the junction *and* get the seam on top — two lines, a doubled divider; dropping
4377
+ * the inner borders leaves exactly the seam. Segments sit flush (no negative margin); a borderless
4378
+ * variant (primary/ghost/…) has no inner border to drop, so it is unaffected and the seam still
4379
+ * divides it. Anchored on the group root, reaching only its direct-child marked segments.
3952
4380
  */
3953
4381
  [data-slot="noctis-button-group"] > [data-button-group-item] ~ [data-button-group-item] {
3954
- margin-inline-start: -1px;
3955
4382
  border-start-start-radius: 0;
3956
4383
  border-end-start-radius: 0;
4384
+ border-inline-start-width: 0;
3957
4385
  }
3958
4386
 
3959
- /* Square the inner-end corner of every segment that has a later sibling segment. */
4387
+ /* Square the inner-end corner of every segment that has a later sibling, and drop its inner-end border. */
3960
4388
  [data-slot="noctis-button-group"] > [data-button-group-item]:has(~ [data-button-group-item]) {
3961
4389
  border-start-end-radius: 0;
3962
4390
  border-end-end-radius: 0;
4391
+ border-inline-end-width: 0;
3963
4392
  }
3964
4393
 
3965
4394
  /*
@@ -7361,6 +7790,97 @@
7361
7790
  }
7362
7791
  }
7363
7792
 
7793
+ @layer noctis.components {
7794
+ /*
7795
+ * Pagination is a self-contained CONTAINER, so every rule keys off its own `data-slot`. It hosts
7796
+ * real Noctis controls — the nav buttons render `Button` welded by a `ButtonGroup`, the page field
7797
+ * renders `Input`, the page-size picker renders `Select` — and those keep their own slots, paint,
7798
+ * and per-size metrics: Pagination styles only its own layout (the row + cluster gaps), the info
7799
+ * line's type, the page field's width, and the hairline separator. The control `size` is fed to the
7800
+ * hosted controls through React context in the orchestration, not a token re-point here. Identity
7801
+ * values flow through the generated `--_pagination-*` internals; the rest is structural layout.
7802
+ */
7803
+
7804
+ /* root — the navigation row. Wraps when narrow; the consumer adds their own justify if they want
7805
+ * the info line and controls pushed apart. */
7806
+ [data-slot="noctis-pagination"] {
7807
+ display: flex;
7808
+ flex-wrap: wrap;
7809
+ align-items: center;
7810
+ gap: var(--_pagination-gap);
7811
+ }
7812
+
7813
+ /* info — the “Showing X–Y of Z” status line, quieter than the controls. */
7814
+ [data-slot="noctis-pagination-info"] {
7815
+ font-size: var(--_pagination-info-font-size);
7816
+ color: var(--_pagination-info-color);
7817
+ }
7818
+
7819
+ /* page-size — the cluster laying out the “Per page” label beside its select. Layout only; the label
7820
+ * carries its own quiet type/colour and the hosted Select keeps its own. */
7821
+ [data-slot="noctis-pagination-page-size"] {
7822
+ display: inline-flex;
7823
+ align-items: center;
7824
+ gap: var(--_pagination-page-size-gap);
7825
+ }
7826
+
7827
+ [data-slot="noctis-pagination-page-size-label"] {
7828
+ font-size: var(--noctis-text-small);
7829
+ color: var(--noctis-color-muted);
7830
+ }
7831
+
7832
+ /* page — the “Page [n] of N” cluster. The hosted Input is clamped to the page-field width and its
7833
+ * value is centred. */
7834
+ [data-slot="noctis-pagination-page"] {
7835
+ display: inline-flex;
7836
+ align-items: center;
7837
+ gap: var(--_pagination-page-gap);
7838
+ font-size: var(--noctis-text-small);
7839
+ color: var(--noctis-color-muted);
7840
+ }
7841
+
7842
+ [data-slot="noctis-pagination-page"] [data-slot="noctis-input"] {
7843
+ inline-size: var(--_pagination-page-inline-size);
7844
+ }
7845
+
7846
+ [data-slot="noctis-pagination-page"] input {
7847
+ text-align: center;
7848
+ }
7849
+
7850
+ /*
7851
+ * Inside the controls `ButtonGroup`, the page field welds flush like a button segment: the wrapper is
7852
+ * positioned so the group's seam pseudo-element anchors on it, and the inner Input is flattened — a
7853
+ * squared radius (it must NOT follow the pill `radius-control`), its inner borders dropped so the
7854
+ * group's seams are the only dividers (no doubled line), and its rest shadow removed so it sits level
7855
+ * with the flattened buttons. The top/bottom field border stays, lining up with the buttons' edges.
7856
+ */
7857
+ [data-slot="noctis-pagination-controls"] [data-slot="noctis-pagination-page"] {
7858
+ position: relative;
7859
+ }
7860
+
7861
+ [data-slot="noctis-pagination-controls"] [data-slot="noctis-pagination-page"] [data-slot="noctis-input"] {
7862
+ block-size: var(--_pagination-page-block-size);
7863
+ border-inline-start-width: 0;
7864
+ border-inline-end-width: 0;
7865
+ border-radius: 0;
7866
+ box-shadow: none;
7867
+ }
7868
+
7869
+ /* controls — the navigation landmark wrapping the welded ButtonGroup of nav buttons. */
7870
+ [data-slot="noctis-pagination-controls"] {
7871
+ display: inline-flex;
7872
+ align-items: center;
7873
+ }
7874
+
7875
+ /* separator — a vertical hairline between clusters (its own minted rule, like Toolbar's). */
7876
+ [data-slot="noctis-pagination-separator"] {
7877
+ flex-shrink: 0;
7878
+ inline-size: var(--_pagination-separator-inline-size);
7879
+ block-size: var(--_pagination-separator-block-size);
7880
+ background-color: var(--_pagination-separator-color);
7881
+ }
7882
+ }
7883
+
7364
7884
  @layer noctis.components {
7365
7885
  /*
7366
7886
  * PreviewCard is precompiled: every rule keys off the prefixed `data-slot` anchor (no `:where()`, so