@grimoire-rs/indexer 0.4.0 → 0.4.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. package/README.md +85 -9
  2. package/dist/cli/enrich.d.ts +1 -0
  3. package/dist/cli/enrich.d.ts.map +1 -1
  4. package/dist/cli/enrich.js +38 -0
  5. package/dist/cli/enrich.js.map +1 -1
  6. package/dist/cli/main.d.ts.map +1 -1
  7. package/dist/cli/main.js +1 -0
  8. package/dist/cli/main.js.map +1 -1
  9. package/dist/data/index.d.ts.map +1 -1
  10. package/dist/data/index.js +13 -0
  11. package/dist/data/index.js.map +1 -1
  12. package/dist/enrich/checkpoint.d.ts +53 -0
  13. package/dist/enrich/checkpoint.d.ts.map +1 -0
  14. package/dist/enrich/checkpoint.js +296 -0
  15. package/dist/enrich/checkpoint.js.map +1 -0
  16. package/dist/enrich/index.d.ts +14 -0
  17. package/dist/enrich/index.d.ts.map +1 -1
  18. package/dist/enrich/index.js +3 -3
  19. package/dist/enrich/index.js.map +1 -1
  20. package/dist/ratings/paging.d.ts +16 -0
  21. package/dist/ratings/paging.d.ts.map +1 -0
  22. package/dist/ratings/paging.js +36 -0
  23. package/dist/ratings/paging.js.map +1 -0
  24. package/dist/ratings/provider.d.ts +1 -9
  25. package/dist/ratings/provider.d.ts.map +1 -1
  26. package/dist/ratings/provider.js +11 -10
  27. package/dist/ratings/provider.js.map +1 -1
  28. package/dist/ratings/provider_github.d.ts.map +1 -1
  29. package/dist/ratings/provider_github.js +2 -1
  30. package/dist/ratings/provider_github.js.map +1 -1
  31. package/dist/ratings/provider_gitlab.d.ts.map +1 -1
  32. package/dist/ratings/provider_gitlab.js +2 -1
  33. package/dist/ratings/provider_gitlab.js.map +1 -1
  34. package/dist/ratings/reconcile.d.ts.map +1 -1
  35. package/dist/ratings/reconcile.js +14 -4
  36. package/dist/ratings/reconcile.js.map +1 -1
  37. package/dist/renderer/astro/components/Catalog.js +3 -3
  38. package/dist/renderer/astro/components/Catalog.tsx +15 -9
  39. package/dist/renderer/astro/components/CommandField.astro +1 -0
  40. package/dist/renderer/astro/components/VersionMenu.astro +31 -23
  41. package/dist/renderer/astro/layouts/Base.astro +212 -264
  42. package/dist/renderer/astro/pages/p/[...slug].astro +99 -89
  43. package/dist/renderer/astro/styles/tokens.css +157 -0
  44. package/dist/validate/adapters/http.d.ts +23 -0
  45. package/dist/validate/adapters/http.d.ts.map +1 -1
  46. package/dist/validate/adapters/http.js +12 -1
  47. package/dist/validate/adapters/http.js.map +1 -1
  48. package/package.json +1 -1
  49. package/templates/ci/github-enrich.yml +9 -1
  50. package/templates/ci/gitlab-enrich.sh +10 -1
@@ -3,6 +3,10 @@
3
3
  // sheet. Everything in the global block sits in `@layer grimoire`, so a
4
4
  // user CSS file (unlayered) wins over any of it regardless of specificity
5
5
  // or injection order — that layer is the entire theming contract.
6
+ //
7
+ // The tokens themselves live in `../styles/tokens.css`, which declares the
8
+ // same layer. That file is the contract; this one only spends it.
9
+ import "../styles/tokens.css";
6
10
  import { Moon, Sun } from "lucide-preact";
7
11
  import { withBase } from "../lib/base";
8
12
  import { data } from "../lib/data";
@@ -119,9 +123,9 @@ function repoLabel(url: string): string {
119
123
  </script>
120
124
  </head>
121
125
  <body>
122
- <header>
126
+ <header data-slot="site-header">
123
127
  <div class="shell header-row">
124
- <a class="brand" href={withBase("/")}>
128
+ <a class="brand" href={withBase("/")} data-slot="brand">
125
129
  {/* Decorative: the brand text is right beside it, so announcing the
126
130
  logo too would read the index's name twice. */}
127
131
  {config.logo && <img class="brand-logo" src={withBase(config.logo)} alt="" />}
@@ -161,7 +165,7 @@ function repoLabel(url: string): string {
161
165
  <slot />
162
166
  </main>
163
167
 
164
- <footer>
168
+ <footer data-slot="site-footer">
165
169
  <div class="shell">
166
170
  <p>
167
171
  Raw data: <a href={allJson}><code>{allJson}</code></a>{
@@ -359,70 +363,7 @@ function repoLabel(url: string): string {
359
363
  </script>
360
364
 
361
365
  <style is:global>
362
- /* THE THEMING CONTRACT — these custom properties are the whole
363
- customization surface. There is no component-override API.
364
-
365
- Everything the renderer ships is layered. Unlayered CSS — i.e. any
366
- user override file — beats a layered declaration outright, so a
367
- single `:root { --accent: … }` wins in light AND dark without
368
- !important and without knowing where Astro injects its bundle.
369
- Redeclare under `[data-theme="dark"]` to differ per scheme.
370
-
371
- surface --bg --fg --card --border --muted --chip-bg
372
- accent --accent --accent-soft --on-accent
373
- kinds --kind-skill --kind-rule --kind-agent --kind-mcp
374
- --kind-bundle
375
- states --deprecated --banner-bg --banner-fg --banner-border
376
-
377
- Every one is declared in both schemes below; `color-scheme` rides
378
- along so form controls and scrollbars follow. Adding a token is
379
- additive, removing or renaming one is a breaking change. */
380
366
  @layer grimoire {
381
- :root {
382
- --bg: #f7f6f3;
383
- --fg: #1d1c1a;
384
- --muted: #6d6a63;
385
- --card: #ffffff;
386
- --border: #dedbd3;
387
- --accent: #6d4fc4;
388
- --accent-soft: #efeafd;
389
- --chip-bg: #edebe5;
390
- --on-accent: #ffffff;
391
- --kind-skill: #6d4fc4;
392
- --kind-rule: #1a7f6b;
393
- --kind-agent: #b0641a;
394
- --kind-mcp: #2565c7;
395
- --kind-bundle: #a63d68;
396
- /* ~5.7:1 on --card (white) */
397
- --deprecated: #9c5400;
398
- --banner-bg: #fff3cd;
399
- --banner-fg: #6b4c00;
400
- --banner-border: #e0b84c;
401
- color-scheme: light;
402
- }
403
- [data-theme="dark"] {
404
- --bg: #16151a;
405
- --fg: #e8e6e1;
406
- --muted: #98948b;
407
- --card: #201f26;
408
- --border: #35333d;
409
- --accent: #a58cf0;
410
- --accent-soft: #2c2540;
411
- --chip-bg: #2a2931;
412
- --on-accent: #ffffff;
413
- --kind-skill: #a58cf0;
414
- --kind-rule: #4cc2a9;
415
- --kind-agent: #e0a35c;
416
- --kind-mcp: #6fa8f5;
417
- --kind-bundle: #e07ba6;
418
- /* ~7.6:1 on --card (#201f26) */
419
- --deprecated: #e3a640;
420
- --banner-bg: #4a3b0a;
421
- --banner-fg: #f0d78c;
422
- --banner-border: #8a6d1a;
423
- color-scheme: dark;
424
- }
425
-
426
367
  * {
427
368
  box-sizing: border-box;
428
369
  }
@@ -431,8 +372,8 @@ function repoLabel(url: string): string {
431
372
  min-height: 100vh;
432
373
  display: flex;
433
374
  flex-direction: column;
434
- background: var(--bg);
435
- color: var(--fg);
375
+ background: var(--grim-color-bg);
376
+ color: var(--grim-color-fg);
436
377
  font-family:
437
378
  system-ui,
438
379
  -apple-system,
@@ -446,31 +387,31 @@ function repoLabel(url: string): string {
446
387
  }
447
388
  main.shell {
448
389
  flex: 1;
449
- padding-block: 1.5rem 3rem;
390
+ padding-block: var(--grim-space-7) var(--grim-space-9);
450
391
  }
451
392
  a {
452
- color: var(--accent);
393
+ color: var(--grim-color-accent);
453
394
  }
454
395
 
455
396
  header {
456
- border-bottom: 1px solid var(--border);
457
- background: var(--card);
397
+ border-bottom: var(--grim-border-width) solid var(--grim-color-border);
398
+ background: var(--grim-color-card);
458
399
  }
459
400
  .header-row {
460
401
  display: flex;
461
402
  align-items: center;
462
403
  justify-content: space-between;
463
- padding-block: 0.8rem;
464
- gap: 1rem;
404
+ padding-block: var(--grim-space-5);
405
+ gap: var(--grim-space-6);
465
406
  }
466
407
  .brand {
467
408
  display: inline-flex;
468
409
  align-items: center;
469
- gap: 0.55rem;
470
- color: var(--fg);
410
+ gap: var(--grim-space-4);
411
+ color: var(--grim-color-fg);
471
412
  text-decoration: none;
472
413
  font-weight: 600;
473
- font-size: 1.05rem;
414
+ font-size: var(--grim-text-lg);
474
415
  }
475
416
  /* Height-bound, width free: a wordmark and a square icon are both
476
417
  valid logos and neither should be squashed into the other's box. */
@@ -480,20 +421,20 @@ function repoLabel(url: string): string {
480
421
  max-width: 12rem;
481
422
  }
482
423
  .brand-mark {
483
- color: var(--accent);
424
+ color: var(--grim-color-accent);
484
425
  font-family: ui-monospace, "SFMono-Regular", monospace;
485
426
  }
486
427
  nav {
487
428
  display: flex;
488
429
  align-items: center;
489
- gap: 1rem;
430
+ gap: var(--grim-space-6);
490
431
  }
491
432
  nav a {
492
- color: var(--muted);
433
+ color: var(--grim-color-muted);
493
434
  text-decoration: none;
494
435
  }
495
436
  nav a:hover {
496
- color: var(--fg);
437
+ color: var(--grim-color-fg);
497
438
  }
498
439
  /* Borderless and colour-inheriting: same resting and hover colours as
499
440
  the nav links beside it, so the row reads as one set. */
@@ -503,11 +444,11 @@ function repoLabel(url: string): string {
503
444
  border: none;
504
445
  background: none;
505
446
  padding: 0;
506
- color: var(--muted);
447
+ color: var(--grim-color-muted);
507
448
  cursor: pointer;
508
449
  }
509
450
  #theme-toggle:hover {
510
- color: var(--fg);
451
+ color: var(--grim-color-fg);
511
452
  }
512
453
  [data-theme="dark"] .when-light,
513
454
  [data-theme="light"] .when-dark {
@@ -521,13 +462,13 @@ function repoLabel(url: string): string {
521
462
  display: grid;
522
463
  grid-template-columns: 1fr auto;
523
464
  align-items: start;
524
- gap: 0.6rem 2rem;
525
- margin-block: 1rem 1.25rem;
465
+ gap: var(--grim-space-4) var(--grim-space-8);
466
+ margin-block: var(--grim-space-6) var(--grim-space-7);
526
467
  }
527
468
  .hero h1 {
528
469
  grid-column: 1 / -1;
529
470
  margin: 0;
530
- font-size: 1.6rem;
471
+ font-size: var(--grim-text-2xl);
531
472
  }
532
473
  /* Label column, bar column. `minmax(0, …)` on the bars is what lets
533
474
  the commands scroll instead of widening the grid. */
@@ -535,11 +476,11 @@ function repoLabel(url: string): string {
535
476
  display: grid;
536
477
  grid-template-columns: auto minmax(0, 34rem);
537
478
  align-items: center;
538
- gap: 0.4rem 0.7rem;
479
+ gap: var(--grim-space-3) var(--grim-space-5);
539
480
  }
540
481
  .side-label {
541
- color: var(--muted);
542
- font-size: 0.72rem;
482
+ color: var(--grim-color-muted);
483
+ font-size: var(--grim-text-2xs);
543
484
  font-weight: 600;
544
485
  text-transform: uppercase;
545
486
  letter-spacing: 0.04em;
@@ -560,13 +501,15 @@ function repoLabel(url: string): string {
560
501
  }
561
502
  .hero p {
562
503
  margin: 0;
563
- color: var(--muted);
504
+ color: var(--grim-color-muted);
564
505
  max-width: 46rem;
565
506
  }
566
507
  .hero code {
567
- background: var(--chip-bg);
568
- border-radius: 4px;
569
- padding: 0.1rem 0.35rem;
508
+ background: var(--grim-color-chip-bg);
509
+ border-radius: var(--grim-radius-sm);
510
+ padding: var(--grim-space-1) var(--grim-space-3);
511
+ /* `em`, not a type token: inline code sizes against the prose it
512
+ sits in, so it must follow whatever that text is set at. */
570
513
  font-size: 0.9em;
571
514
  }
572
515
 
@@ -576,9 +519,9 @@ function repoLabel(url: string): string {
576
519
  display: flex;
577
520
  align-items: stretch;
578
521
  min-width: 0;
579
- background: var(--card);
580
- border: 1px solid var(--border);
581
- border-radius: 8px;
522
+ background: var(--grim-color-card);
523
+ border: var(--grim-border-width) solid var(--grim-color-border);
524
+ border-radius: var(--grim-radius-lg);
582
525
  }
583
526
  /* No `overflow: hidden` — that would clip the platform menu. The end
584
527
  segments round themselves instead (8px border box, 1px border).
@@ -601,10 +544,10 @@ function repoLabel(url: string): string {
601
544
  cursor: pointer;
602
545
  }
603
546
  .cmd-field:hover {
604
- background: var(--chip-bg);
547
+ background: var(--grim-color-chip-bg);
605
548
  }
606
549
  .cmd-field:focus-visible {
607
- outline: 2px solid var(--accent);
550
+ outline: 2px solid var(--grim-color-accent);
608
551
  outline-offset: -2px;
609
552
  }
610
553
  .cmd-field code {
@@ -614,8 +557,9 @@ function repoLabel(url: string): string {
614
557
  border-radius: 0;
615
558
  /* Right padding is the icon's lane — the text scrolls under the
616
559
  fade rather than up against the glyph. */
617
- padding: 0.4rem 2.1rem 0.4rem 0.7rem;
618
- font-size: 0.85rem;
560
+ padding: var(--grim-space-3) 2.1rem var(--grim-space-3) var(--grim-space-5);
561
+ /* 2.1rem is the glyph lane's own width, not a rhythm step. */
562
+ font-size: var(--grim-text-sm);
619
563
  white-space: nowrap;
620
564
  overflow-x: auto;
621
565
  /* Scrollable, no bar: the bar is the height of the control and
@@ -642,19 +586,19 @@ function repoLabel(url: string): string {
642
586
  right: 0.6rem;
643
587
  display: grid;
644
588
  place-items: center;
645
- color: var(--muted);
589
+ color: var(--grim-color-muted);
646
590
  }
647
591
  .cmd-icons > * {
648
592
  grid-area: 1 / 1;
649
- transition: opacity 0.18s ease;
593
+ transition: opacity var(--grim-duration-slow) ease;
650
594
  }
651
595
  .cmd-icons .icon-done {
652
596
  opacity: 0;
653
- color: var(--kind-rule);
597
+ color: var(--grim-color-kind-rule);
654
598
  }
655
599
  .cmd-field:hover .cmd-icons,
656
600
  .cmd-field:focus-visible .cmd-icons {
657
- color: var(--fg);
601
+ color: var(--grim-color-fg);
658
602
  }
659
603
  .cmd-field.copied .icon-idle {
660
604
  opacity: 0;
@@ -675,11 +619,11 @@ function repoLabel(url: string): string {
675
619
  display: inline-flex;
676
620
  align-items: center;
677
621
  border: none;
678
- border-left: 1px solid var(--border);
622
+ border-left: var(--grim-border-width) solid var(--grim-color-border);
679
623
  border-radius: 0;
680
624
  background: none;
681
- padding: 0 0.5rem;
682
- color: var(--muted);
625
+ padding: 0 var(--grim-space-4);
626
+ color: var(--grim-color-muted);
683
627
  text-decoration: none;
684
628
  cursor: pointer;
685
629
  }
@@ -693,11 +637,11 @@ function repoLabel(url: string): string {
693
637
  .os-menu > summary {
694
638
  display: inline-flex;
695
639
  align-items: center;
696
- gap: 0.1rem;
697
- padding: 0 0.45rem;
698
- color: var(--muted);
640
+ gap: var(--grim-space-1);
641
+ padding: 0 var(--grim-space-4);
642
+ color: var(--grim-color-muted);
699
643
  cursor: pointer;
700
- border-right: 1px solid var(--border);
644
+ border-right: var(--grim-border-width) solid var(--grim-color-border);
701
645
  /* Both spellings: the default triangle is a marker in Firefox and
702
646
  a `::-webkit-details-marker` pseudo-element in older WebKit. */
703
647
  list-style: none;
@@ -708,8 +652,8 @@ function repoLabel(url: string): string {
708
652
  .os-menu > summary:hover,
709
653
  .os-menu > summary:focus-visible,
710
654
  .os-menu[open] > summary {
711
- background: var(--chip-bg);
712
- color: var(--fg);
655
+ background: var(--grim-color-chip-bg);
656
+ color: var(--grim-color-fg);
713
657
  }
714
658
  .os-glyph {
715
659
  display: inline-flex;
@@ -729,41 +673,41 @@ function repoLabel(url: string): string {
729
673
  z-index: 5;
730
674
  min-width: 9rem;
731
675
  margin: 0;
732
- padding: 0.25rem;
676
+ padding: var(--grim-space-2);
733
677
  list-style: none;
734
- background: var(--card);
735
- border: 1px solid var(--border);
736
- border-radius: 8px;
737
- box-shadow: 0 6px 20px rgb(0 0 0 / 18%);
678
+ background: var(--grim-color-card);
679
+ border: var(--grim-border-width) solid var(--grim-color-border);
680
+ border-radius: var(--grim-radius-lg);
681
+ box-shadow: var(--grim-shadow-raised);
738
682
  }
739
683
  .os-menu li button {
740
684
  display: flex;
741
685
  align-items: center;
742
- gap: 0.5rem;
686
+ gap: var(--grim-space-4);
743
687
  width: 100%;
744
688
  border: none;
745
- border-radius: 6px;
689
+ border-radius: var(--grim-radius-md);
746
690
  background: none;
747
- padding: 0.35rem 0.5rem;
748
- color: var(--fg);
691
+ padding: var(--grim-space-3) var(--grim-space-4);
692
+ color: var(--grim-color-fg);
749
693
  font: inherit;
750
- font-size: 0.85rem;
694
+ font-size: var(--grim-text-sm);
751
695
  text-align: left;
752
696
  cursor: pointer;
753
697
  }
754
698
  .os-menu li button:hover,
755
699
  .os-menu li button:focus-visible {
756
- background: var(--chip-bg);
700
+ background: var(--grim-color-chip-bg);
757
701
  }
758
702
  .os-menu li button[aria-checked="true"] {
759
- color: var(--accent);
703
+ color: var(--grim-color-accent);
760
704
  }
761
705
  /* Borderless segments need a different hover than the pills do — the
762
706
  border they would have tinted is not theirs any more. */
763
707
  .cmd-bar .seg:hover,
764
708
  .cmd-bar .seg:focus-visible {
765
- background: var(--chip-bg);
766
- color: var(--fg);
709
+ background: var(--grim-color-chip-bg);
710
+ color: var(--grim-color-fg);
767
711
  }
768
712
 
769
713
  /* The bar's end rounding, last so it wins.
@@ -776,12 +720,12 @@ function repoLabel(url: string): string {
776
720
  The summary is named explicitly rather than left to inherit. */
777
721
  .cmd-bar > :first-child,
778
722
  .cmd-bar > :first-child > summary {
779
- border-start-start-radius: 7px;
780
- border-end-start-radius: 7px;
723
+ border-start-start-radius: calc(var(--grim-radius-lg) - var(--grim-border-width));
724
+ border-end-start-radius: calc(var(--grim-radius-lg) - var(--grim-border-width));
781
725
  }
782
726
  .cmd-bar > :last-child {
783
- border-start-end-radius: 7px;
784
- border-end-end-radius: 7px;
727
+ border-start-end-radius: calc(var(--grim-radius-lg) - var(--grim-border-width));
728
+ border-end-end-radius: calc(var(--grim-radius-lg) - var(--grim-border-width));
785
729
  }
786
730
 
787
731
  /* Attribution sits opposite the raw-data line, on the same row where
@@ -791,7 +735,7 @@ function repoLabel(url: string): string {
791
735
  flex-wrap: wrap;
792
736
  justify-content: space-between;
793
737
  align-items: baseline;
794
- gap: 0.35rem 1rem;
738
+ gap: var(--grim-space-3) var(--grim-space-6);
795
739
  }
796
740
  .attribution {
797
741
  margin: 0;
@@ -799,7 +743,7 @@ function repoLabel(url: string): string {
799
743
  text-align: end;
800
744
  }
801
745
  .attribution span[aria-hidden] {
802
- color: var(--accent);
746
+ color: var(--grim-color-accent);
803
747
  }
804
748
  /* Sits between the raw-data line and the attribution, which keeps its
805
749
  `margin-inline-start: auto` and so stays pinned to the end. */
@@ -807,7 +751,7 @@ function repoLabel(url: string): string {
807
751
  margin: 0;
808
752
  display: flex;
809
753
  flex-wrap: wrap;
810
- gap: 0.35rem 1rem;
754
+ gap: var(--grim-space-3) var(--grim-space-6);
811
755
  }
812
756
 
813
757
  /* Copy toast. Fixed and centred at the bottom: a card's three copy
@@ -821,36 +765,36 @@ function repoLabel(url: string): string {
821
765
  bottom: 1.25rem;
822
766
  z-index: 20;
823
767
  display: grid;
824
- gap: 0.15rem;
768
+ gap: var(--grim-space-1);
825
769
  max-width: min(30rem, calc(100vw - 2rem));
826
- padding: 0.5rem 0.85rem;
827
- background: var(--card);
828
- border: 1px solid var(--border);
829
- border-radius: 10px;
830
- box-shadow: 0 8px 24px rgb(0 0 0 / 18%);
770
+ padding: var(--grim-space-4) var(--grim-space-5);
771
+ background: var(--grim-color-card);
772
+ border: var(--grim-border-width) solid var(--grim-color-border);
773
+ border-radius: var(--grim-radius-xl);
774
+ box-shadow: var(--grim-shadow-overlay);
831
775
  /* Out of the layout and unhittable until shown, so it never eats a
832
776
  click aimed at whatever is beneath it. */
833
777
  pointer-events: none;
834
778
  opacity: 0;
835
779
  transform: translate(-50%, 0.5rem);
836
780
  transition:
837
- opacity 160ms ease,
838
- transform 160ms ease;
781
+ opacity var(--grim-duration-base) ease,
782
+ transform var(--grim-duration-base) ease;
839
783
  }
840
784
  #copy-toast.show {
841
785
  opacity: 1;
842
786
  transform: translate(-50%, 0);
843
787
  }
844
788
  #copy-toast .toast-name {
845
- font-size: 0.8rem;
789
+ font-size: var(--grim-text-sm);
846
790
  font-weight: 600;
847
- color: var(--fg);
791
+ color: var(--grim-color-fg);
848
792
  }
849
793
  /* The exact string, one line, clipped rather than wrapped — a long
850
794
  install one-liner must not grow the toast into the page. */
851
795
  #copy-toast .toast-value {
852
- font-size: 0.78rem;
853
- color: var(--muted);
796
+ font-size: var(--grim-text-xs);
797
+ color: var(--grim-color-muted);
854
798
  white-space: nowrap;
855
799
  overflow: hidden;
856
800
  text-overflow: ellipsis;
@@ -877,8 +821,8 @@ function repoLabel(url: string): string {
877
821
  display: flex;
878
822
  flex-wrap: wrap;
879
823
  align-items: center;
880
- gap: 0.75rem;
881
- margin-bottom: 1.25rem;
824
+ gap: var(--grim-space-5);
825
+ margin-bottom: var(--grim-space-7);
882
826
  }
883
827
  /* Full-width basis in a wrapping row: the search bar takes a line to
884
828
  itself and pushes both chip groups onto the next one, which then
@@ -895,18 +839,19 @@ function repoLabel(url: string): string {
895
839
  }
896
840
  .controls input[type="search"] {
897
841
  flex: 1;
898
- padding: 0.55rem 0.8rem;
842
+ padding: var(--grim-space-4) var(--grim-space-5);
899
843
  /* Room for the key hint, so a long query never runs under it. */
844
+ /* 2.4rem is the hint's measured width, not a rhythm step. */
900
845
  padding-right: 2.4rem;
901
- border: 1px solid var(--border);
902
- border-radius: 8px;
903
- background: var(--card);
904
- color: var(--fg);
905
- font-size: 0.95rem;
846
+ border: var(--grim-border-width) solid var(--grim-color-border);
847
+ border-radius: var(--grim-radius-lg);
848
+ background: var(--grim-color-card);
849
+ color: var(--grim-color-fg);
850
+ font-size: var(--grim-text-md);
906
851
  min-width: 0;
907
852
  }
908
853
  .controls input[type="search"]:focus-visible {
909
- outline: 2px solid var(--accent);
854
+ outline: 2px solid var(--grim-color-accent);
910
855
  outline-offset: 1px;
911
856
  }
912
857
  /* The `/` shortcut, shown as the key it is. It is a hint for a field
@@ -919,15 +864,15 @@ function repoLabel(url: string): string {
919
864
  top: 50%;
920
865
  translate: 0 -50%;
921
866
  pointer-events: none;
922
- border: 1px solid var(--border);
867
+ border: var(--grim-border-width) solid var(--grim-color-border);
923
868
  border-bottom-width: 2px;
924
- border-radius: 5px;
925
- background: var(--chip-bg);
926
- color: var(--muted);
869
+ border-radius: var(--grim-radius-md);
870
+ background: var(--grim-color-chip-bg);
871
+ color: var(--grim-color-muted);
927
872
  font-family: ui-monospace, "SFMono-Regular", monospace;
928
- font-size: 0.72rem;
873
+ font-size: var(--grim-text-2xs);
929
874
  line-height: 1;
930
- padding: 0.2rem 0.4rem;
875
+ padding: var(--grim-space-2) var(--grim-space-3);
931
876
  }
932
877
  .search-field:focus-within .search-hint,
933
878
  .search-field:has(input:not(:placeholder-shown)) .search-hint {
@@ -936,7 +881,7 @@ function repoLabel(url: string): string {
936
881
  .chips {
937
882
  display: flex;
938
883
  flex-wrap: wrap;
939
- gap: 0.4rem;
884
+ gap: var(--grim-space-3);
940
885
  }
941
886
  /* A drawn rule rather than a "|" glyph: its height is the chip row's,
942
887
  not whatever the font gives a pipe. `stretch` overrides the
@@ -944,7 +889,7 @@ function repoLabel(url: string): string {
944
889
  .chip-sep {
945
890
  align-self: stretch;
946
891
  width: 1px;
947
- background: var(--border);
892
+ background: var(--grim-color-border);
948
893
  }
949
894
  /* Held at the far end of the chip row: it answers a different
950
895
  question from sort and kind — what the catalog is withholding,
@@ -956,30 +901,30 @@ function repoLabel(url: string): string {
956
901
  accent, so "deprecated entries are in view" is signalled by the
957
902
  same colour the badges on those entries carry. */
958
903
  .chip.deprecated-toggle.active {
959
- color: var(--deprecated);
960
- border-color: var(--deprecated);
961
- background: var(--chip-bg);
904
+ color: var(--grim-color-deprecated);
905
+ border-color: var(--grim-color-deprecated);
906
+ background: var(--grim-color-chip-bg);
962
907
  }
963
908
  .chip {
964
- border: 1px solid var(--border);
965
- background: var(--chip-bg);
966
- color: var(--fg);
967
- border-radius: 999px;
968
- padding: 0.25rem 0.7rem;
969
- font-size: 0.85rem;
970
- transition: border-color 150ms ease;
909
+ border: var(--grim-border-width) solid var(--grim-color-border);
910
+ background: var(--grim-color-chip-bg);
911
+ color: var(--grim-color-fg);
912
+ border-radius: var(--grim-radius-pill);
913
+ padding: var(--grim-space-2) var(--grim-space-5);
914
+ font-size: var(--grim-text-sm);
915
+ transition: border-color var(--grim-duration-base) ease;
971
916
  cursor: pointer;
972
917
  }
973
918
  .chip small {
974
- color: var(--muted);
919
+ color: var(--grim-color-muted);
975
920
  }
976
921
  /* button-only: the "+N" overflow chip is a span and stays inert */
977
922
  button.chip:hover {
978
- border-color: var(--accent);
923
+ border-color: var(--grim-color-accent);
979
924
  }
980
925
  .chip.active {
981
- border-color: var(--accent);
982
- background: var(--accent-soft);
926
+ border-color: var(--grim-color-accent);
927
+ background: var(--grim-color-accent-soft);
983
928
  }
984
929
 
985
930
  .grid {
@@ -988,28 +933,28 @@ function repoLabel(url: string): string {
988
933
  padding: 0;
989
934
  display: grid;
990
935
  grid-template-columns: repeat(auto-fill, minmax(19rem, 1fr));
991
- gap: 1rem;
936
+ gap: var(--grim-space-6);
992
937
  }
993
938
  .card {
994
939
  display: flex;
995
940
  flex-direction: column;
996
- gap: 0.35rem;
997
- background: var(--card);
998
- border: 1px solid var(--border);
999
- border-radius: 10px;
1000
- padding: 1rem 1.1rem;
941
+ gap: var(--grim-space-3);
942
+ background: var(--grim-color-card);
943
+ border: var(--grim-border-width) solid var(--grim-color-border);
944
+ border-radius: var(--grim-radius-xl);
945
+ padding: var(--grim-space-6) var(--grim-space-6);
1001
946
  /* Whole card navigates to the detail page via the stretched title
1002
947
  link below; real controls inside re-stack above the overlay. */
1003
948
  position: relative;
1004
949
  cursor: pointer;
1005
- transition: border-color 150ms ease;
950
+ transition: border-color var(--grim-duration-base) ease;
1006
951
  }
1007
952
  /* Card highlight yields while an inner control is hovered, so its
1008
953
  own hover state reads as the click target instead. */
1009
954
  .card:hover:not(
1010
955
  :has(.keywords :hover, .copy-group :hover, .source:hover)
1011
956
  ) {
1012
- border-color: var(--accent);
957
+ border-color: var(--grim-color-accent);
1013
958
  }
1014
959
  /* Keyboard focus wears the hover treatment rather than an outline on
1015
960
  top of it — one affordance, whichever way the card was reached.
@@ -1017,7 +962,7 @@ function repoLabel(url: string): string {
1017
962
  is the part that may not be dropped. */
1018
963
  .card:focus-visible {
1019
964
  outline: none;
1020
- border-color: var(--accent);
965
+ border-color: var(--grim-color-accent);
1021
966
  }
1022
967
  .card h2 a::after {
1023
968
  content: "";
@@ -1032,13 +977,13 @@ function repoLabel(url: string): string {
1032
977
  .card-head {
1033
978
  display: flex;
1034
979
  align-items: center;
1035
- gap: 0.6rem;
980
+ gap: var(--grim-space-4);
1036
981
  }
1037
982
  .card h2 {
1038
983
  flex: 1;
1039
984
  min-width: 0;
1040
985
  margin: 0;
1041
- font-size: 1.05rem;
986
+ font-size: var(--grim-text-lg);
1042
987
  font-family: ui-monospace, "SFMono-Regular", monospace;
1043
988
  word-break: break-word;
1044
989
  }
@@ -1050,19 +995,19 @@ function repoLabel(url: string): string {
1050
995
  flex-shrink: 0;
1051
996
  width: 28px;
1052
997
  height: 28px;
1053
- border-radius: 6px;
998
+ border-radius: var(--grim-radius-md);
1054
999
  }
1055
1000
  img.card-logo {
1056
1001
  object-fit: contain;
1057
- background: var(--chip-bg);
1002
+ background: var(--grim-color-chip-bg);
1058
1003
  }
1059
1004
  .card-logo-fallback {
1060
1005
  display: flex;
1061
1006
  align-items: center;
1062
1007
  justify-content: center;
1063
- color: var(--on-accent);
1008
+ color: var(--grim-color-on-accent);
1064
1009
  font-weight: 700;
1065
- font-size: 0.85rem;
1010
+ font-size: var(--grim-text-sm);
1066
1011
  font-family: ui-monospace, "SFMono-Regular", monospace;
1067
1012
  }
1068
1013
  /* THE LOGO SLOT — one box, three states, no layout shift.
@@ -1085,12 +1030,12 @@ function repoLabel(url: string): string {
1085
1030
  align-items: center;
1086
1031
  justify-content: center;
1087
1032
  overflow: hidden;
1088
- background: var(--chip-bg);
1089
- color: var(--muted);
1033
+ background: var(--grim-color-chip-bg);
1034
+ color: var(--grim-color-muted);
1090
1035
  }
1091
1036
  .logo-slot .logo-mark,
1092
1037
  .logo-slot img {
1093
- transition: opacity 200ms ease;
1038
+ transition: opacity var(--grim-duration-slow) ease;
1094
1039
  }
1095
1040
  .logo-slot .logo-mark {
1096
1041
  width: 60%;
@@ -1119,7 +1064,7 @@ function repoLabel(url: string): string {
1119
1064
  display: none;
1120
1065
  }
1121
1066
  .logo-slot[data-state="broken"] {
1122
- border: 1px dashed var(--border);
1067
+ border: var(--grim-border-width) dashed var(--grim-color-border);
1123
1068
  }
1124
1069
  @media (prefers-reduced-motion: reduce) {
1125
1070
  .logo-slot .logo-mark,
@@ -1129,54 +1074,57 @@ function repoLabel(url: string): string {
1129
1074
  }
1130
1075
  .badge {
1131
1076
  flex-shrink: 0;
1132
- font-size: 0.72rem;
1077
+ font-size: var(--grim-text-2xs);
1133
1078
  font-weight: 600;
1134
1079
  text-transform: uppercase;
1135
1080
  letter-spacing: 0.04em;
1136
- border: 1px solid currentColor;
1137
- border-radius: 999px;
1138
- padding: 0.05rem 0.5rem;
1139
- color: var(--muted);
1081
+ border: var(--grim-border-width) solid currentColor;
1082
+ border-radius: var(--grim-radius-pill);
1083
+ /* Optical: below `--grim-space-1`, tuned so the pill hugs its text.
1084
+ A rhythm step here visibly grows the pill. */
1085
+ padding: 0.05rem var(--grim-space-4);
1086
+ color: var(--grim-color-muted);
1140
1087
  }
1141
1088
  .kind-skill {
1142
- color: var(--kind-skill);
1089
+ color: var(--grim-color-kind-skill);
1143
1090
  }
1144
1091
  .kind-rule {
1145
- color: var(--kind-rule);
1092
+ color: var(--grim-color-kind-rule);
1146
1093
  }
1147
1094
  .kind-agent {
1148
- color: var(--kind-agent);
1095
+ color: var(--grim-color-kind-agent);
1149
1096
  }
1150
1097
  .kind-mcp {
1151
- color: var(--kind-mcp);
1098
+ color: var(--grim-color-kind-mcp);
1152
1099
  }
1153
1100
  .kind-bundle {
1154
- color: var(--kind-bundle);
1101
+ color: var(--grim-color-kind-bundle);
1155
1102
  }
1156
1103
  .badge.deprecated {
1157
- color: var(--deprecated);
1104
+ color: var(--grim-color-deprecated);
1158
1105
  }
1159
1106
  .chip[class*="kind-"] {
1160
- color: var(--fg);
1107
+ color: var(--grim-color-fg);
1161
1108
  }
1162
1109
  .namespace {
1163
1110
  margin: 0;
1164
- color: var(--muted);
1165
- font-size: 0.82rem;
1111
+ color: var(--grim-color-muted);
1112
+ font-size: var(--grim-text-sm);
1166
1113
  font-family: ui-monospace, "SFMono-Regular", monospace;
1167
1114
  }
1168
1115
  .meta-row {
1169
1116
  display: flex;
1170
1117
  flex-wrap: wrap;
1171
1118
  align-items: center;
1172
- gap: 0.4rem;
1119
+ gap: var(--grim-space-3);
1173
1120
  }
1174
1121
  .pill {
1175
- font-size: 0.78rem;
1176
- color: var(--muted);
1177
- border: 1px solid var(--border);
1178
- border-radius: 999px;
1179
- padding: 0.03rem 0.5rem;
1122
+ font-size: var(--grim-text-xs);
1123
+ color: var(--grim-color-muted);
1124
+ border: var(--grim-border-width) solid var(--grim-color-border);
1125
+ border-radius: var(--grim-radius-pill);
1126
+ /* Optical, as above — the smallest badge in the UI. */
1127
+ padding: 0.03rem var(--grim-space-4);
1180
1128
  }
1181
1129
  .pill.version {
1182
1130
  font-family: ui-monospace, "SFMono-Regular", monospace;
@@ -1186,22 +1134,22 @@ function repoLabel(url: string): string {
1186
1134
  .pill.rating {
1187
1135
  display: inline-flex;
1188
1136
  align-items: center;
1189
- gap: 0.15rem;
1137
+ gap: var(--grim-space-1);
1190
1138
  }
1191
1139
  .updated {
1192
- font-size: 0.78rem;
1193
- color: var(--muted);
1140
+ font-size: var(--grim-text-xs);
1141
+ color: var(--grim-color-muted);
1194
1142
  }
1195
1143
  .deprecated-strip {
1196
1144
  margin: 0;
1197
- font-size: 0.82rem;
1198
- color: var(--deprecated);
1145
+ font-size: var(--grim-text-sm);
1146
+ color: var(--grim-color-deprecated);
1199
1147
  }
1200
1148
  /* Long descriptions would stretch their whole grid row; clamp to 3
1201
1149
  lines so cards stay uniform. Full text lives on the detail page. */
1202
1150
  .description {
1203
1151
  margin: 0;
1204
- font-size: 0.92rem;
1152
+ font-size: var(--grim-text-md);
1205
1153
  /* `auto` basis, not `0`: overflow:hidden drops the min-height:auto
1206
1154
  floor, so a 0-basis item can collapse in an auto-height column. */
1207
1155
  flex: 1 1 auto;
@@ -1214,12 +1162,12 @@ function repoLabel(url: string): string {
1214
1162
  .keywords {
1215
1163
  display: flex;
1216
1164
  flex-wrap: wrap;
1217
- gap: 0.3rem;
1165
+ gap: var(--grim-space-2);
1218
1166
  }
1219
1167
  .chip.keyword {
1220
- font-size: 0.72rem;
1221
- padding: 0.1rem 0.5rem;
1222
- color: var(--muted);
1168
+ font-size: var(--grim-text-2xs);
1169
+ padding: var(--grim-space-1) var(--grim-space-4);
1170
+ color: var(--grim-color-muted);
1223
1171
  }
1224
1172
  .chip.keyword.overflow {
1225
1173
  cursor: default;
@@ -1228,40 +1176,40 @@ function repoLabel(url: string): string {
1228
1176
  display: flex;
1229
1177
  align-items: center;
1230
1178
  justify-content: space-between;
1231
- gap: 0.6rem;
1232
- margin-top: 0.5rem;
1179
+ gap: var(--grim-space-4);
1180
+ margin-top: var(--grim-space-4);
1233
1181
  }
1234
1182
  .copy-group {
1235
1183
  display: flex;
1236
- gap: 0.4rem;
1184
+ gap: var(--grim-space-3);
1237
1185
  flex-wrap: wrap;
1238
1186
  }
1239
1187
  .copy {
1240
1188
  display: inline-flex;
1241
1189
  align-items: center;
1242
- gap: 0.32rem;
1243
- transition: border-color 150ms ease;
1244
- border: 1px solid var(--border);
1245
- background: var(--chip-bg);
1246
- color: var(--fg);
1247
- border-radius: 6px;
1248
- padding: 0.28rem 0.55rem;
1249
- font-size: 0.8rem;
1190
+ gap: var(--grim-space-3);
1191
+ transition: border-color var(--grim-duration-base) ease;
1192
+ border: var(--grim-border-width) solid var(--grim-color-border);
1193
+ background: var(--grim-color-chip-bg);
1194
+ color: var(--grim-color-fg);
1195
+ border-radius: var(--grim-radius-md);
1196
+ padding: var(--grim-space-2) var(--grim-space-4);
1197
+ font-size: var(--grim-text-sm);
1250
1198
  font-family: ui-monospace, "SFMono-Regular", monospace;
1251
1199
  cursor: pointer;
1252
1200
  }
1253
1201
  .copy:hover {
1254
- border-color: var(--accent);
1202
+ border-color: var(--grim-color-accent);
1255
1203
  }
1256
1204
  .copy.copied {
1257
- color: var(--kind-rule);
1258
- border-color: var(--kind-rule);
1205
+ color: var(--grim-color-kind-rule);
1206
+ border-color: var(--grim-color-kind-rule);
1259
1207
  }
1260
1208
  .sr-only {
1261
1209
  position: absolute;
1262
1210
  width: 1px;
1263
1211
  height: 1px;
1264
- margin: -1px;
1212
+ margin: calc(-1 * var(--grim-border-width));
1265
1213
  padding: 0;
1266
1214
  border: 0;
1267
1215
  overflow: hidden;
@@ -1274,22 +1222,22 @@ function repoLabel(url: string): string {
1274
1222
  corners are the same ones every other panel uses. */
1275
1223
  .code-block {
1276
1224
  position: relative;
1277
- margin: 1rem 0;
1225
+ margin: var(--grim-space-6) 0;
1278
1226
  }
1279
1227
  .astro-code {
1280
1228
  margin: 0;
1281
- padding: 0.9rem 1rem;
1282
- border: 1px solid var(--border);
1283
- border-radius: 8px;
1229
+ padding: var(--grim-space-6) var(--grim-space-6);
1230
+ border: var(--grim-border-width) solid var(--grim-color-border);
1231
+ border-radius: var(--grim-radius-lg);
1284
1232
  overflow-x: auto;
1285
- font-size: 0.85rem;
1233
+ font-size: var(--grim-text-sm);
1286
1234
  line-height: 1.5;
1287
1235
  tab-size: 2;
1288
1236
  /* Shiki colours tokens; the surface is ours. Its own background is
1289
1237
  the theme's editor chrome — GitHub's blue-grey `#24292e` — which
1290
1238
  next to this page's purple-tinted card reads as a green cast.
1291
1239
  `!important` because Shiki writes it as an inline style. */
1292
- background-color: var(--chip-bg) !important;
1240
+ background-color: var(--grim-color-chip-bg) !important;
1293
1241
  }
1294
1242
  /* The dark half of the pair. Shiki writes the light colour inline and
1295
1243
  the dark one as a custom property on the same token, so switching
@@ -1318,28 +1266,28 @@ function repoLabel(url: string): string {
1318
1266
  width: 1.9rem;
1319
1267
  height: 1.9rem;
1320
1268
  padding: 0;
1321
- border: 1px solid var(--border);
1322
- border-radius: 6px;
1323
- background: var(--card);
1324
- color: var(--muted);
1269
+ border: var(--grim-border-width) solid var(--grim-color-border);
1270
+ border-radius: var(--grim-radius-md);
1271
+ background: var(--grim-color-card);
1272
+ color: var(--grim-color-muted);
1325
1273
  cursor: pointer;
1326
1274
  opacity: 0;
1327
1275
  transition:
1328
- opacity 120ms ease,
1329
- color 120ms ease,
1330
- border-color 120ms ease;
1276
+ opacity var(--grim-duration-fast) ease,
1277
+ color var(--grim-duration-fast) ease,
1278
+ border-color var(--grim-duration-fast) ease;
1331
1279
  }
1332
1280
  .code-block:hover .code-copy,
1333
1281
  .code-copy:focus-visible {
1334
1282
  opacity: 1;
1335
1283
  }
1336
1284
  .code-copy:hover {
1337
- color: var(--accent);
1338
- border-color: var(--accent);
1285
+ color: var(--grim-color-accent);
1286
+ border-color: var(--grim-color-accent);
1339
1287
  }
1340
1288
  .code-copy.copied {
1341
- color: var(--kind-rule);
1342
- border-color: var(--kind-rule);
1289
+ color: var(--grim-color-kind-rule);
1290
+ border-color: var(--grim-color-kind-rule);
1343
1291
  opacity: 1;
1344
1292
  }
1345
1293
  @media (prefers-reduced-motion: reduce) {
@@ -1358,20 +1306,20 @@ function repoLabel(url: string): string {
1358
1306
  text-decoration: none;
1359
1307
  }
1360
1308
  .source {
1361
- font-size: 0.85rem;
1309
+ font-size: var(--grim-text-sm);
1362
1310
  white-space: nowrap;
1363
1311
  }
1364
1312
  .empty {
1365
- color: var(--muted);
1313
+ color: var(--grim-color-muted);
1366
1314
  }
1367
1315
 
1368
1316
  footer {
1369
- border-top: 1px solid var(--border);
1370
- color: var(--muted);
1371
- font-size: 0.85rem;
1317
+ border-top: var(--grim-border-width) solid var(--grim-color-border);
1318
+ color: var(--grim-color-muted);
1319
+ font-size: var(--grim-text-sm);
1372
1320
  }
1373
1321
  footer p {
1374
- margin: 0.8rem 0;
1322
+ margin: var(--grim-space-5) 0;
1375
1323
  }
1376
1324
  footer a {
1377
1325
  color: inherit;