@crewlethq/ui 0.4.4 → 0.5.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.
Files changed (231) hide show
  1. package/README.md +888 -24
  2. package/dist/Accordion/index.js +2 -2
  3. package/dist/AddPill/index.js +1 -1
  4. package/dist/{AddPill-DFWXYLIQ.css → AddPill-IJQYCY6C.css} +9 -0
  5. package/dist/AppShell/AppShell.d.ts +26 -5
  6. package/dist/AppShell/index.js +3 -3
  7. package/dist/{AppShell-NVE6LHNI.css → AppShell-XARELGIH.css} +178 -25
  8. package/dist/Avatar/Avatar.d.ts +85 -40
  9. package/dist/Avatar/AvatarStack.d.ts +76 -0
  10. package/dist/Avatar/index.d.ts +5 -2
  11. package/dist/Avatar/index.js +1 -1
  12. package/dist/Avatar-XID7Z74C.css +200 -0
  13. package/dist/AvatarStack-GEJBNV7E.css +72 -0
  14. package/dist/BrandLockup/index.js +1 -1
  15. package/dist/{BrandLockup-6ISDEHPJ.css → BrandLockup-JKGXFCZF.css} +25 -19
  16. package/dist/Button/Button.d.ts +7 -2
  17. package/dist/Button/index.js +1 -1
  18. package/dist/{Button-D4J6B4MA.css → Button-X4B2TJAQ.css} +50 -19
  19. package/dist/Callout/index.js +1 -1
  20. package/dist/Canvas/index.js +4 -4
  21. package/dist/Card/Card.d.ts +9 -5
  22. package/dist/Card/index.js +1 -1
  23. package/dist/{Card-RLR254LD.css → Card-GLP7SUV6.css} +25 -18
  24. package/dist/Charts/BarList.d.ts +18 -1
  25. package/dist/Charts/ChartTooltip.d.ts +68 -0
  26. package/dist/Charts/StackedBar.d.ts +25 -7
  27. package/dist/Charts/StackedColumns.d.ts +112 -0
  28. package/dist/Charts/TimeSeries.d.ts +33 -2
  29. package/dist/Charts/dataColor.d.ts +22 -14
  30. package/dist/Charts/index.d.ts +6 -0
  31. package/dist/Charts/index.js +1 -1
  32. package/dist/Charts/useChartHover.d.ts +56 -0
  33. package/dist/Charts-B3YEF7R4.css +742 -0
  34. package/dist/Checkbox/index.js +1 -1
  35. package/dist/{Checkbox-VGW26YLQ.css → Checkbox-BOXQ747I.css} +2 -2
  36. package/dist/CodeBlock/index.js +4 -4
  37. package/dist/Combobox/index.js +5 -5
  38. package/dist/CommandPalette/CommandPalette.d.ts +97 -6
  39. package/dist/CommandPalette/index.d.ts +1 -1
  40. package/dist/CommandPalette/index.js +9 -7
  41. package/dist/CommandPalette-C5AMKGN2.css +259 -0
  42. package/dist/Copyable/index.js +3 -3
  43. package/dist/DataTable/index.js +7 -7
  44. package/dist/{DataTable-37UWTRN6.css → DataTable-OLHPF7D4.css} +35 -38
  45. package/dist/DataView/index.js +15 -15
  46. package/dist/{DataView-256YF32J.css → DataView-N6JX464S.css} +5 -4
  47. package/dist/DateTimePicker/index.js +5 -5
  48. package/dist/DiffList/index.js +1 -1
  49. package/dist/Disclosure/index.js +2 -2
  50. package/dist/EntityChip/EntityChip.d.ts +9 -12
  51. package/dist/EntityChip/index.d.ts +1 -1
  52. package/dist/EntityChip/index.js +2 -2
  53. package/dist/ErrorBoundary/index.js +2 -2
  54. package/dist/{ErrorBoundary-ME36CQTA.css → ErrorBoundary-U2PA3LY2.css} +4 -4
  55. package/dist/IconButton/index.js +1 -1
  56. package/dist/{IconButton-VQGNMJDI.css → IconButton-TVEUWK6L.css} +2 -2
  57. package/dist/ImageUpload/ImageUpload.d.ts +10 -7
  58. package/dist/ImageUpload/index.js +2 -2
  59. package/dist/{ImageUpload-HKFIZR6D.css → ImageUpload-YCHJMUGX.css} +24 -10
  60. package/dist/Input/index.js +2 -2
  61. package/dist/Kbd/Kbd.d.ts +14 -4
  62. package/dist/Kbd/index.js +1 -1
  63. package/dist/Kbd-JPLDVJIP.css +71 -0
  64. package/dist/Layer/index.js +1 -1
  65. package/dist/Link/index.js +1 -1
  66. package/dist/List/index.js +1 -1
  67. package/dist/{List-XTHESXLR.css → List-MYJIV6MP.css} +12 -2
  68. package/dist/ListInput/index.js +6 -6
  69. package/dist/Listbox/index.js +2 -2
  70. package/dist/Listbox/useListbox.d.ts +2 -0
  71. package/dist/{Listbox-ZXYYNN6U.css → Listbox-6WJNJQVQ.css} +32 -7
  72. package/dist/Menu/index.js +4 -4
  73. package/dist/Meter/Meter.d.ts +103 -16
  74. package/dist/Meter/index.d.ts +2 -2
  75. package/dist/Meter/index.js +1 -1
  76. package/dist/{Meter-SKOOXQBC.css → Meter-5VCSFMZW.css} +46 -7
  77. package/dist/Modal/index.js +4 -4
  78. package/dist/{Modal-XYQJ4BL6.css → Modal-JAYBS2KS.css} +13 -4
  79. package/dist/OrgLabel/OrgLabel.d.ts +60 -24
  80. package/dist/OrgLabel/index.d.ts +1 -1
  81. package/dist/OrgLabel/index.js +2 -1
  82. package/dist/{OrgLabel-D7U6QJZD.css → OrgLabel-CR233G34.css} +9 -18
  83. package/dist/OrgNode/index.js +3 -2
  84. package/dist/OrgTable/OrgTable.d.ts +2 -2
  85. package/dist/OrgTable/index.js +8 -7
  86. package/dist/Popover/index.js +2 -2
  87. package/dist/PricingCard/index.js +3 -3
  88. package/dist/{PricingCard-JFI7RYXP.css → PricingCard-7EFXRSD2.css} +4 -5
  89. package/dist/SearchTrigger/SearchTrigger.d.ts +23 -4
  90. package/dist/SearchTrigger/index.d.ts +1 -1
  91. package/dist/SearchTrigger/index.js +1 -1
  92. package/dist/SearchTrigger-Z5D4AAY7.css +112 -0
  93. package/dist/SegmentedControl/index.js +2 -2
  94. package/dist/SegmentedMeter/SegmentedMeter.d.ts +107 -0
  95. package/dist/SegmentedMeter/index.d.ts +3 -0
  96. package/dist/SegmentedMeter/index.js +2 -0
  97. package/dist/SegmentedMeter-KQNML2TW.css +109 -0
  98. package/dist/Select/index.js +3 -3
  99. package/dist/Shortcut/index.js +2 -2
  100. package/dist/SidebarNav/SidebarNav.d.ts +85 -25
  101. package/dist/SidebarNav/index.d.ts +1 -1
  102. package/dist/SidebarNav/index.js +1 -1
  103. package/dist/SidebarNav-X5NLZNWA.css +424 -0
  104. package/dist/StatCard/StatCard.d.ts +59 -12
  105. package/dist/StatCard/index.d.ts +1 -1
  106. package/dist/StatCard/index.js +1 -1
  107. package/dist/StatCard-KPAFD4E2.css +204 -0
  108. package/dist/StatGroup/index.js +1 -1
  109. package/dist/{StatGroup-TGB6AEKM.css → StatGroup-HVG6O62W.css} +8 -9
  110. package/dist/StatusDot/StatusDot.d.ts +24 -6
  111. package/dist/StatusDot/index.js +1 -1
  112. package/dist/StatusDot-7OMCQCZF.css +186 -0
  113. package/dist/Stepper/Stepper.d.ts +78 -0
  114. package/dist/Stepper/index.d.ts +3 -0
  115. package/dist/Stepper/index.js +4 -0
  116. package/dist/Stepper-HW4JM3YH.css +176 -0
  117. package/dist/Tabs/index.js +1 -1
  118. package/dist/{Tabs-MJ2E3VPK.css → Tabs-XCNPHA7B.css} +46 -26
  119. package/dist/Tag/Tag.d.ts +29 -22
  120. package/dist/Tag/index.js +2 -2
  121. package/dist/{Tag-VNZEYLB6.css → Tag-GBE7LQJP.css} +82 -83
  122. package/dist/TagsInput/index.js +7 -7
  123. package/dist/ThemeSwitcher/ThemeSwitcher.d.ts +53 -21
  124. package/dist/ThemeSwitcher/index.d.ts +3 -3
  125. package/dist/ThemeSwitcher/index.js +4 -3
  126. package/dist/ThemeSwitcher/preferences.d.ts +19 -5
  127. package/dist/ThemeToggle/ThemeToggle.d.ts +40 -0
  128. package/dist/ThemeToggle/index.d.ts +2 -0
  129. package/dist/ThemeToggle/index.js +5 -0
  130. package/dist/TimeWindowPicker/index.js +8 -8
  131. package/dist/Toaster/index.js +2 -2
  132. package/dist/Toolbar/index.js +2 -2
  133. package/dist/{Toolbar-IP6LXN45.css → Toolbar-HUOSMNTH.css} +3 -1
  134. package/dist/Tooltip/index.js +2 -2
  135. package/dist/Tree/index.d.ts +2 -2
  136. package/dist/Tree/index.js +1 -1
  137. package/dist/Tree/layout.d.ts +103 -28
  138. package/dist/TreeCanvas/TreeCanvas.d.ts +60 -14
  139. package/dist/TreeCanvas/index.d.ts +1 -1
  140. package/dist/TreeCanvas/index.js +6 -6
  141. package/dist/TreeCanvas/motion.d.ts +3 -2
  142. package/dist/{TreeCanvas-WBNQPHC7.css → TreeCanvas-HVOV4SQN.css} +154 -30
  143. package/dist/TreeGrid/index.js +4 -4
  144. package/dist/{chunk-F6OE5FH3.js → chunk-2FPENTCF.js} +1 -1
  145. package/dist/chunk-4AK52VHB.js +88 -0
  146. package/dist/{chunk-7EM5T4ME.js → chunk-4IQD3HUQ.js} +2 -2
  147. package/dist/{chunk-YODNNSZL.js → chunk-4PZ6FJKW.js} +43 -13
  148. package/dist/{chunk-F27EPQ7D.js → chunk-4UQ7SMPK.js} +1 -1
  149. package/dist/chunk-5QWIJSQM.js +73 -0
  150. package/dist/{chunk-KIC7BZYJ.js → chunk-6MU7HNB4.js} +6 -5
  151. package/dist/{chunk-S2XHHEW4.js → chunk-74KMX7YH.js} +4 -4
  152. package/dist/{chunk-WNI2WSJF.js → chunk-7KBNFFM3.js} +1 -1
  153. package/dist/{chunk-EFSG7HNU.js → chunk-AUS5FNQE.js} +1 -1
  154. package/dist/{chunk-CMEE37QJ.js → chunk-BMYPGGPV.js} +4 -4
  155. package/dist/{chunk-H4FBTAYS.js → chunk-BNCCEER3.js} +8 -8
  156. package/dist/chunk-C5WJUZVR.js +56 -0
  157. package/dist/{chunk-5WS6L6FA.js → chunk-CAIHUYXV.js} +9 -9
  158. package/dist/{chunk-5KSRXHOW.js → chunk-CQY5NTRS.js} +1 -1
  159. package/dist/{chunk-MW356IVK.js → chunk-D6EVJUGU.js} +2 -2
  160. package/dist/{chunk-7PEFUMQJ.js → chunk-DHPUMOTX.js} +2 -2
  161. package/dist/{chunk-HZ5XZNPS.js → chunk-DS2C73RJ.js} +3 -3
  162. package/dist/{chunk-GKHAKGOF.js → chunk-DSUY5F4E.js} +3 -3
  163. package/dist/{chunk-Q4ZPPART.js → chunk-EFYPAJT3.js} +3 -3
  164. package/dist/{chunk-PATXSJGR.js → chunk-ERVO6OUF.js} +17 -17
  165. package/dist/{chunk-BZYDZBAN.js → chunk-ETYEBKR4.js} +3 -3
  166. package/dist/{chunk-CC67MUUO.js → chunk-FD5UEN6X.js} +30 -30
  167. package/dist/{chunk-5SDBMKUO.js → chunk-FIFNP6PL.js} +3 -3
  168. package/dist/{chunk-7HPRF5XN.js → chunk-FUF52K7E.js} +98 -16
  169. package/dist/{chunk-5KPQ6D7N.js → chunk-FZVJDJFN.js} +2 -2
  170. package/dist/chunk-IA232OTU.js +156 -0
  171. package/dist/{chunk-2EOKFKHX.js → chunk-IG27QX7Q.js} +7 -7
  172. package/dist/chunk-IKB6HFGK.js +55 -0
  173. package/dist/{chunk-T43A26SD.js → chunk-IPVQKAHO.js} +6 -6
  174. package/dist/{chunk-3EYF6HKB.js → chunk-IVFJD7WY.js} +28 -9
  175. package/dist/{chunk-XJWXPRSK.js → chunk-JGRNTBF2.js} +11 -11
  176. package/dist/chunk-K3OWD7BJ.js +121 -0
  177. package/dist/{chunk-6KCO2D5C.js → chunk-KD4H66L6.js} +7 -20
  178. package/dist/{chunk-SFZOKW2G.js → chunk-KJ34ZBBI.js} +8 -3
  179. package/dist/{chunk-AQTBF4EB.js → chunk-LFHCXZO5.js} +5 -5
  180. package/dist/{chunk-LWKJQTOM.js → chunk-MICH6QSJ.js} +1 -1
  181. package/dist/chunk-N3DPO6HG.js +226 -0
  182. package/dist/{chunk-S4GZWSKR.js → chunk-OM5E3TTK.js} +1 -1
  183. package/dist/{chunk-3QRYCPXQ.js → chunk-OPKIKM35.js} +6 -6
  184. package/dist/{chunk-5EKIWVOR.js → chunk-PGRPNDWM.js} +2 -2
  185. package/dist/{chunk-FSOW3ARP.js → chunk-PQNILU27.js} +9 -9
  186. package/dist/{chunk-QNCVHRZL.js → chunk-QVAFL2LE.js} +1 -1
  187. package/dist/{chunk-Q3B66TJM.js → chunk-QY7UU5ZB.js} +1 -1
  188. package/dist/{chunk-ITHXJHBB.js → chunk-R25RGPUB.js} +1 -0
  189. package/dist/{chunk-KLJCCMF3.js → chunk-R6735B37.js} +2 -2
  190. package/dist/{chunk-3ZP55QZE.js → chunk-R6FBDTP3.js} +4 -4
  191. package/dist/{chunk-7FZ53WDJ.js → chunk-RIAZM6L3.js} +1 -1
  192. package/dist/chunk-RJM4QCGG.js +550 -0
  193. package/dist/{chunk-NTRZGNEX.js → chunk-S3BCVWTU.js} +215 -46
  194. package/dist/chunk-S7KW47IQ.js +121 -0
  195. package/dist/{chunk-KNYYCWMK.js → chunk-SJQ546ID.js} +4 -4
  196. package/dist/{chunk-D35VTV2Z.js → chunk-SV7QAONL.js} +1 -1
  197. package/dist/{chunk-IAJLHVUA.js → chunk-TIWAHZZ6.js} +1 -1
  198. package/dist/{chunk-2PRH365R.js → chunk-UA7O3KKJ.js} +1 -1
  199. package/dist/{chunk-NPZY6YYL.js → chunk-UG5ZMAXW.js} +6 -6
  200. package/dist/{chunk-NDCATSW7.js → chunk-V34H2YCY.js} +1 -1
  201. package/dist/chunk-WIATRXEJ.js +22 -0
  202. package/dist/{chunk-5C5YMZQU.js → chunk-WOFOMTGB.js} +16 -10
  203. package/dist/{chunk-QYOFACSP.js → chunk-WSOFKOLP.js} +3 -3
  204. package/dist/{chunk-MNAXYY3R.js → chunk-WUVZDFHS.js} +31 -11
  205. package/dist/{chunk-DB2VDLVR.js → chunk-YIMOT5OO.js} +10 -10
  206. package/dist/{chunk-2ZQMA2WB.js → chunk-ZPSOF6VL.js} +2 -2
  207. package/dist/generated/index.d.ts +3 -0
  208. package/dist/generated/index.js +69 -65
  209. package/dist/index.js +69 -65
  210. package/dist/styles.css +2538 -741
  211. package/dist/utils/index.d.ts +1 -1
  212. package/dist/utils/tone.d.ts +7 -12
  213. package/package.json +4 -4
  214. package/scripts/check-css-literals.mjs +159 -23
  215. package/scripts/check-css-variables.mjs +5 -3
  216. package/scripts/css-source.mjs +97 -5
  217. package/dist/Avatar-P2KRQM2B.css +0 -156
  218. package/dist/Charts-D7G2BSXH.css +0 -277
  219. package/dist/CommandPalette-CSJDUCQA.css +0 -115
  220. package/dist/Kbd-W66MXQI5.css +0 -61
  221. package/dist/SearchTrigger-QXOYAUUY.css +0 -79
  222. package/dist/SidebarNav-QGSFKZYA.css +0 -319
  223. package/dist/StatCard-KYPKZUWX.css +0 -111
  224. package/dist/StatusDot-HA2L2FSX.css +0 -84
  225. package/dist/chunk-22O7LAW2.js +0 -41
  226. package/dist/chunk-AJNCATWZ.js +0 -144
  227. package/dist/chunk-F4PJZ4ED.js +0 -245
  228. package/dist/chunk-PNFASD6F.js +0 -98
  229. package/dist/chunk-PZSWF74H.js +0 -15
  230. package/dist/chunk-R66KLW7S.js +0 -143
  231. /package/dist/{chunk-ZCR6YGQ4.js → chunk-PKIN4IMB.js} +0 -0
package/dist/styles.css CHANGED
@@ -88,7 +88,7 @@
88
88
  }
89
89
 
90
90
 
91
- /* AddPill-DFWXYLIQ.css */
91
+ /* AddPill-IJQYCY6C.css */
92
92
  /*
93
93
  * The control that adds a child (AddPill.tsx).
94
94
  *
@@ -493,6 +493,15 @@
493
493
  `currentcolor` under that root then resolves to THAT: the fill was
494
494
  overridden and landed on the same purple it started from. */
495
495
  color: inherit;
496
+ }
497
+
498
+ /* THE FILL IS FOR A FILLED DRAWING, and a glyph is a stroke. Painting the
499
+ inside of a Lucide glyph turns every closed shape in it solid and every
500
+ open one into a smear, so a `.crewlet-glyph` keeps the fill its own frame
501
+ decides and takes the ink through its stroke, which is `currentColor`. */
502
+ .crewlet-add-pill__section svg:not(.crewlet-glyph),
503
+ .crewlet-add-pill__section svg:not(.crewlet-glyph) g,
504
+ .crewlet-add-pill__section svg:not(.crewlet-glyph) path {
496
505
  fill: currentcolor;
497
506
  }
498
507
 
@@ -525,18 +534,30 @@
525
534
  }
526
535
 
527
536
 
528
- /* AppShell-NVE6LHNI.css */
537
+ /* AppShell-XARELGIH.css */
529
538
  /*
530
- * The application frame.
539
+ * The application frame: a rail on the FRAME, and the screen on a SHEET that
540
+ * floats beside it.
531
541
  *
532
542
  * The rail's width and the bar's height are read from the token layer through
533
543
  * two component variables, so an application with a narrower rail sets ONE
534
544
  * value rather than repeating a number in its own stylesheet, which is what
535
545
  * every consumer of the passive shell had to do.
536
546
  *
547
+ * THE SHEET IS INSET FROM THE FRAME, rounded, and drawn round with the plain
548
+ * hairline, which is the approved design's frame: the rail stands on the
549
+ * lowest rung and the screen a rung above it, so where the navigation ends
550
+ * and the page begins is a difference of ground, a line and a corner rather
551
+ * than a divider the rail draws. The inset is --size-shell-inset on the
552
+ * sheet's top, right and bottom; the rail is the gap on its left. The sheet clips what it holds to its corner, and the ONE scroller is
553
+ * inside it, so a screen scrolls under the bar and never past the corner.
554
+ *
537
555
  * The breakpoint is written out because a media query cannot read a custom
538
556
  * property. It is the shell step from @crewlethq/tokens, and the CSS check
539
- * compares the literal against the token.
557
+ * compares the literal against the token. The query is STRICTLY UNDER it,
558
+ * (width < 1024px): the step is the rail, the inset and the sheet's floor
559
+ * added up, so at exactly that width the rail still fits, and the component's
560
+ * own matchMedia asks the same question.
540
561
  */
541
562
 
542
563
  .crewlet-app-shell {
@@ -548,15 +569,34 @@
548
569
  --crewlet-app-shell-drawer-z: var(--z-index-overlay);
549
570
  display: grid;
550
571
  grid-template-columns: var(--crewlet-app-shell-rail) minmax(0, 1fr);
572
+ /* One row, the viewport's height less nothing: the sheet's own margin is
573
+ what holds it off the frame's edges, and a row sized by its content would
574
+ let a tall screen push the sheet's bottom edge off the window. */
575
+ grid-template-rows: minmax(0, 1fr);
551
576
  /* THE DOCUMENT DOES NOT SCROLL: exactly the viewport, and nothing may grow
552
577
  past it. A page that can also scroll as a whole carries the rail off the
553
578
  top of the window. */
554
579
  height: 100dvh;
555
580
  overflow: hidden;
556
- background: var(--color-surface-background);
581
+ /* The FRAME, the lowest rung: what the rail stands on and what shows round
582
+ the sheet's inset. */
583
+ background: var(--color-surface-frame);
557
584
  color: var(--color-text-primary);
558
585
  }
559
586
 
587
+ /*
588
+ * A shell with no rail is one column, and the sheet is inset on its left as
589
+ * well, from the frame's edge rather than from a rail. The inset is
590
+ * the ROOT's padding rather than a second margin rule on the sheet, so the
591
+ * narrow block below takes it back with a rule of the same weight declared
592
+ * after this one; a margin here would have needed two classes, and would have
593
+ * beaten the narrow block's one.
594
+ */
595
+ .crewlet-app-shell--no-rail {
596
+ grid-template-columns: minmax(0, 1fr);
597
+ padding-left: var(--size-shell-inset);
598
+ }
599
+
560
600
  /* The skip link, drawn only while it holds focus, over everything. */
561
601
  .crewlet-app-shell__skip {
562
602
  position: fixed;
@@ -581,13 +621,22 @@
581
621
  outline-offset: 2px;
582
622
  }
583
623
 
624
+ /*
625
+ * The rail stands on the FRAME, the application ground, and the screen beside
626
+ * it on the sheet: the two lowest rungs, which are what separate the chrome a
627
+ * reader navigates with from the page they are reading.
628
+ *
629
+ * AND IT DRAWS NO EDGE OF ITS OWN in the wide layout. It carried a right
630
+ * border when the screen beside it was flush against it; the sheet draws its
631
+ * own hairline now, an inset away, and a second line at the rail's edge would
632
+ * run the height of the window parallel to it, eight pixels off.
633
+ */
584
634
  .crewlet-app-shell__rail {
585
635
  display: flex;
586
636
  flex-direction: column;
587
637
  min-height: 0;
588
638
  min-width: 0;
589
- background: var(--color-surface-topbar);
590
- border-right: 1px solid var(--color-border-default);
639
+ background: var(--color-surface-frame);
591
640
  }
592
641
 
593
642
  .crewlet-app-shell__rail-inner {
@@ -598,8 +647,13 @@
598
647
  }
599
648
 
600
649
  /*
601
- * The head sits at the top bar's own height, so the first nav row starts level
602
- * with the top of the screen beside it.
650
+ * The head stands BESIDE the top bar: the inset the sheet is held off the
651
+ * frame by, then the bar's own height, so what the head holds (the lockup) is
652
+ * centred on the same line as the screen's title in the bar beside it, and the
653
+ * first nav row starts level with the top of the screen under the bar. The
654
+ * box is sized as a border box whatever the document says, because the height
655
+ * is written as the inset plus the bar and the padding is the inset: counted
656
+ * outside the height, the head would stand an inset taller than the bar.
603
657
  *
604
658
  * AND IT DRAWS NO LINE OF ITS OWN. It carried a bottom border, which put a
605
659
  * divider across the rail at the same height as the bar's, and the two read as
@@ -612,7 +666,9 @@
612
666
  display: flex;
613
667
  align-items: center;
614
668
  flex: none;
615
- min-height: var(--crewlet-app-shell-topbar);
669
+ box-sizing: border-box;
670
+ min-height: calc(var(--size-shell-inset) + var(--crewlet-app-shell-topbar));
671
+ padding-top: var(--size-shell-inset);
616
672
  }
617
673
 
618
674
  .crewlet-app-shell__rail-body {
@@ -646,7 +702,7 @@
646
702
  * AND SO DOES WHATEVER ELSE LANDS THERE. `AppShell.RailRow` is the row this
647
703
  * package draws, but the slot takes a control from anywhere and an application
648
704
  * that already has a status button reaches for that one: the engine drops a
649
- * tertiary Button into the foot, which arrived centred in a 263px rail on a
705
+ * ghost Button into the foot, which arrived centred in a 263px rail on a
650
706
  * toolbar's inset. The foot claims a direct child instead, which is the same
651
707
  * move the nav's badge slot makes on whatever a caller puts in it, and there
652
708
  * is no second idea of what a row in this rail is.
@@ -699,17 +755,17 @@
699
755
  color: var(--color-text-primary);
700
756
  }
701
757
 
702
- /* A row in the foot fills the rail, so its label takes whatever the glyph and
703
- the trailing slot leave it and truncates rather than pushing them off the
704
- end: a status line says what a node is doing, and what it says is as long as
705
- the sentence the application wrote. */
758
+ /* A row in the foot fills the rail, so its label takes whatever the glyph
759
+ leaves it and WRAPS rather than ending in an ellipsis: a status line says
760
+ what a node is doing, and what it says is as long as the sentence the
761
+ application wrote. Cut, it kept the half that said nothing ("engine
762
+ conn…"). */
706
763
  .crewlet-app-shell__rail-foot > .crewlet-btn > .crewlet-btn__label {
707
764
  display: block;
708
765
  flex: 1 1 auto;
709
766
  min-width: 0;
710
- overflow: hidden;
711
- text-overflow: ellipsis;
712
- white-space: nowrap;
767
+ overflow-wrap: anywhere;
768
+ white-space: normal;
713
769
  }
714
770
 
715
771
  /*
@@ -730,27 +786,102 @@
730
786
  flex: none;
731
787
  }
732
788
 
733
- .crewlet-app-shell__rail-row-label {
789
+ /*
790
+ * THE WORDS AND THE TRAILING VALUE SHARE ONE WRAPPING LINE, and the words are
791
+ * never cut.
792
+ *
793
+ * The words take their own width up to the whole line (`flex-basis: auto`
794
+ * with `max-width: 100%`), so the line breaks BEFORE the value exactly when
795
+ * the words and the value together are wider than the rail: the value stands
796
+ * at the end of the words' line while both fit, and at the start of a line
797
+ * of its own under them when they do not. The words grow into what is left
798
+ * on their line, which is what puts a value that fits at the row's end
799
+ * without a margin that would also push a wrapped one to the far side. And
800
+ * words wider than the rail wrap, at any character if they must, rather than
801
+ * end in an ellipsis: they are the part of the row that was the point.
802
+ */
803
+ .crewlet-app-shell__rail-row-body {
804
+ display: flex;
734
805
  flex: 1 1 auto;
806
+ flex-wrap: wrap;
807
+ align-items: center;
808
+ gap: var(--spacing-1) var(--spacing-2);
809
+ min-width: 0;
810
+ }
811
+
812
+ .crewlet-app-shell__rail-row-text {
813
+ display: flex;
814
+ flex: 1 0 auto;
815
+ flex-direction: column;
816
+ max-width: 100%;
735
817
  min-width: 0;
736
- overflow: hidden;
737
- text-overflow: ellipsis;
738
- white-space: nowrap;
739
818
  }
740
819
 
741
- /* Pushed to the end of the row whatever the label's length. */
820
+ .crewlet-app-shell__rail-row-label,
821
+ .crewlet-app-shell__rail-row-detail {
822
+ overflow-wrap: anywhere;
823
+ }
824
+
742
825
  .crewlet-app-shell__rail-row-trailing {
743
826
  display: inline-flex;
744
827
  align-items: center;
745
828
  flex: none;
746
- margin-left: auto;
747
829
  }
748
830
 
749
- .crewlet-app-shell__column {
831
+ /*
832
+ * THE STATUS BLOCK: a row given a `detail` is the approved design's engine
833
+ * status, its words over a second line, on the card rung inside the plain
834
+ * hairline, so the one row in the foot that reports on the fleet stands off
835
+ * the rows that only go somewhere. The words step up to the primary ink at the
836
+ * medium weight, since they are the state, and the detail keeps the row's
837
+ * quiet ink a step smaller. Both are set on the snug leading, where the
838
+ * design's two lines sit as one block rather than as two rows.
839
+ *
840
+ * It keeps the row's own inline pad and its transparent-border arithmetic, so
841
+ * its mark still lands on the line every nav glyph above it sits on; the block
842
+ * inset grows by a pixel for the second line, the design's 10px around the
843
+ * words with the border counted in.
844
+ */
845
+ .crewlet-app-shell__rail-row--block {
846
+ padding-block: calc(var(--spacing-2) + 1px);
847
+ border-color: var(--color-border-default);
848
+ border-radius: var(--radius-lg);
849
+ background: var(--color-surface-subtle);
850
+ line-height: var(--font-line-height-snug);
851
+ }
852
+
853
+ .crewlet-app-shell__rail-row--block .crewlet-app-shell__rail-row-label {
854
+ color: var(--color-text-primary);
855
+ font-weight: var(--font-weight-medium);
856
+ }
857
+
858
+ .crewlet-app-shell__rail-row-detail {
859
+ color: var(--color-text-tertiary);
860
+ font-size: var(--font-size-2xs);
861
+ }
862
+
863
+ /*
864
+ * THE SHEET: the bar, a banner, the one scroller and a footer, floated on the
865
+ * frame. It stands on --color-surface-background, the sheet rung, inside the
866
+ * plain hairline and at the sheet's own corner, a step rounder than every
867
+ * card drawn inside it. It clips to that corner, which is what lets the bar
868
+ * and the scroller run square to its edges and still be rounded by it.
869
+ *
870
+ * Physical margins, as every other edge in this file is physical: the drawer
871
+ * slides in from the left and the rail's column is the grid's first, so the
872
+ * shell is drawn left to right throughout, and one logical margin in it would
873
+ * be a promise about a direction nothing else here keeps.
874
+ */
875
+ .crewlet-app-shell__sheet {
750
876
  display: flex;
751
877
  flex-direction: column;
752
878
  min-width: 0;
753
879
  min-height: 0;
880
+ margin: var(--size-shell-inset) var(--size-shell-inset) var(--size-shell-inset) 0;
881
+ border: 1px solid var(--color-border-default);
882
+ border-radius: var(--radius-sheet);
883
+ background: var(--color-surface-background);
884
+ overflow: hidden;
754
885
  }
755
886
 
756
887
  .crewlet-app-shell__topbar {
@@ -761,7 +892,7 @@
761
892
  height: var(--crewlet-app-shell-topbar);
762
893
  padding: 0 var(--spacing-4);
763
894
  border-bottom: 1px solid var(--color-border-default);
764
- background: var(--color-surface-topbar);
895
+ background: var(--color-surface-background);
765
896
  }
766
897
 
767
898
  .crewlet-app-shell__title {
@@ -867,17 +998,48 @@
867
998
  background: var(--color-surface-scrim);
868
999
  }
869
1000
 
870
- @media (max-width: 900px) {
1001
+ @media (width < 1024px) {
871
1002
  .crewlet-app-shell {
872
1003
  grid-template-columns: minmax(0, 1fr);
873
1004
  }
874
1005
 
1006
+ .crewlet-app-shell--no-rail {
1007
+ padding-left: 0;
1008
+ }
1009
+
1010
+ /*
1011
+ * FULL BLEED. Under the step the rail is not beside the sheet, so there is
1012
+ * nothing for the sheet to be held off: the inset, the corner and the
1013
+ * hairline all collapse to nothing, and the sheet is the window. A corner
1014
+ * kept here would round the screen into the viewport's own corners, and a
1015
+ * hairline would draw a line round the window's edge.
1016
+ */
1017
+ .crewlet-app-shell__sheet {
1018
+ margin: 0;
1019
+ border-width: 0;
1020
+ border-radius: 0;
1021
+ }
1022
+
1023
+ /* Beside a full-bleed sheet the bar starts at the window's top, and so does
1024
+ the drawer's head. */
1025
+ .crewlet-app-shell__rail-head {
1026
+ min-height: var(--crewlet-app-shell-topbar);
1027
+ padding-top: 0;
1028
+ }
1029
+
1030
+ /*
1031
+ * The drawer draws the edge the wide rail does not: it slides over the
1032
+ * screen rather than standing beside a sheet that draws its own, and in
1033
+ * light the frame and the sheet it covers are close enough that the shadow
1034
+ * alone does not say where the drawer ends.
1035
+ */
875
1036
  .crewlet-app-shell__rail {
876
1037
  position: fixed;
877
1038
  inset: 0 auto 0 0;
878
1039
  width: var(--crewlet-app-shell-rail);
879
1040
  max-width: 100%;
880
1041
  transform: translateX(-100%);
1042
+ border-right: 1px solid var(--color-border-default);
881
1043
  box-shadow: var(--shadow-xl);
882
1044
  /*
883
1045
  * HIDDEN, not only moved. A rail translated off screen keeps every link
@@ -923,7 +1085,7 @@
923
1085
  }
924
1086
 
925
1087
 
926
- /* Avatar-P2KRQM2B.css */
1088
+ /* Avatar-XID7Z74C.css */
927
1089
  /*
928
1090
  * The identity badge.
929
1091
  *
@@ -932,7 +1094,11 @@
932
1094
  * spent on phases and event categories, so one amber meant "the execute
933
1095
  * phase", "the decision category" and "the Analyst" at once. A hash of a name
934
1096
  * carries no information: rename the seat and its colour changes, which is the
935
- * proof it never meant anything. Identity is the monogram and the name.
1097
+ * proof it never meant anything. Identity is the OUTLINE (a squircle for an
1098
+ * agent, a circle for a person), the monogram and the name.
1099
+ *
1100
+ * THE ONE HUE A BADGE CARRIES IS A STATE, as a ring round it, and the ring is
1101
+ * the component's only coloured line.
936
1102
  *
937
1103
  * The seeded tints stay for the one case that earns them, a roster somebody
938
1104
  * scans, and their grounds are TOKENS: measured under white initials and held
@@ -958,7 +1124,7 @@
958
1124
  The box is a fixed square that centres whatever line it holds, so the ink
959
1125
  lands in the same place either way; what the tight step bought was one
960
1126
  more number in a component that already sets four. */
961
- line-height: var(--font-line-height-normal);
1127
+ line-height: var(--font-line-height-body);
962
1128
  text-transform: uppercase;
963
1129
  user-select: none;
964
1130
  box-sizing: border-box;
@@ -966,8 +1132,10 @@
966
1132
 
967
1133
  /*
968
1134
  * The four steps. Each pairs its box with a type step, so two initials sit
969
- * inside the circle at every one of them; a numeric size computes its own,
970
- * because nothing in the scale can answer for an arbitrary box.
1135
+ * inside the outline at every one of them. A numeric size sets the same
1136
+ * `--crewlet-avatar-size` inline and computes its own type, because nothing in
1137
+ * the scale can answer for an arbitrary box; everything else it takes from the
1138
+ * rules below exactly as a step does.
971
1139
  */
972
1140
  .crewlet-avatar--xs {
973
1141
  --crewlet-avatar-size: 20px;
@@ -989,35 +1157,47 @@
989
1157
  font-size: var(--font-size-sm);
990
1158
  }
991
1159
 
1160
+ /* ── kinds ─────────────────────────────────────────────────────────────── */
1161
+
992
1162
  /*
993
- * Shapes. THE SQUARE IS THE DEFAULT, which is the change: the engine's
994
- * identity mark is a rounded square and it is what a reader sees in every seat
995
- * chip, every list row and every header on that product. A circle stays for a
996
- * PERSON, where the round badge is the platform convention a member list
997
- * already speaks.
1163
+ * AN AGENT IS A SQUIRCLE, set in the mono face: what the engine runs, named
1164
+ * the way a handle is written.
1165
+ *
1166
+ * THE CORNER MOVES WITH THE BOX, at 0.29 of it (`AVATAR_CORNER_RATIO` in the
1167
+ * component, which the suite holds equal to this number): the approved
1168
+ * design's 7px at 24 and 9px at 30, as one proportion. It is computed here from
1169
+ * the size property every step and every numeric size sets, so there is ONE
1170
+ * ladder. There used to be two, a step table here and a numeric table in the
1171
+ * component, and they disagreed: `size={80}` drew a squarer badge than
1172
+ * `size="lg"` at half its width.
998
1173
  *
999
- * The square's radius moves with the box rather than sitting at one step. The
1000
- * engine draws 4px at 20, 8px at 26 and 12px at 40, which is a roughly
1001
- * constant proportion; one radius across the four steps reads as a pill at the
1002
- * smallest and as a plain box at the largest. A NUMERIC SIZE OBEYS THE SAME
1003
- * LADDER, from `avatarSquareCorner` in the component, which picks the corner
1004
- * of the step nearest the box it was given: taking one fixed step there is how
1005
- * `size={80}` ended up drawn squarer than `size="lg"` at half its width.
1174
+ * WHERE THE BROWSER DRAWS A SQUIRCLE, IT IS A WHOLE ONE. `corner-shape:
1175
+ * squircle` is a superellipse of exponent 4, which at a given radius reaches
1176
+ * much closer to the box's corner than a circular arc does: at the 45 degree
1177
+ * point it stands 0.159 of the radius in from each edge, against 0.293 for an
1178
+ * arc. Kept at 0.29 of the box, that corner would stand 0.046 of the box in,
1179
+ * half the design's depth and a nearly square badge. At half the box it stands
1180
+ * 0.0795 of the box in, against the design's 0.0849 (0.13px at 24px), with the
1181
+ * continuous curvature a squircle is for. So the corner is the circle token
1182
+ * there, and the fallback above is what every other browser draws.
1006
1183
  */
1007
- .crewlet-avatar--circle {
1008
- border-radius: var(--radius-circle);
1009
- }
1010
-
1011
- .crewlet-avatar--square {
1012
- border-radius: var(--radius-md);
1184
+ .crewlet-avatar--agent {
1185
+ border-radius: calc(var(--crewlet-avatar-size) * 0.29);
1186
+ font-family: var(--font-family-mono);
1013
1187
  }
1014
1188
 
1015
- .crewlet-avatar--square.crewlet-avatar--xs {
1016
- border-radius: var(--radius-xs);
1189
+ @supports (corner-shape: squircle) {
1190
+ .crewlet-avatar--agent {
1191
+ corner-shape: squircle;
1192
+ border-radius: var(--radius-circle);
1193
+ }
1017
1194
  }
1018
1195
 
1019
- .crewlet-avatar--square.crewlet-avatar--lg {
1020
- border-radius: var(--radius-lg);
1196
+ /* A PERSON IS A CIRCLE, set in the sans face, the round badge every member list
1197
+ a reader has used already speaks. */
1198
+ .crewlet-avatar--human {
1199
+ border-radius: var(--radius-circle);
1200
+ font-family: var(--font-family-sans);
1021
1201
  }
1022
1202
 
1023
1203
  .crewlet-avatar--image {
@@ -1031,23 +1211,15 @@
1031
1211
  border: 1px solid transparent;
1032
1212
  }
1033
1213
 
1214
+ /* The design's badge: the raised rung with the strong hairline round it and
1215
+ the secondary ink, so a badge on a card reads as a mark standing on it
1216
+ rather than as a hole in it. */
1034
1217
  .crewlet-avatar--neutral {
1035
1218
  background: var(--color-surface-elevated);
1036
- border-color: var(--color-border-default);
1219
+ border-color: var(--color-border-strong);
1037
1220
  color: var(--color-text-secondary);
1038
1221
  }
1039
1222
 
1040
- /*
1041
- * The label on the accent fill is the on-accent step, not the on-brand one.
1042
- * The themes repaint the brand fill monochrome and leave the accent where it
1043
- * is, so on-brand is black in the dark palette and black on the accent
1044
- * measures 4.35:1. On-accent is white in every palette and measures 4.83:1.
1045
- */
1046
- .crewlet-avatar--brand {
1047
- background: var(--color-brand-accent);
1048
- color: var(--color-text-on-accent);
1049
- }
1050
-
1051
1223
  .crewlet-avatar--seeded {
1052
1224
  color: var(--color-text-on-accent);
1053
1225
  }
@@ -1063,26 +1235,135 @@
1063
1235
  .crewlet-avatar--tint-8 { background: var(--color-avatar-tint-8); }
1064
1236
  .crewlet-avatar--tint-9 { background: var(--color-avatar-tint-9); }
1065
1237
 
1238
+ /* ── the state ring ────────────────────────────────────────────────────── */
1239
+
1240
+ /*
1241
+ * A 1.5px LINE 2px OUTSIDE THE BADGE, which is the design's ring: it draws a
1242
+ * 3.5px shadow over a 2px one in the card's colour, and 3.5 less 2 is 1.5.
1243
+ *
1244
+ * AN OUTLINE RATHER THAN THAT SHADOW PAIR, for three reasons. The gap is
1245
+ * TRANSPARENT, so the ring reads on whatever the badge stands on, where the
1246
+ * design's gap is the card's own fill and cuts a card-coloured band into any
1247
+ * other ground. An outline follows the corner, the squircle's included, in
1248
+ * every engine this package supports. And forced-colors mode keeps an outline
1249
+ * and drops every shadow, so the ring is still drawn for the readers who most
1250
+ * need a boundary; it is drawn in the system colour there, which is why the
1251
+ * state is always said in words beside the badge as well.
1252
+ *
1253
+ * LONGHANDS, so the tone rules below set the colour alone and cannot reset the
1254
+ * geometry, whichever order they are read in. Each fill is measured at 3:1 as
1255
+ * a mark on every opaque surface by @crewlethq/tokens, which is the floor a
1256
+ * boundary a reader has to see is held to.
1257
+ */
1258
+ .crewlet-avatar--ring-info,
1259
+ .crewlet-avatar--ring-warning,
1260
+ .crewlet-avatar--ring-danger,
1261
+ .crewlet-avatar--ring-success,
1262
+ .crewlet-avatar--ring-brand {
1263
+ outline-style: solid;
1264
+ outline-width: 1.5px;
1265
+ outline-offset: 2px;
1266
+ }
1267
+
1268
+ .crewlet-avatar--ring-info {
1269
+ outline-color: var(--color-feedback-info);
1270
+ }
1271
+
1272
+ .crewlet-avatar--ring-warning {
1273
+ outline-color: var(--color-feedback-warning);
1274
+ }
1275
+
1276
+ .crewlet-avatar--ring-danger {
1277
+ outline-color: var(--color-feedback-danger);
1278
+ }
1279
+
1280
+ .crewlet-avatar--ring-success {
1281
+ outline-color: var(--color-feedback-success);
1282
+ }
1283
+
1284
+ /* SELECTED, in the accent, which is what the accent means: where the reader
1285
+ is. It is the only place a badge spends the accent. */
1286
+ .crewlet-avatar--ring-brand {
1287
+ outline-color: var(--color-brand-accent);
1288
+ }
1289
+
1290
+
1291
+ /* AvatarStack-GEJBNV7E.css */
1066
1292
  /*
1067
- * A HUMAN SEAT IS DRAWN, NOT TINTED. The engine does not run it, which is a
1068
- * structural fact rather than a status, so it takes the edge and no fill at
1069
- * all. Last, so it wins over whichever tone it is paired with.
1293
+ * Several badges as one mark (AvatarStack.tsx).
1294
+ *
1295
+ * THE DESIGN'S STACK: each badge overlaps the one before it by 6px and is cut
1296
+ * out of it by a 2px ring in the ground's own colour, so the overlap reads as
1297
+ * badges standing in front of each other rather than as one blot. The ring is
1298
+ * a SHADOW rather than a border, because it has to fall outside the badge
1299
+ * without moving it, and it is decoration: forced-colors mode drops it and the
1300
+ * badges' own hairlines still separate them.
1070
1301
  *
1071
- * The whole border rather than its style alone: the badge is the same person
1072
- * whether or not they have uploaded a photo, and an image draws no border of
1073
- * its own for a style to change.
1302
+ * THE GROUND IS A VARIABLE because a stack stands on whatever it is put on,
1303
+ * and a cut-out in the sheet's colour on a card is a band of the wrong grey
1304
+ * round every badge. It defaults to the SHEET, because that is where the
1305
+ * approved design draws every stack it has: in the top bar of a page, over a
1306
+ * board and over a knowledge page, and in a task's side column, all of them on
1307
+ * the sheet, with the design's own cut-out drawn in the sheet's colour. A stack
1308
+ * that stands on a card, or on anything else, sets it on the stack itself.
1309
+ *
1310
+ * Every rule is two classes deep, so it outweighs the badge's own one-class
1311
+ * rules whichever order the stylesheets are bundled in.
1074
1312
  */
1075
- .crewlet-avatar--dashed {
1076
- background: transparent;
1077
- /* The same hairline the solid neutral badge draws, so the human seat differs
1078
- by its LINE STYLE and its missing fill rather than by a second grey a
1079
- reader would have to hold two of in mind. */
1080
- border: 1px dashed var(--color-border-default);
1313
+
1314
+ .crewlet-avatar-stack {
1315
+ --crewlet-avatar-stack-ground: var(--color-surface-background);
1316
+ /* The badges' box, which the component sets from the step it was given; the
1317
+ default is the default step's, sm. The chip reads it, so it stands exactly
1318
+ as tall as the badges beside it. */
1319
+ --crewlet-avatar-stack-size: 26px;
1320
+ display: inline-flex;
1321
+ flex: none;
1322
+ align-items: center;
1323
+ vertical-align: middle;
1324
+ }
1325
+
1326
+ .crewlet-avatar-stack > .crewlet-avatar-stack__member {
1327
+ box-shadow: 0 0 0 2px var(--crewlet-avatar-stack-ground);
1328
+ }
1329
+
1330
+ /* The design's 6px, a little under a third of its 22px badge: enough that the
1331
+ stack is one mark, little enough that every monogram stays readable. */
1332
+ .crewlet-avatar-stack > .crewlet-avatar-stack__member + .crewlet-avatar-stack__member {
1333
+ margin-inline-start: -6px;
1334
+ }
1335
+
1336
+ /*
1337
+ * THE COUNT OF THE REST. A PILL, where every badge is a squircle or a circle:
1338
+ * it is a number rather than somebody, and drawn in either kind's outline it
1339
+ * would read as one more agent or one more person. Otherwise it is the neutral
1340
+ * badge exactly (the raised rung, the strong hairline, the secondary ink), in
1341
+ * the sans face with tabular figures so "+9" and "+12" sit alike.
1342
+ */
1343
+ .crewlet-avatar-stack > .crewlet-avatar-stack__more {
1344
+ display: inline-flex;
1345
+ flex: none;
1346
+ align-items: center;
1347
+ justify-content: center;
1348
+ box-sizing: border-box;
1349
+ min-width: var(--crewlet-avatar-stack-size);
1350
+ height: var(--crewlet-avatar-stack-size);
1351
+ padding-inline: var(--spacing-1);
1352
+ border: 1px solid var(--color-border-strong);
1353
+ border-radius: var(--radius-pill);
1354
+ background: var(--color-surface-elevated);
1081
1355
  color: var(--color-text-secondary);
1356
+ font-family: var(--font-family-sans);
1357
+ font-size: var(--font-size-2xs);
1358
+ font-weight: var(--font-weight-semibold);
1359
+ font-variant-numeric: tabular-nums;
1360
+ line-height: var(--font-line-height-tight);
1361
+ white-space: nowrap;
1362
+ user-select: none;
1082
1363
  }
1083
1364
 
1084
1365
 
1085
- /* BrandLockup-6ISDEHPJ.css */
1366
+ /* BrandLockup-JKGXFCZF.css */
1086
1367
  /*
1087
1368
  * The brand lockup at the head of the rail.
1088
1369
  *
@@ -1094,12 +1375,19 @@
1094
1375
 
1095
1376
  /*
1096
1377
  * IT FITS THE BAR IT IS DRAWN BESIDE. The rail's head is the top bar's own
1097
- * height (64px, a fixed token at every density), so the lockup has to come in
1378
+ * height (52px, a fixed token at every density), so the lockup has to come in
1098
1379
  * under that height with its context line on: mark 24 plus one 11px line at
1099
- * the document's own leading plus twice the block padding is 56.5px at the
1100
- * normal density and 58.7px at comfortable. It was 66.5px, which grew the head
1101
- * past the bar and put a visible kink across the window on every deployment
1102
- * that names a company.
1380
+ * the document's own leading (15.95px) plus twice the block padding is 47.95px
1381
+ * at the normal density and 49.07px at comfortable. It was 66.5px once, which
1382
+ * grew the head past the bar and put a visible kink across the window on every
1383
+ * deployment that names a company.
1384
+ *
1385
+ * THE BLOCK PADDING IS THE SMALL STEP for that reason. It was the 8px step
1386
+ * while the bar was 64px; at 52px the same padding made the lockup 55.95px,
1387
+ * past the bar again, and the mark and the context line cannot give anything
1388
+ * up (the mark is the home link's 24px target, the line is the document's).
1389
+ * The head centres the lockup, so the padding is the least room it keeps at
1390
+ * the top and the bottom rather than the room it is drawn with.
1103
1391
  *
1104
1392
  * NO GAP BETWEEN THE TWO LINES. They are one lockup rather than two stacked
1105
1393
  * labels, and the leading is the space between them: a gap on top of it reads
@@ -1118,7 +1406,7 @@
1118
1406
  link's target height, so it sits on the 24px floor rather than under it.
1119
1407
  A consumer with a wider mark sets this rather than editing two rules. */
1120
1408
  --crewlet-brand-mark: 24px;
1121
- padding: var(--spacing-2) calc(var(--size-nav-gutter) + var(--size-nav-row-pad));
1409
+ padding: var(--spacing-1) calc(var(--size-nav-gutter) + var(--size-nav-row-pad));
1122
1410
  }
1123
1411
 
1124
1412
  .crewlet-brand__home {
@@ -1157,7 +1445,7 @@
1157
1445
  font-size: var(--font-size-sm);
1158
1446
  font-weight: var(--font-weight-semibold);
1159
1447
  letter-spacing: var(--font-letter-spacing-tight);
1160
- line-height: var(--font-line-height-normal);
1448
+ line-height: var(--font-line-height-body);
1161
1449
  color: var(--color-text-primary);
1162
1450
  overflow: hidden;
1163
1451
  text-overflow: ellipsis;
@@ -1167,24 +1455,23 @@
1167
1455
  /* Indented to the name above it by the mark's own box, and truncated: a
1168
1456
  company name is as long as somebody registered it.
1169
1457
 
1170
- THE RAIL'S OWN MICRO-LABEL REGISTER, which is the wide step rather than the
1171
- wider one an Eyebrow takes: this line and the nav's group labels are the two
1172
- uppercase runs in the rail, they sit twenty pixels apart, and at the wider
1173
- step the company's name was visibly broader than the sections under it
1174
- rather than quieter than them. The suite holds the two together. */
1458
+ THE RAIL'S ONE UPPERCASE RUN, on the wide step rather than the wider one an
1459
+ Eyebrow takes: at the wider step the company's name was visibly broader
1460
+ than the sections under it rather than quieter than them. The nav's group
1461
+ labels twenty pixels below are sentence-case words at the caption step, so
1462
+ the case and the size are what hold the two apart; the suite holds that. */
1175
1463
  .crewlet-brand__context {
1176
1464
  padding-left: calc(var(--crewlet-brand-mark) + var(--spacing-2));
1177
1465
  font-family: var(--font-family-sans);
1178
1466
  font-size: var(--font-size-2xs);
1179
- /* THE REGULAR WEIGHT, which is the one thing that separates this line from
1180
- the nav's group labels below it. The two are the only uppercase runs in
1181
- the rail and they sit twenty pixels apart; drawn at the same size, the
1182
- same tracking and the same weight they read as two headings of one list
1183
- rather than as the company's name above the sections in it. A group name
1184
- is what a reader scans, so the weight stays there and goes from here. */
1467
+ /* THE REGULAR WEIGHT: the company's name is a quiet line under the product
1468
+ name, not a heading. It used to be the one thing separating this line
1469
+ from the nav's group labels, when both were uppercase at this size; the
1470
+ labels are sentence case at the caption step now, and the weight stays
1471
+ here because the line is still meant to be read past. */
1185
1472
  font-weight: var(--font-weight-regular);
1186
1473
  letter-spacing: var(--font-letter-spacing-wide);
1187
- line-height: var(--font-line-height-normal);
1474
+ line-height: var(--font-line-height-body);
1188
1475
  text-transform: uppercase;
1189
1476
  color: var(--color-text-tertiary);
1190
1477
  overflow: hidden;
@@ -1193,16 +1480,16 @@
1193
1480
  }
1194
1481
 
1195
1482
 
1196
- /* Button-D4J6B4MA.css */
1483
+ /* Button-X4B2TJAQ.css */
1197
1484
  /*
1198
1485
  * The button, and the link drawn as one.
1199
1486
  *
1200
1487
  * SIX VARIANTS, AND THEY ARE A HIERARCHY RATHER THAN A PALETTE. primary is the
1201
1488
  * one action on the screen and takes the accent fill; secondary is everything
1202
1489
  * else; outline is the branded yes on a page that already has a primary;
1203
- * tertiary is for a dense toolbar; danger is destructive, and the only one
1204
- * that spends the critical hue. accent is primary's own recipe under the name
1205
- * a caller may already have written.
1490
+ * ghost is for a dense toolbar and the quiet second answer beside a primary;
1491
+ * danger is destructive, and the only one that spends the critical hue. accent
1492
+ * is primary's own recipe under the name a caller may already have written.
1206
1493
  *
1207
1494
  * THE ONE ACTION IS THE ACCENT FILL. It reads as the answer a screen is
1208
1495
  * asking for, which is what a filled monochrome button could not do beside a
@@ -1212,9 +1499,12 @@
1212
1499
  *
1213
1500
  * Every size is a --size-control-* step, so a button, a select and an input in
1214
1501
  * one row are the same height at every density, and none of them can fall
1215
- * under the 24px a finger can hit. The padding ramp is one spacing step per
1216
- * size, so a small button in a toolbar is tight and a large one on a landing
1217
- * page is not.
1502
+ * under the 24px a finger can hit. The steps are the approved design's own
1503
+ * control rhythm, 30px and 26px for the medium and the small button, and they
1504
+ * live in the tokens rather than here because the field and the segmented
1505
+ * row beside a button stand at the same height. The padding ramp is one
1506
+ * spacing step per size, so a small button in a toolbar is tight and a large
1507
+ * one on a landing page is not.
1218
1508
  */
1219
1509
 
1220
1510
  .crewlet-btn {
@@ -1332,9 +1622,16 @@
1332
1622
  * Primary: the accent fill, and the one action on the screen.
1333
1623
  *
1334
1624
  * `accent` is the same recipe under the other name it is written as. They are
1335
- * one rule rather than two, so the pair cannot drift into two blues, and the
1625
+ * one rule rather than two, so the pair cannot drift into two violets, and the
1336
1626
  * name stays because call sites already spell it.
1337
1627
  *
1628
+ * UNDER THE POINTER AND PRESSED IT DARKENS, a step each, and never brightens.
1629
+ * The label is the on-accent white in both palettes, so a brighter fill is a
1630
+ * step toward it: the approved design's brightness(1.08) hover took the dark
1631
+ * accent's label from 4.53:1 to 4.18:1, under the text floor at the one moment
1632
+ * the reader is about to press. The steps are tokens rather than a filter, so
1633
+ * @crewlethq/tokens can measure them.
1634
+ *
1338
1635
  * THE BORDER IS TRANSPARENT rather than the fill: a filled control needs no
1339
1636
  * boundary, and one drawn in the fill's own colour makes the button a step
1340
1637
  * wider than the secondary beside it in every forced-colors stylesheet that
@@ -1359,16 +1656,30 @@
1359
1656
  border-color: transparent;
1360
1657
  }
1361
1658
 
1362
- /* Secondary: a surface with a visible boundary. Everything else. */
1659
+ /*
1660
+ * Secondary: everything else. The CARD's own ground inside the STRONG
1661
+ * hairline, the approved design's button.
1662
+ *
1663
+ * STRONG, NOT DEFAULT, because a button stands on the very card it is filled
1664
+ * with: every panel's actions sit on a card, and there the fill is no edge at
1665
+ * all and the boundary is the whole of the button. The default hairline is
1666
+ * the one that finds a CARD on the sheet, and a button drawn with it was a
1667
+ * card-shaped outline of the panel's own divider; the strong step is the one
1668
+ * a reader takes for a control's edge.
1669
+ *
1670
+ * Under the pointer it steps up a rung, to the raised ground, which the
1671
+ * palette suite holds a visible step above the card, with the boundary a
1672
+ * step stronger again; pressed, the pressed overlay.
1673
+ */
1363
1674
  .crewlet-btn--secondary {
1364
1675
  background: var(--color-surface-subtle);
1365
1676
  color: var(--color-text-primary);
1366
- border-color: var(--color-border-default);
1677
+ border-color: var(--color-border-strong);
1367
1678
  }
1368
1679
 
1369
1680
  .crewlet-btn--secondary:hover:not(:disabled):not([aria-disabled='true']) {
1370
1681
  background: var(--color-surface-elevated);
1371
- border-color: var(--color-border-hover);
1682
+ border-color: var(--color-border-strong-hover);
1372
1683
  }
1373
1684
 
1374
1685
  .crewlet-btn--secondary:active:not(:disabled):not([aria-disabled='true']) {
@@ -1387,19 +1698,25 @@
1387
1698
  background: var(--color-brand-accent-soft);
1388
1699
  }
1389
1700
 
1390
- /* Tertiary: borderless, for a dense toolbar. */
1391
- .crewlet-btn--tertiary {
1701
+ /*
1702
+ * Ghost: no ground and no boundary, for a dense toolbar and for the quiet
1703
+ * answer beside a primary ("Reassign" next to "Raise budget"). It is the word
1704
+ * IconButton's borderless square uses, so a toolbar holding both is written
1705
+ * in one vocabulary. Under the pointer it takes the hover overlay, the one
1706
+ * every row takes, and its ink steps up to the primary text.
1707
+ */
1708
+ .crewlet-btn--ghost {
1392
1709
  background: transparent;
1393
1710
  color: var(--color-text-secondary);
1394
1711
  border-color: transparent;
1395
1712
  }
1396
1713
 
1397
- .crewlet-btn--tertiary:hover:not(:disabled):not([aria-disabled='true']) {
1714
+ .crewlet-btn--ghost:hover:not(:disabled):not([aria-disabled='true']) {
1398
1715
  background: var(--color-surface-hover);
1399
1716
  color: var(--color-text-primary);
1400
1717
  }
1401
1718
 
1402
- .crewlet-btn--tertiary:active:not(:disabled):not([aria-disabled='true']) {
1719
+ .crewlet-btn--ghost:active:not(:disabled):not([aria-disabled='true']) {
1403
1720
  background: var(--color-surface-pressed);
1404
1721
  }
1405
1722
 
@@ -1408,15 +1725,16 @@
1408
1725
  *
1409
1726
  * A SECONDARY THAT HAS GONE RED, not a red slab. It sits in the same row as
1410
1727
  * Cancel and it is the button a reader must not press by reflex, so it holds
1411
- * the secondary's own weight until it is pointed at and states itself in its
1412
- * INK, which is the step measured as text; the red fill it used to carry
1413
- * pulled the eye to the destructive answer first on every dialog that had one.
1414
- * The hue arrives on hover, as the tint plus the full fill on the boundary.
1728
+ * the secondary's own weight, the card inside the strong hairline, until it
1729
+ * is pointed at and states itself in its INK, which is the step measured as
1730
+ * text; the red fill it used to carry pulled the eye to the destructive
1731
+ * answer first on every dialog that had one. The hue arrives on hover, as the
1732
+ * tint plus the full fill on the boundary.
1415
1733
  */
1416
1734
  .crewlet-btn--danger {
1417
1735
  background: var(--color-surface-subtle);
1418
1736
  color: var(--color-feedback-danger-ink);
1419
- border-color: var(--color-border-default);
1737
+ border-color: var(--color-border-strong);
1420
1738
  }
1421
1739
 
1422
1740
  .crewlet-btn--danger:hover:not(:disabled):not([aria-disabled='true']) {
@@ -2061,7 +2379,7 @@
2061
2379
  }
2062
2380
 
2063
2381
 
2064
- /* Card-RLR254LD.css */
2382
+ /* Card-GLP7SUV6.css */
2065
2383
  /*
2066
2384
  * Card, THE surface. Everything on a screen is a card, a row inside one, or a
2067
2385
  * control.
@@ -2091,23 +2409,24 @@
2091
2409
  }
2092
2410
 
2093
2411
  /*
2094
- * TWO GROUNDS, TWO DEVICES. On light the shadow is the elevation; on dark a
2095
- * shadow over a dark page is nearly invisible, so the hairline along the top
2096
- * edge does the job instead.
2412
+ * THE CARD IS FLAT: the card rung inside the default hairline, at the 12px
2413
+ * corner, and nothing else, which is the approved design's card in both
2414
+ * palettes. It casts no shadow and draws no rim of light, because what finds a
2415
+ * card on the sheet is the pair the palette suite holds together: the rung a
2416
+ * visible step off the sheet, and the hairline a clear step off both. A
2417
+ * shadow under every panel of a screen made a list of records into a relief
2418
+ * map, and a rim along every top edge was a second hairline nobody measured.
2419
+ * Lift belongs to what genuinely stands OVER the page, which is `elevated`.
2097
2420
  *
2098
- * THE HAIRLINE IS ON ITS OWN ELEMENT, and that is the whole reason the rule is
2099
- * two rules. `--shadow-hairline` is `none` in the light theme, and `none` is a
2100
- * value a shadow list may not carry: `box-shadow: <shadow>, none` is invalid at
2101
- * computed-value time, so the declaration is dropped and the light card loses
2102
- * the elevation the list was built around. Alone on a pseudo element the same
2103
- * token is valid in both themes, and it composes with the selection ring
2104
- * rather than replacing whichever was declared last, exactly as the rail does.
2421
+ * THE RIM IS ON ITS OWN ELEMENT where it is still drawn, and that is the whole
2422
+ * reason the elevated card's rule is two rules. `--shadow-hairline` is `none`
2423
+ * in the light theme, and `none` is a value a shadow list may not carry:
2424
+ * `box-shadow: <shadow>, none` is invalid at computed-value time, so the
2425
+ * declaration is dropped and the light card loses the elevation the list was
2426
+ * built around. Alone on a pseudo element the same token is valid in both
2427
+ * themes, and it composes with the selection ring rather than replacing
2428
+ * whichever was declared last, exactly as the rail does.
2105
2429
  */
2106
- .crewlet-card--default:not(.crewlet-card--flush) {
2107
- box-shadow: var(--shadow-xs);
2108
- }
2109
-
2110
- .crewlet-card--default:not(.crewlet-card--flush)::after,
2111
2430
  .crewlet-card--elevated::after {
2112
2431
  content: '';
2113
2432
  position: absolute;
@@ -2122,8 +2441,9 @@
2122
2441
  }
2123
2442
 
2124
2443
  /*
2125
- * THE TILE: the panel's ground with none of its lift. One of many in a grid,
2126
- * where a shadow under every card turns a list of records into a relief map.
2444
+ * THE TILE: the card at the tile's tighter inset. One of many records in a
2445
+ * grid, where at the panel's own step each tile spends a third of its height
2446
+ * on air.
2127
2447
  *
2128
2448
  * It used to take the PAGE's ground, which is a card drawn in the colour of
2129
2449
  * the thing behind it: on the light palette a white tile on a white page, held
@@ -2250,9 +2570,14 @@
2250
2570
  box-shadow var(--motion-duration-base) var(--motion-easing-default);
2251
2571
  }
2252
2572
 
2573
+ /*
2574
+ * Under the pointer the hairline steps up and nothing lifts: a flat card that
2575
+ * rose on hover would be the one shadow on the screen, and it would move as
2576
+ * the pointer crossed a grid of them. The approved design's card answers the
2577
+ * pointer with its boundary alone.
2578
+ */
2253
2579
  .crewlet-card.is-interactive:hover {
2254
2580
  border-color: var(--color-border-hover);
2255
- box-shadow: var(--shadow-md);
2256
2581
  }
2257
2582
 
2258
2583
  .crewlet-card.is-interactive:focus-visible {
@@ -2514,9 +2839,9 @@
2514
2839
  }
2515
2840
 
2516
2841
 
2517
- /* Charts-D7G2BSXH.css */
2518
- /* The chart kit: a legend, a ranked bar list, a stacked bar and an activity
2519
- strip. Hand-drawn rather than a charting library, for one reason that
2842
+ /* Charts-B3YEF7R4.css */
2843
+ /* The chart kit: a legend, a ranked bar list, a stacked bar, stacked
2844
+ columns, an activity strip, a time series and the reading layer they share. Hand-drawn rather than a charting library, for one reason that
2520
2845
  decides it: every mark here reads tokens, in two themes, at the contrast
2521
2846
  floors the palette suite measures, and a library's theming surface is a
2522
2847
  second design system to keep in step with this one. */
@@ -2634,10 +2959,24 @@
2634
2959
  font-variant-numeric: tabular-nums;
2635
2960
  }
2636
2961
 
2962
+ /*
2963
+ * A BAR IS ROUNDED AT ITS VALUE END ONLY. The start is the baseline every row
2964
+ * shares, so it is square and the bars read as measured from one line; the end
2965
+ * is where the value is, and the smallest radius step marks it as an end
2966
+ * rather than a cut. The track is the scale at full length, so it takes the
2967
+ * same shape: a bar at the top of the scale is exactly the track.
2968
+ *
2969
+ * Written as LOGICAL corners, because the value end is the inline end: in a
2970
+ * right-to-left document the bars grow leftward and their value end is the
2971
+ * left one.
2972
+ */
2637
2973
  .crewlet-bar-list__track {
2638
2974
  display: block;
2639
2975
  height: 5px;
2640
- border-radius: var(--radius-pill);
2976
+ border-start-start-radius: 0;
2977
+ border-end-start-radius: 0;
2978
+ border-start-end-radius: var(--radius-xs);
2979
+ border-end-end-radius: var(--radius-xs);
2641
2980
  background: var(--color-surface-inset);
2642
2981
  overflow: hidden;
2643
2982
  }
@@ -2645,7 +2984,10 @@
2645
2984
  .crewlet-bar-list__bar {
2646
2985
  display: block;
2647
2986
  height: 100%;
2648
- border-radius: var(--radius-pill);
2987
+ border-start-start-radius: 0;
2988
+ border-end-start-radius: 0;
2989
+ border-start-end-radius: var(--radius-xs);
2990
+ border-end-end-radius: var(--radius-xs);
2649
2991
  background: var(--crewlet-bar-list-bar-color, var(--color-data-other));
2650
2992
  }
2651
2993
 
@@ -2685,97 +3027,495 @@
2685
3027
  white-space: nowrap;
2686
3028
  }
2687
3029
 
2688
- /* ─── Stacked bar ─────────────────────────────────────────────── */
2689
- .crewlet-stacked-bar__track {
2690
- display: flex;
2691
- height: 6px;
2692
- border-radius: var(--radius-pill);
2693
- background: var(--color-surface-inset);
2694
- overflow: hidden;
3030
+ /*
3031
+ * BESIDE: the design's ranked figure. The words in a column of their own, the
3032
+ * bar, and the value at the bar's end, one row 30px tall: the design's, and
3033
+ * the control step's, --size-control-md, so it follows the density. Two
3034
+ * component variables set its geometry, because both depend on what a screen
3035
+ * puts in it rather than on the kit:
3036
+ *
3037
+ * --crewlet-bar-list-label-width, the words' column (128px, the Home card's):
3038
+ * one width for every row, so the bars share one baseline.
3039
+ *
3040
+ * --crewlet-bar-list-value-room, what the scale keeps free at its end for the
3041
+ * value of the longest bar (6ch of tabular figures and the gap before them,
3042
+ * "412.3k"). The SCALE is the plot less that room, a bar is its share of the
3043
+ * scale, and the value follows the bar, so the longest bar's value stands in
3044
+ * the room and every shorter bar's value just past its own end.
3045
+ *
3046
+ * The bar is 12px thick, the design's, and square on its baseline with the
3047
+ * value end rounded, as the stacked register's is. It has no track: the
3048
+ * longest bar IS the end of the scale, and a track under the rest would be a
3049
+ * second baseline to read against.
3050
+ */
3051
+ .crewlet-bar-list--beside {
3052
+ --crewlet-bar-list-label-width: 128px;
3053
+ --crewlet-bar-list-value-room: calc(6ch + var(--spacing-2));
3054
+
3055
+ gap: calc(var(--spacing-1) * 1.5);
2695
3056
  }
2696
3057
 
2697
- .crewlet-stacked-bar__segment {
2698
- height: 100%;
2699
- background: var(--crewlet-stacked-bar-segment-color, var(--color-data-other));
3058
+ .crewlet-bar-list--beside .crewlet-bar-list__row {
3059
+ flex-direction: row;
3060
+ align-items: center;
3061
+ gap: var(--spacing-3);
3062
+ min-height: var(--size-control-md);
2700
3063
  }
2701
3064
 
2702
- /* ─── Activity strip ──────────────────────────────────────────── */
2703
- .crewlet-activity-strip {
3065
+ .crewlet-bar-list__names {
2704
3066
  display: flex;
2705
- align-items: flex-end;
2706
- gap: var(--crewlet-activity-strip-gap, 2px);
2707
- height: var(--crewlet-activity-strip-height, 26px);
2708
- width: 100%;
3067
+ flex: none;
3068
+ flex-direction: column;
3069
+ width: var(--crewlet-bar-list-label-width);
3070
+ min-width: 0;
3071
+ line-height: var(--font-line-height-tight);
2709
3072
  }
2710
3073
 
2711
- .crewlet-activity-strip__cell {
2712
- flex: 1;
2713
- min-width: var(--crewlet-activity-strip-cell-min-width, 2px);
2714
- height: var(--crewlet-activity-strip-fill, 10%);
2715
- /*
2716
- * A quarter of the smallest step. A cell is two pixels wide, so at the step
2717
- * itself every mark was a capsule and the strip read as a row of pills
2718
- * rather than as a shape.
2719
- */
2720
- border-radius: calc(var(--radius-xs) / 4);
2721
- /* An empty bucket is a neutral hairline: the bucket happened, and nothing
2722
- happened in it. That is a different fact from a quiet one, so it takes a
2723
- different colour rather than a fainter version of the same one. */
2724
- background: var(--color-border-default);
3074
+ .crewlet-bar-list--beside .crewlet-bar-list__label {
3075
+ flex: none;
3076
+ color: var(--color-text-secondary);
2725
3077
  }
2726
3078
 
2727
- .crewlet-activity-strip__cell.is-active {
2728
- background: var(--color-data-1);
3079
+ .crewlet-bar-list--beside .crewlet-bar-list__row--pressable:hover .crewlet-bar-list__label {
3080
+ color: var(--color-text-primary);
2729
3081
  }
2730
3082
 
2731
- /* ─── Time series, and the sparkline beside a number ──────────── */
2732
-
2733
- /*
2734
- * The plot fills the width it is given and does not clip: a line that touches
2735
- * the top of its own box is a peak, and a box that clipped it would silently
2736
- * flatten exactly the moment a reader is looking for.
2737
- */
2738
- .crewlet-time-series {
2739
- margin: 0;
3083
+ .crewlet-bar-list__plot {
3084
+ display: block;
3085
+ flex: 1 1 auto;
2740
3086
  min-width: 0;
2741
3087
  }
2742
3088
 
2743
- .crewlet-chart {
2744
- display: block;
2745
- width: 100%;
2746
- overflow: visible;
3089
+ .crewlet-bar-list__scale {
3090
+ display: flex;
3091
+ align-items: center;
3092
+ gap: var(--spacing-2);
3093
+ width: calc(100% - var(--crewlet-bar-list-value-room));
2747
3094
  }
2748
3095
 
2749
- /* The baseline: a hairline, because it is where the plot sits rather than
2750
- something to read. */
2751
- .crewlet-chart__axis-line {
2752
- stroke: var(--color-border-default);
2753
- stroke-width: 1;
3096
+ .crewlet-bar-list--beside .crewlet-bar-list__bar {
3097
+ flex: none;
3098
+ height: 12px;
2754
3099
  }
2755
3100
 
2756
- /*
2757
- * The grid is DASHED, which is what keeps three horizontal lines from reading
2758
- * as three series. They carry no values of their own: the peak under the plot
2759
- * is the scale, and a chart this size cannot label four gridlines legibly.
2760
- */
2761
- .crewlet-chart__grid-line {
2762
- stroke: var(--color-border-default);
2763
- stroke-width: 1;
2764
- stroke-dasharray: 2 4;
3101
+ /* What the row is, under its name at the micro step, as the design sets it:
3102
+ in a column 128px wide a caption at the list's own step wrapped a word. */
3103
+ .crewlet-bar-list--beside .crewlet-bar-list__sub {
3104
+ font-size: var(--font-size-2xs);
3105
+ }
3106
+
3107
+ /* The number the row is about: the primary ink, a step heavier than the name. */
3108
+ .crewlet-bar-list--beside .crewlet-bar-list__value {
3109
+ flex: none;
3110
+ color: var(--color-text-primary);
3111
+ font-size: var(--font-size-xs);
3112
+ font-weight: var(--font-weight-medium);
3113
+ white-space: nowrap;
3114
+ }
3115
+
3116
+ /* ─── Stacked bar ─────────────────────────────────────────────── */
3117
+
3118
+ /*
3119
+ * THE PARTS STAND 2PX APART. Butted together, two neighbouring hues meet at an
3120
+ * edge the eye reads as one mark in two colours; the gap is the ground showing
3121
+ * through, which is what makes each part a part. Two pixels, the approved
3122
+ * artboard's own, and not a spacing step, because it is a hairline of ground
3123
+ * rather than a space and a density setting must not widen it. Each part GROWS
3124
+ * by its value (a style property on the part), so the gaps come out of the
3125
+ * parts and the whole still fills the track exactly.
3126
+ *
3127
+ * The value end is rounded and the start is square, as a bar list's bar is.
3128
+ */
3129
+ .crewlet-stacked-bar__track {
3130
+ display: flex;
3131
+ gap: 2px;
3132
+ height: 6px;
3133
+ border-start-start-radius: 0;
3134
+ border-end-start-radius: 0;
3135
+ border-start-end-radius: var(--radius-xs);
3136
+ border-end-end-radius: var(--radius-xs);
3137
+ background: var(--color-surface-inset);
3138
+ overflow: hidden;
3139
+ }
3140
+
3141
+ .crewlet-stacked-bar__segment {
3142
+ flex-grow: 0;
3143
+ flex-shrink: 1;
3144
+ flex-basis: 0;
3145
+ min-width: 0;
3146
+ height: 100%;
3147
+ background: var(--crewlet-stacked-bar-segment-color, var(--color-data-other));
3148
+ }
3149
+
3150
+ /* ─── Stacked columns ─────────────────────────────────────────── */
3151
+
3152
+ /*
3153
+ * The scale's words stand in a column of their own at the start, sized by the
3154
+ * widest of them, and the time under the plot starts where the plot does.
3155
+ */
3156
+ .crewlet-stacked-columns {
3157
+ display: grid;
3158
+ grid-template-columns: auto minmax(0, 1fr);
3159
+ column-gap: var(--spacing-2);
3160
+ row-gap: var(--spacing-1);
3161
+ margin: 0;
3162
+ min-width: 0;
3163
+ }
3164
+
3165
+ /*
3166
+ * EACH WORD IS A BOX OF NO HEIGHT, spread from the top of the plot to its
3167
+ * baseline, with the word centred on it: so every word stands exactly on the
3168
+ * line it names, whatever the plot's height, with nothing measured.
3169
+ */
3170
+ .crewlet-stacked-columns__axis {
3171
+ display: flex;
3172
+ flex-direction: column;
3173
+ justify-content: space-between;
3174
+ align-items: flex-end;
3175
+ }
3176
+
3177
+ .crewlet-stacked-columns__tick {
3178
+ display: flex;
3179
+ align-items: center;
3180
+ height: 0;
3181
+ font-family: var(--font-family-mono);
3182
+ font-size: var(--font-size-2xs);
3183
+ color: var(--color-text-tertiary);
3184
+ font-variant-numeric: tabular-nums;
3185
+ white-space: nowrap;
3186
+ }
3187
+
3188
+ .crewlet-stacked-columns__plot {
3189
+ position: relative;
3190
+ display: flex;
3191
+ align-items: stretch;
3192
+ }
3193
+
3194
+ .crewlet-stacked-columns__grid {
3195
+ position: absolute;
3196
+ inset: 0;
3197
+ display: flex;
3198
+ flex-direction: column;
3199
+ justify-content: space-between;
3200
+ pointer-events: none;
3201
+ }
3202
+
3203
+ /* The scale's lines: hairlines, because they are where a value is read against
3204
+ rather than something to read. The last is the baseline. */
3205
+ .crewlet-stacked-columns__grid-line {
3206
+ display: block;
3207
+ height: 0;
3208
+ border-top: 1px solid var(--color-border-default);
3209
+ }
3210
+
3211
+ /*
3212
+ * A SLOT IS THE COLUMN'S WHOLE SHARE OF THE WIDTH, and the pointer's target:
3213
+ * the gaps between columns belong to a column, so the reading never drops out
3214
+ * as the pointer crosses one. The column stands in its middle at the approved
3215
+ * artboard's proportion, 14 of a 22.2 slot, and never wider than a finger's
3216
+ * worth, so a week of seven buckets does not draw seven slabs.
3217
+ */
3218
+ .crewlet-stacked-columns__slot {
3219
+ position: relative;
3220
+ display: flex;
3221
+ flex: 1 1 0;
3222
+ min-width: 0;
3223
+ align-items: flex-end;
3224
+ justify-content: center;
3225
+ border-radius: var(--radius-xs);
3226
+ }
3227
+
3228
+ .crewlet-stacked-columns__slot.is-active {
3229
+ background: var(--color-surface-hover);
3230
+ }
3231
+
3232
+ /*
3233
+ * THE COLUMN IS ITS TOTAL'S HEIGHT (a style property), and its parts share it
3234
+ * by value, first series at the baseline. They stand 2px apart for the reason
3235
+ * a stacked bar's do, and the gap comes out of the parts.
3236
+ */
3237
+ .crewlet-stacked-columns__column {
3238
+ display: flex;
3239
+ flex-direction: column-reverse;
3240
+ gap: 2px;
3241
+ width: 63%;
3242
+ max-width: var(--spacing-7);
3243
+ }
3244
+
3245
+ .crewlet-stacked-columns__segment {
3246
+ display: block;
3247
+ flex-grow: 0;
3248
+ flex-shrink: 1;
3249
+ flex-basis: 0;
3250
+ min-height: 0;
3251
+ background: var(--crewlet-stacked-columns-segment-color, var(--color-data-other));
3252
+ }
3253
+
3254
+ /* The VALUE END: the top of the topmost part, rounded at the smallest step.
3255
+ The foot stays square on the baseline every column shares. */
3256
+ .crewlet-stacked-columns__segment:last-child {
3257
+ border-top-left-radius: var(--radius-xs);
3258
+ border-top-right-radius: var(--radius-xs);
3259
+ }
3260
+
3261
+ .crewlet-stacked-columns__scale {
3262
+ position: relative;
3263
+ grid-column: 2;
3264
+ display: flex;
3265
+ justify-content: space-between;
3266
+ gap: var(--spacing-2);
3267
+ min-width: 0;
3268
+ font-size: var(--font-size-xs);
3269
+ color: var(--color-text-tertiary);
3270
+ font-variant-numeric: tabular-nums;
3271
+ }
3272
+
3273
+ /*
3274
+ * THE HEAD AND THE LEGEND span both of the figure's columns, the axis's and
3275
+ * the plot's. The head is one row: what the chart is at its start, and the
3276
+ * legend at its END, top right, where the design's Spend card draws it; the
3277
+ * legend is flushed to the end of that row and wraps from there. Below, the
3278
+ * legend starts under the axis, a step clear of the dates.
3279
+ */
3280
+ .crewlet-stacked-columns__head {
3281
+ grid-column: 1 / -1;
3282
+ display: flex;
3283
+ align-items: flex-start;
3284
+ gap: var(--spacing-4);
3285
+ margin-bottom: var(--spacing-3);
3286
+ min-width: 0;
3287
+ }
3288
+
3289
+ .crewlet-stacked-columns__heading {
3290
+ flex: 1 1 auto;
3291
+ min-width: 0;
3292
+ }
3293
+
3294
+ .crewlet-stacked-columns__legend--head {
3295
+ flex: 0 1 auto;
3296
+ justify-content: flex-end;
3297
+ margin-inline-start: auto;
3298
+ }
3299
+
3300
+ .crewlet-stacked-columns__legend--below {
3301
+ grid-column: 1 / -1;
3302
+ margin-top: var(--spacing-2);
3303
+ }
3304
+
3305
+ /* The middle label stands on the column it names (a style property). */
3306
+ .crewlet-stacked-columns__middle {
3307
+ position: absolute;
3308
+ top: 0;
3309
+ transform: translateX(-50%);
3310
+ white-space: nowrap;
3311
+ }
3312
+
3313
+ /* ─── The reading layer: a focusable plot and its tooltip ─────── */
3314
+
3315
+ /*
3316
+ * THE PLOT IS ONE TAB STOP, and the positioning context its tooltip stands in.
3317
+ * Its ring is drawn on `:focus-visible` only, so a keyboard reader sees it and
3318
+ * a click that focuses the plot on the way to a pointer reading draws none.
3319
+ */
3320
+ .crewlet-chart-frame {
3321
+ position: relative;
3322
+ min-width: 0;
3323
+ border-radius: var(--radius-xs);
3324
+ }
3325
+
3326
+ .crewlet-chart-frame:focus-visible {
3327
+ outline: 2px solid var(--color-focus);
3328
+ outline-offset: 2px;
3329
+ }
3330
+
3331
+ /*
3332
+ * The box stands beside the mark, at the top of the plot. Its one varying
3333
+ * value, `left`, is a style property on the element (see ChartTooltip); the
3334
+ * side it stands on is a class, and the gap between it and the mark is a step.
3335
+ * It never takes the pointer, so it can never steal the reading from the mark
3336
+ * under it.
3337
+ *
3338
+ * IT STANDS OVER THE DATA, BY DESIGN, and that decides its ground. A kit
3339
+ * Tooltip or Popover floats over interface; this one floats over the columns
3340
+ * next to the one being read and over the lines and areas of a time series. So
3341
+ * it is not the card: in the marketing palette the card is a 5% white wash,
3342
+ * and every data hue showed through it, taking the title to 1.12:1 and the
3343
+ * values to 2.77:1. It is the GLASS, frosted by --blur-sm, which the palette
3344
+ * suite holds every text step over 4.5:1 on in every palette with each data
3345
+ * hue, the residual and the inverse ground behind it (the inverse being the far
3346
+ * end of the palette from the glass, and so the worst backdrop anything can
3347
+ * put there). The hairline and the medium shadow are the kit's overlay edge,
3348
+ * and every word is a TEXT step.
3349
+ */
3350
+ .crewlet-chart-tooltip {
3351
+ position: absolute;
3352
+ top: 0;
3353
+ z-index: var(--z-index-raised);
3354
+ display: flex;
3355
+ flex-direction: column;
3356
+ gap: var(--spacing-1);
3357
+ min-width: 140px;
3358
+ max-width: 260px;
3359
+ padding: var(--spacing-2);
3360
+ background: var(--color-surface-glass);
3361
+ backdrop-filter: blur(var(--blur-sm));
3362
+ color: var(--color-text-primary);
3363
+ border: 1px solid var(--color-border-default);
3364
+ border-radius: var(--radius-md);
3365
+ box-shadow: var(--shadow-md);
3366
+ font-size: var(--font-size-xs);
3367
+ line-height: var(--font-line-height-snug);
3368
+ pointer-events: none;
3369
+ white-space: nowrap;
3370
+ }
3371
+
3372
+ .crewlet-chart-tooltip--after {
3373
+ transform: translateX(var(--spacing-2));
3374
+ }
3375
+
3376
+ .crewlet-chart-tooltip--before {
3377
+ transform: translateX(calc(-100% - var(--spacing-2)));
3378
+ }
3379
+
3380
+ .crewlet-chart-tooltip__title {
3381
+ margin: 0;
3382
+ color: var(--color-text-tertiary);
3383
+ }
3384
+
3385
+ .crewlet-chart-tooltip__rows {
3386
+ display: flex;
3387
+ flex-direction: column;
3388
+ gap: var(--spacing-1);
3389
+ margin: 0;
3390
+ padding: 0;
3391
+ list-style: none;
3392
+ }
3393
+
3394
+ .crewlet-chart-tooltip__row,
3395
+ .crewlet-chart-tooltip__total {
3396
+ display: flex;
3397
+ align-items: center;
3398
+ gap: var(--spacing-2);
3399
+ margin: 0;
3400
+ }
3401
+
3402
+ /* The key to the series: a swatch, drawn as the legend's is. It is the one
3403
+ place a data hue appears in the tooltip, and it is a mark, never a word. */
3404
+ .crewlet-chart-tooltip__swatch {
3405
+ width: 8px;
3406
+ height: 8px;
3407
+ flex: none;
3408
+ border-radius: calc(var(--radius-xs) / 2);
3409
+ background: var(--crewlet-chart-tooltip-swatch-color, var(--color-data-other));
3410
+ }
3411
+
3412
+ .crewlet-chart-tooltip__name {
3413
+ flex: 1;
3414
+ min-width: 0;
3415
+ color: var(--color-text-secondary);
3416
+ }
3417
+
3418
+ .crewlet-chart-tooltip__value {
3419
+ color: var(--color-text-primary);
3420
+ font-variant-numeric: tabular-nums;
3421
+ }
3422
+
3423
+ .crewlet-chart-tooltip__total {
3424
+ padding-top: var(--spacing-1);
3425
+ border-top: 1px solid var(--color-border-default);
3426
+ }
3427
+
3428
+ .crewlet-chart-tooltip__total .crewlet-chart-tooltip__value {
3429
+ font-weight: var(--font-weight-semibold);
3430
+ }
3431
+
3432
+ /* ─── Activity strip ──────────────────────────────────────────── */
3433
+ .crewlet-activity-strip {
3434
+ display: flex;
3435
+ align-items: flex-end;
3436
+ gap: var(--crewlet-activity-strip-gap, 2px);
3437
+ height: var(--crewlet-activity-strip-height, 26px);
3438
+ width: 100%;
3439
+ }
3440
+
3441
+ .crewlet-activity-strip__cell {
3442
+ flex: 1;
3443
+ min-width: var(--crewlet-activity-strip-cell-min-width, 2px);
3444
+ height: var(--crewlet-activity-strip-fill, 10%);
3445
+ /*
3446
+ * A quarter of the smallest step. A cell is two pixels wide, so at the step
3447
+ * itself every mark was a capsule and the strip read as a row of pills
3448
+ * rather than as a shape.
3449
+ */
3450
+ border-radius: calc(var(--radius-xs) / 4);
3451
+ /* An empty bucket is a neutral hairline: the bucket happened, and nothing
3452
+ happened in it. That is a different fact from a quiet one, so it takes a
3453
+ different colour rather than a fainter version of the same one. */
3454
+ background: var(--color-border-default);
3455
+ }
3456
+
3457
+ .crewlet-activity-strip__cell.is-active {
3458
+ background: var(--color-data-1);
3459
+ }
3460
+
3461
+ /* ─── Time series, and the sparkline beside a number ──────────── */
3462
+
3463
+ /*
3464
+ * The plot fills the width it is given and does not clip: a line that touches
3465
+ * the top of its own box is a peak, and a box that clipped it would silently
3466
+ * flatten exactly the moment a reader is looking for.
3467
+ */
3468
+ .crewlet-time-series {
3469
+ margin: 0;
3470
+ min-width: 0;
3471
+ }
3472
+
3473
+ .crewlet-chart {
3474
+ display: block;
3475
+ width: 100%;
3476
+ overflow: visible;
3477
+ }
3478
+
3479
+ /* The baseline: a hairline, because it is where the plot sits rather than
3480
+ something to read. */
3481
+ .crewlet-chart__axis-line {
3482
+ stroke: var(--color-border-default);
3483
+ stroke-width: 1;
3484
+ }
3485
+
3486
+ /*
3487
+ * The grid is DASHED, which is what keeps three horizontal lines from reading
3488
+ * as three series. They carry no values of their own: the peak under the plot
3489
+ * is the scale, and a chart this size cannot label four gridlines legibly.
3490
+ */
3491
+ .crewlet-chart__grid-line {
3492
+ stroke: var(--color-border-default);
3493
+ stroke-width: 1;
3494
+ stroke-dasharray: 2 4;
2765
3495
  }
2766
3496
 
2767
3497
  /*
2768
3498
  * The series line. It is painted with the colour passed on the element,
2769
3499
  * because a series' hue is data rather than style; the shape of the stroke is
2770
- * the one thing that is the same for all of them.
3500
+ * the one thing that is the same for all of them. Two pixels, which is what a
3501
+ * line a reader follows across a plot is drawn at; a sparkline's quieter
3502
+ * stroke is its own, below.
2771
3503
  */
2772
3504
  .crewlet-chart__series {
2773
3505
  fill: none;
2774
- stroke-width: 1.75;
3506
+ stroke-width: 2;
2775
3507
  stroke-linejoin: round;
2776
3508
  stroke-linecap: round;
2777
3509
  }
2778
3510
 
3511
+ /* The reading's crosshair: a hairline in the strong border, from the top of
3512
+ the plot to its baseline, on the instant being read. */
3513
+ .crewlet-chart__crosshair {
3514
+ stroke: var(--color-border-strong);
3515
+ stroke-width: 1;
3516
+ pointer-events: none;
3517
+ }
3518
+
2779
3519
  /* The window's two ends and its peak, under the plot: the scale, as words. */
2780
3520
  .crewlet-time-series__scale {
2781
3521
  display: flex;
@@ -2787,14 +3527,64 @@
2787
3527
  font-variant-numeric: tabular-nums;
2788
3528
  }
2789
3529
 
3530
+ /*
3531
+ * THE SPARKLINE: the plot stretched to the box, and, with `current`, one
3532
+ * accent point on the last value.
3533
+ *
3534
+ * The point is the approved design's: an accent disc 5px across, cut out of
3535
+ * the ground by a 2px ring in that ground's colour, so where the line runs
3536
+ * into it the line stops a ring short of the disc rather than crossing it.
3537
+ * The ring is `--crewlet-spark-ground`, the CARD, because a sparkline stands
3538
+ * beside a number on a card; one on another rung sets the variable.
3539
+ *
3540
+ * THE PLOT GIVES UP ITS END TO THE POINT. With a point, the box keeps the
3541
+ * disc's half and its ring back at its inline end, so the whole point stands
3542
+ * inside the box beside whatever follows it, and the line's last value lands
3543
+ * exactly under the disc's centre.
3544
+ */
2790
3545
  .crewlet-spark {
3546
+ --crewlet-spark-ground: var(--color-surface-subtle);
3547
+ --crewlet-spark-point: 5px;
3548
+ --crewlet-spark-ring: 2px;
3549
+
3550
+ position: relative;
3551
+ display: block;
3552
+ box-sizing: border-box;
3553
+ width: 100%;
3554
+ overflow: visible;
3555
+ }
3556
+
3557
+ .crewlet-spark__plot {
2791
3558
  display: block;
2792
3559
  width: 100%;
3560
+ height: 100%;
2793
3561
  overflow: visible;
2794
3562
  }
2795
3563
 
3564
+ /* A shape beside a number is drawn quieter than a plot's line: the approved
3565
+ design's 1.75 stroke, under the 2 a line across a plot takes. */
3566
+ .crewlet-spark__plot .crewlet-chart__series {
3567
+ stroke-width: 1.75;
3568
+ }
3569
+
3570
+ .crewlet-spark--current {
3571
+ padding-inline-end: calc(var(--crewlet-spark-point) / 2 + var(--crewlet-spark-ring));
3572
+ }
3573
+
3574
+ .crewlet-spark__current {
3575
+ position: absolute;
3576
+ inset-inline-end: var(--crewlet-spark-ring);
3577
+ width: var(--crewlet-spark-point);
3578
+ height: var(--crewlet-spark-point);
3579
+ border-radius: var(--radius-circle);
3580
+ background: var(--color-brand-accent);
3581
+ box-shadow: 0 0 0 var(--crewlet-spark-ring) var(--crewlet-spark-ground);
3582
+ transform: translateY(-50%);
3583
+ pointer-events: none;
3584
+ }
3585
+
2796
3586
 
2797
- /* Checkbox-VGW26YLQ.css */
3587
+ /* Checkbox-BOXQ747I.css */
2798
3588
  /*
2799
3589
  * Checkbox: a box, its label and its consequence as one target.
2800
3590
  *
@@ -2841,8 +3631,8 @@
2841
3631
  flex: 0 0 auto;
2842
3632
  /*
2843
3633
  * THE TICK IS THE ACCENT, which is what "here, this one" means everywhere
2844
- * else in the system. It used to read --color-brand-primary, which is white
2845
- * in the dark theme: a white tick on a white box.
3634
+ * else in the system. It used to read the monochrome brand fill, which was
3635
+ * white in the dark theme: a white tick on a white box.
2846
3636
  */
2847
3637
  accent-color: var(--color-brand-accent);
2848
3638
  cursor: pointer;
@@ -3182,15 +3972,16 @@
3182
3972
  }
3183
3973
 
3184
3974
 
3185
- /* CommandPalette-CSJDUCQA.css */
3975
+ /* CommandPalette-C5AMKGN2.css */
3186
3976
  /*
3187
- * The command palette: a field, a list, and a line of keyboard hints.
3977
+ * The command palette: a field, an optional row of scopes, one scroller
3978
+ * holding the lead and the list, and a key legend.
3188
3979
  *
3189
- * It is a Modal with its body's padding dropped, so the three bands run edge to
3190
- * edge and the field reads as the surface rather than as a question on a form.
3980
+ * It is a Modal with its body's padding dropped, so the bands run edge to edge
3981
+ * and the field reads as the surface rather than as a question on a form.
3191
3982
  * The rows are the listbox register (`Listbox.css`), because a result here and
3192
- * a completion in a field are the same thing to a reader and the accent that
3193
- * marks the active row has to mean the same in both.
3983
+ * a completion in a field are the same thing to a reader and the raised row
3984
+ * that marks the active one has to mean the same in both.
3194
3985
  *
3195
3986
  * THE TWO OVERRIDES BELOW NAME BOTH CLASSES ON PURPOSE. A single class would
3196
3987
  * tie with the rule it is overriding (`.crewlet-modal--md`,
@@ -3199,11 +3990,17 @@
3199
3990
  */
3200
3991
 
3201
3992
  .crewlet-modal.crewlet-palette {
3202
- /* Wider than a prompt and shorter than the window: a launcher is read in one
3203
- glance, and a list taller than this is a list nobody scans. */
3204
- --crewlet-modal-width: 620px;
3993
+ /*
3994
+ * THE APPROVED DESIGN'S SURFACE: 720px wide, and as tall as its artboard
3995
+ * draws it with an answer leading five rows, 664px of a 900px window. It was
3996
+ * 620 by min(60dvh, 520px), sized for a list alone, and a lead that size
3997
+ * over it left room for three rows. 74dvh is that artboard's 664/900; the
3998
+ * 680px cap is the same surface with one more row, so a tall window does
3999
+ * not turn a launcher read in one glance into a page.
4000
+ */
4001
+ --crewlet-modal-width: 720px;
3205
4002
 
3206
- max-height: min(60dvh, 520px);
4003
+ max-height: min(74dvh, 680px);
3207
4004
  }
3208
4005
 
3209
4006
  /*
@@ -3227,10 +4024,18 @@
3227
4024
  * than at a control's. It is the first thing on the surface and the only thing
3228
4025
  * with focus, so it is the surface's headline as much as its input.
3229
4026
  */
4027
+ /*
4028
+ * THE ROW'S TWO ENDS ARE INSET ONE STEP LESS THAN THE BANDS BELOW IT. The
4029
+ * search glyph and the Esc keycap each carry a slot inset of their own (the
4030
+ * glyph's, a step less than text's, see Input.css), so at the bands' 16px the
4031
+ * glyph stood 24px in and the keycap 28px from the edge; at 12px they stand
4032
+ * 20px and 16px in, where the approved palette draws them, and the query still
4033
+ * starts on the line the design's does.
4034
+ */
3230
4035
  .crewlet-input.crewlet-palette__field {
3231
4036
  flex-shrink: 0;
3232
4037
  min-height: var(--size-row-lg);
3233
- padding-inline: var(--spacing-4);
4038
+ padding-inline: var(--spacing-3);
3234
4039
  border: none;
3235
4040
  border-bottom: 1px solid var(--color-border-default);
3236
4041
  border-radius: 0;
@@ -3241,6 +4046,10 @@
3241
4046
  font-size: var(--font-size-md);
3242
4047
  }
3243
4048
 
4049
+ .crewlet-input.crewlet-palette__field .crewlet-input__trailing {
4050
+ padding-right: var(--spacing-1);
4051
+ }
4052
+
3244
4053
  /*
3245
4054
  * THE FOOT IS THE KEYBOARD'S OWN BAND, at the micro register rather than the
3246
4055
  * modal footer's. A modal's foot carries buttons and is sized for them; this
@@ -3252,15 +4061,73 @@
3252
4061
  * the stylesheets are concatenated in.
3253
4062
  */
3254
4063
  .crewlet-palette .crewlet-modal__footer {
3255
- gap: var(--spacing-3);
3256
- padding: var(--spacing-2) var(--spacing-3);
4064
+ gap: var(--spacing-4);
4065
+ padding: var(--spacing-2) var(--spacing-4);
4066
+ /* The SHEET rung under the card the results sit on, as the design draws the
4067
+ legend: a band a step back from the surface, so it reads as the frame's
4068
+ edge rather than as one more row. */
4069
+ background: var(--color-surface-background);
3257
4070
  }
3258
4071
 
3259
4072
  .crewlet-palette .crewlet-modal__footer-start {
3260
- gap: var(--spacing-3);
3261
- font-size: var(--font-size-2xs);
4073
+ gap: var(--spacing-4);
4074
+ font-size: var(--font-size-xs);
4075
+ }
4076
+
4077
+ /*
4078
+ * THE SCOPES: a strip of words under the field, the current one in the primary
4079
+ * ink over a bar in the same ink. Not `Tabs`, whose tabs are a roving tab stop:
4080
+ * these are never focused (the field drives them), so the row has no ring to
4081
+ * draw and no slider to measure, and the bar is each tab's own edge.
4082
+ */
4083
+ .crewlet-palette__scopes {
4084
+ flex-shrink: 0;
4085
+ display: flex;
4086
+ align-items: stretch;
4087
+ gap: var(--spacing-4);
4088
+ min-height: var(--size-row-md);
4089
+ padding-inline: var(--spacing-4);
4090
+ border-bottom: 1px solid var(--color-border-default);
4091
+ overflow-x: auto;
4092
+ scrollbar-width: none;
4093
+ }
4094
+
4095
+ .crewlet-palette__scopes::-webkit-scrollbar {
4096
+ display: none;
4097
+ }
4098
+
4099
+ .crewlet-palette__scope {
4100
+ flex: none;
4101
+ display: inline-flex;
4102
+ align-items: center;
4103
+ gap: var(--spacing-2);
4104
+ padding: 0 var(--spacing-1);
4105
+ border: none;
4106
+ /* The bar is drawn on every tab and coloured only on the chosen one, so a
4107
+ choice moves no label by the bar's width. */
4108
+ border-bottom: 2px solid transparent;
4109
+ background: none;
4110
+ color: var(--color-text-tertiary);
4111
+ font: inherit;
4112
+ font-size: var(--font-size-xs);
4113
+ font-weight: var(--font-weight-medium);
4114
+ white-space: nowrap;
4115
+ cursor: pointer;
4116
+ }
4117
+
4118
+ .crewlet-palette__scope:hover,
4119
+ .crewlet-palette__scope.is-active {
4120
+ color: var(--color-text-primary);
3262
4121
  }
3263
4122
 
4123
+ .crewlet-palette__scope.is-active {
4124
+ border-bottom-color: var(--color-text-primary);
4125
+ }
4126
+
4127
+ /*
4128
+ * THE ONE SCROLLER: the lead and the list move together, and the listbox
4129
+ * keeps the highlighted row in view inside this element.
4130
+ */
3264
4131
  .crewlet-palette__results {
3265
4132
  flex: 1 1 auto;
3266
4133
  min-height: 0;
@@ -3269,24 +4136,75 @@
3269
4136
  padding: var(--spacing-1);
3270
4137
  }
3271
4138
 
4139
+ /*
4140
+ * THE LEAD: an answer on the raised rung above the rows, in the secondary ink
4141
+ * at a reading leading, because it is prose read once rather than a row run
4142
+ * past. Empty, it draws nothing: the region is mounted so a screen reader sees
4143
+ * its first words arrive, and an empty box would be a band saying nothing.
4144
+ */
4145
+ .crewlet-palette__lead:not(:empty) {
4146
+ display: flex;
4147
+ flex-direction: column;
4148
+ gap: var(--spacing-2);
4149
+ margin: var(--spacing-2) var(--spacing-3) var(--spacing-1);
4150
+ padding: var(--spacing-3) var(--spacing-4);
4151
+ border-radius: var(--radius-lg);
4152
+ background: var(--color-surface-elevated);
4153
+ color: var(--color-text-secondary);
4154
+ line-height: var(--font-line-height-relaxed);
4155
+ }
4156
+
3272
4157
  /*
3273
4158
  * The glyph takes the ROW'S colour rather than a quiet step of its own, so the
3274
- * row under the arrows turns accent in one piece. Pinned to the tertiary step
3275
- * it stayed grey inside the highlight, which read as a glyph that had failed
3276
- * to load.
4159
+ * row under the arrows lifts to the primary ink in one piece. Pinned to the
4160
+ * tertiary step it stayed grey inside the highlight, which read as a glyph
4161
+ * that had failed to load.
3277
4162
  */
3278
4163
  .crewlet-palette__icon {
3279
4164
  display: inline-flex;
3280
4165
  flex-shrink: 0;
3281
4166
  }
3282
4167
 
3283
- .crewlet-palette__label {
4168
+ /*
4169
+ * THE LABEL AND ITS HINT ARE ONE LINE, cut together: the hint reads as the
4170
+ * rest of the label's sentence ("ENG-420 Flaky e2e, Todo, unassigned"), and
4171
+ * the row's end is kept for its meta. A hint pushed to the end as well would
4172
+ * put two quiet columns side by side, and neither would say which it was.
4173
+ */
4174
+ .crewlet-palette__text {
4175
+ flex: 1 1 auto;
3284
4176
  min-width: 0;
3285
4177
  overflow: hidden;
3286
4178
  text-overflow: ellipsis;
3287
4179
  white-space: nowrap;
3288
4180
  }
3289
4181
 
4182
+ .crewlet-palette__label {
4183
+ font-weight: var(--font-weight-medium);
4184
+ }
4185
+
4186
+ /* The quiet ink on every row, the highlighted one included, as the approved
4187
+ palette draws it: the rest of the label's sentence, a step under the label
4188
+ it follows. The tertiary step clears 4.5:1 on the raised row as on the card,
4189
+ so the highlight has no reason to lift it. */
4190
+ .crewlet-palette__hint {
4191
+ color: var(--color-text-tertiary);
4192
+ }
4193
+
4194
+ /*
4195
+ * The row's end: a short fact or an accelerator's keycap. Never cut and never
4196
+ * wrapped, so a column of keycaps stands in one line down the list.
4197
+ */
4198
+ .crewlet-palette__meta {
4199
+ display: inline-flex;
4200
+ flex-shrink: 0;
4201
+ align-items: center;
4202
+ margin-left: auto;
4203
+ color: var(--color-text-tertiary);
4204
+ font-size: var(--font-size-xs);
4205
+ white-space: nowrap;
4206
+ }
4207
+
3290
4208
  /*
3291
4209
  * An honest empty state: it says which kind of nothing this is, and the
3292
4210
  * component takes the sentence from the caller for that reason.
@@ -3299,6 +4217,22 @@
3299
4217
  text-align: center;
3300
4218
  }
3301
4219
 
4220
+ /*
4221
+ * FORCED COLORS draws a transparent border in the system's own ink, so every
4222
+ * scope would wear the chosen one's bar. The bar is kept where it means
4223
+ * something and painted out everywhere else, in the two colours the mode
4224
+ * leaves as the author wrote them.
4225
+ */
4226
+ @media (forced-colors: active) {
4227
+ .crewlet-palette__scope {
4228
+ border-bottom-color: Canvas;
4229
+ }
4230
+
4231
+ .crewlet-palette__scope.is-active {
4232
+ border-bottom-color: CanvasText;
4233
+ }
4234
+ }
4235
+
3302
4236
 
3303
4237
  /* Container-3TSKMGNI.css */
3304
4238
  /*
@@ -3506,7 +4440,7 @@
3506
4440
  }
3507
4441
 
3508
4442
 
3509
- /* DataTable-37UWTRN6.css */
4443
+ /* DataTable-OLHPF7D4.css */
3510
4444
  /* ─────────────────────────────────────────────────────────────────
3511
4445
  * Default variant.
3512
4446
  *
@@ -4776,7 +5710,7 @@ body.crewlet-data-table-resizing {
4776
5710
  display: inline-block;
4777
5711
  height: var(--spacing-3);
4778
5712
  border-radius: var(--radius-xs);
4779
- background: var(--color-surface-elevated, var(--color-surface-muted));
5713
+ background: var(--color-surface-elevated);
4780
5714
  animation: crewlet-data-table-skeleton-pulse var(--crewlet-data-table-skeleton-duration) var(--motion-easing-in-out) infinite;
4781
5715
  vertical-align: middle;
4782
5716
  }
@@ -5482,58 +6416,55 @@ body.crewlet-data-table-resizing {
5482
6416
  The component states its own, rather than leaning on the document
5483
6417
  baseline: this stylesheet also ships to an application that imports the
5484
6418
  component and not the baseline. The skeleton stops PULSING and keeps its
5485
- bars, which is what says the rows have not arrived.
5486
-
5487
- THE SETTINGS FRAME IS NAMED SEPARATELY BECAUSE IT IS NOT IN THE TABLE. It
5488
- is a Modal, which portals onto the layer host, so a descendant selector
5489
- rooted at .crewlet-data-table reaches none of it: the chip row and every
5490
- column row kept their transitions under the preference in exactly the
5491
- application this rule exists for. */
5492
- /*
5493
- * EVERY PART OF THE TABLE, INCLUDING THE ONES DRAWN SOMEWHERE ELSE. The list
5494
- * is not the root and its descendants: two of these live in the settings
5495
- * frame, which is a dialog portaled to the layer host, and the chrome row is
5496
- * drawn on a card's header wherever the table fills one. A preference
5497
- * cancelled through the root alone leaves exactly those pieces animating,
5498
- * which is the one place a reader who asked for stillness is least able to
5499
- * connect it back to a table.
6419
+ bars, which is what says the rows have not arrived. */
6420
+ /*
6421
+ * EVERY MOTION THIS FILE STARTS IS STOPPED BY NAME, the same selector as the
6422
+ * rule that starts it and after it, so the two tie on specificity and the stop
6423
+ * wins on source order. The package's literal check holds the pairing
6424
+ * selector for selector.
6425
+ *
6426
+ * A CATCH-ALL IS WHAT THIS REPLACED, and it lost twice. Written as
6427
+ * `.crewlet-data-table *` it was one class against rules of two, so the row
6428
+ * hover, the sort control, the action button and the pager and cog all kept
6429
+ * their transitions; doubled to `.crewlet-data-table.crewlet-data-table *` it
6430
+ * was two classes, and the row's own rule is two classes AND two elements
6431
+ * (`… tbody tr`), so the row still eased its hover for a reader who had asked
6432
+ * for stillness. The document-wide rule in @crewlethq/tokens covers every
6433
+ * one of them with `!important` wherever that sheet is loaded, which is the
6434
+ * only reason nobody saw it.
6435
+ *
6436
+ * Naming the rules also reaches the pieces a descendant selector cannot: the
6437
+ * page-size and column rows are in the settings frame, a Modal portaled onto
6438
+ * the layer host, and the chrome row is drawn on a card's header wherever the
6439
+ * table fills one.
5500
6440
  */
5501
6441
  @media (prefers-reduced-motion: reduce) {
5502
- /*
5503
- * EACH NAME IS WRITTEN TWICE, which is not a typo: a selector repeating one
5504
- * class matches exactly what it matched and counts for twice as much. A
5505
- * cancellation is only a cancellation if it outranks what it cancels, and
5506
- * this one did not: written once, `.crewlet-data-table *` is one class where
5507
- * the rules it had to beat are two, so the row hover, the sort control, the
5508
- * action button and the pager and cog all kept their transitions for a
5509
- * reader who had asked for stillness. The document-wide rule in
5510
- * @crewlethq/tokens covered it with `!important` wherever that sheet is
5511
- * loaded, which is the only reason nobody saw it; this rule exists for the
5512
- * document that loads the components alone, and it has to stand on its own.
5513
- */
5514
- .crewlet-data-table.crewlet-data-table,
5515
- .crewlet-data-table.crewlet-data-table *,
5516
- .crewlet-data-table.crewlet-data-table *::before,
5517
- .crewlet-data-table.crewlet-data-table *::after,
5518
- .crewlet-data-table__chrome.crewlet-data-table__chrome,
5519
- .crewlet-data-table__chrome.crewlet-data-table__chrome *,
5520
- .crewlet-data-table__chrome.crewlet-data-table__chrome *::before,
5521
- .crewlet-data-table__chrome.crewlet-data-table__chrome *::after,
5522
- .crewlet-data-table__items-per-page-btn.crewlet-data-table__items-per-page-btn,
5523
- .crewlet-data-table__column-toggle-item.crewlet-data-table__column-toggle-item {
5524
- animation: none;
6442
+ .crewlet-data-table--default .crewlet-data-table__table tbody tr,
6443
+ .crewlet-data-table--default .crewlet-data-table__th--sortable,
6444
+ .crewlet-data-table--default .crewlet-data-table__sort-icon,
6445
+ .crewlet-data-table--default .crewlet-data-table__action-btn,
6446
+ .crewlet-data-table--default .crewlet-data-table__header-btn,
6447
+ .crewlet-data-table__items-per-page-btn,
6448
+ .crewlet-data-table__column-toggle-item,
6449
+ .crewlet-data-table__chrome .crewlet-data-table__page-btn,
6450
+ .crewlet-data-table__chrome .crewlet-data-table__settings-btn,
6451
+ .crewlet-data-table__expand-all-btn,
6452
+ .crewlet-data-table__chevron,
6453
+ .crewlet-data-table__resizer::before,
6454
+ .crewlet-data-table__copy-cell-button {
5525
6455
  transition: none;
5526
6456
  }
5527
6457
 
5528
6458
  /* The bars stay; only the pulse goes. A skeleton that vanished under a
5529
6459
  motion preference would take the answer to "has this loaded" with it. */
5530
6460
  .crewlet-data-table__skeleton-bar {
6461
+ animation: none;
5531
6462
  opacity: 0.6;
5532
6463
  }
5533
6464
  }
5534
6465
 
5535
6466
 
5536
- /* DataView-256YF32J.css */
6467
+ /* DataView-N6JX464S.css */
5537
6468
  /*
5538
6469
  * The list screen: header, toolbar, filter chips, table.
5539
6470
  *
@@ -5718,10 +6649,11 @@ body.crewlet-data-table-resizing {
5718
6649
  * and without the boundary a reader reads them as a row of the table's own.
5719
6650
  *
5720
6651
  * A SOLID HAIRLINE. The fence was dashed, and a dashed edge MEANS SOMETHING
5721
- * ELSE here: it is the mark a card or a node wears when it stands for somebody
5722
- * outside the system, on the canvas and in every chart. Two meanings for one
5723
- * stroke is how a reader learns neither. Every boundary in this system is the
5724
- * same hairline; what differs is where it is drawn.
6652
+ * ELSE here: it marks a place nothing fills yet, an empty card slot, a unit
6653
+ * with no lead, the ghost of a node being added. A fence round chips that are
6654
+ * there is not one of those, and two meanings for one stroke is how a reader
6655
+ * learns neither. Every boundary in this system is the same hairline; what
6656
+ * differs is where it is drawn.
5725
6657
  */
5726
6658
  .crewlet-filter-axis-bar {
5727
6659
  display: flex;
@@ -6675,7 +7607,7 @@ svg.crewlet-datetime__chevron {
6675
7607
  }
6676
7608
 
6677
7609
 
6678
- /* ErrorBoundary-ME36CQTA.css */
7610
+ /* ErrorBoundary-U2PA3LY2.css */
6679
7611
  /*
6680
7612
  * The default fallback: a quiet block on the inset surface rather than a red
6681
7613
  * panel. A screen that failed to draw is not an error the reader made, and a
@@ -6688,14 +7620,14 @@ svg.crewlet-datetime__chevron {
6688
7620
  flex-direction: column;
6689
7621
  align-items: flex-start;
6690
7622
  gap: var(--spacing-3);
6691
- /* The panel's own body inset and its lift: a fallback is still a panel of
6692
- the product, and one drawn without the rim read as a block of unstyled
6693
- text where the screen should have been. */
7623
+ /* The card's own recipe and its body inset: a fallback is still a panel of
7624
+ the product, and one drawn without the card's ground and hairline read as
7625
+ a block of unstyled text where the screen should have been. Flat, as
7626
+ every card is. */
6694
7627
  padding: var(--spacing-4);
6695
7628
  border: 1px solid var(--color-border-default);
6696
7629
  border-radius: var(--radius-lg);
6697
7630
  background: var(--color-surface-subtle);
6698
- box-shadow: var(--shadow-xs), var(--shadow-hairline);
6699
7631
  max-width: var(--size-measure);
6700
7632
  }
6701
7633
 
@@ -6896,7 +7828,7 @@ svg.crewlet-datetime__chevron {
6896
7828
  }
6897
7829
 
6898
7830
 
6899
- /* IconButton-VQGNMJDI.css */
7831
+ /* IconButton-TVEUWK6L.css */
6900
7832
  /*
6901
7833
  * IconButton: a square icon-only control.
6902
7834
  *
@@ -6987,13 +7919,13 @@ svg.crewlet-datetime__chevron {
6987
7919
  */
6988
7920
  .crewlet-icon-btn--secondary {
6989
7921
  background: var(--color-surface-subtle);
6990
- border-color: var(--color-border-default);
7922
+ border-color: var(--color-border-strong);
6991
7923
  color: var(--color-text-primary);
6992
7924
  }
6993
7925
 
6994
7926
  .crewlet-icon-btn--secondary:hover:not(:disabled):not([aria-disabled='true']) {
6995
7927
  background: var(--color-surface-elevated);
6996
- border-color: var(--color-border-hover);
7928
+ border-color: var(--color-border-strong-hover);
6997
7929
  }
6998
7930
 
6999
7931
  .crewlet-icon-btn--secondary:active:not(:disabled):not([aria-disabled='true']) {
@@ -7057,7 +7989,7 @@ svg.crewlet-datetime__chevron {
7057
7989
  }
7058
7990
 
7059
7991
 
7060
- /* ImageUpload-HKFIZR6D.css */
7992
+ /* ImageUpload-YCHJMUGX.css */
7061
7993
  /*
7062
7994
  * ImageUpload, the click-to-upload affordance built on Avatar.
7063
7995
  *
@@ -7077,10 +8009,11 @@ svg.crewlet-datetime__chevron {
7077
8009
  of the six places that read it: a fallback repeated six times is six
7078
8010
  places for the default to drift apart. */
7079
8011
  --crewlet-image-upload-size: 64px;
7080
- /* The corner that box takes, set per instance beside the size. Declared here
7081
- for the same reason the size is: a default repeated as a var() fallback at
7082
- each place that reads it is several places for one default to drift. */
7083
- --crewlet-image-upload-corner: var(--radius-lg);
8012
+ /* The corner that box takes, set per instance beside the size from Avatar's
8013
+ own `avatarCorner`, which is the one statement of the ladder a script can
8014
+ read. There is deliberately NO default here: the only right value is a
8015
+ proportion of the size, and a stylesheet can only restate that proportion,
8016
+ which is how the trigger and the picture under it came apart before. */
7084
8017
  position: relative;
7085
8018
  display: inline-flex;
7086
8019
  flex-shrink: 0;
@@ -7100,21 +8033,34 @@ svg.crewlet-datetime__chevron {
7100
8033
  cursor: pointer;
7101
8034
  }
7102
8035
 
7103
- /* Shape modifiers keep the trigger, the overlay and the Avatar corners in step. */
7104
- .crewlet-image-upload--circle .crewlet-image-upload__trigger,
7105
- .crewlet-image-upload--circle .crewlet-image-upload__overlay {
8036
+ /* The kind modifiers keep the trigger, the overlay and the Avatar outlines in
8037
+ step. A person's picture is a circle. */
8038
+ .crewlet-image-upload--human .crewlet-image-upload__trigger,
8039
+ .crewlet-image-upload--human .crewlet-image-upload__overlay {
7106
8040
  border-radius: var(--radius-circle);
7107
8041
  }
7108
8042
 
7109
8043
  /* THE SAME CORNER THE PICTURE INSIDE TAKES, which is why it is a variable
7110
- rather than a step: Avatar moves a square badge's radius with its box, so a
8044
+ rather than a step: Avatar moves an agent badge's corner with its box, so a
7111
8045
  trigger pinned to one step is rounder or squarer than the badge under it at
7112
8046
  every size but one, and the badge's corners show through the overlay. */
7113
- .crewlet-image-upload--square .crewlet-image-upload__trigger,
7114
- .crewlet-image-upload--square .crewlet-image-upload__overlay {
8047
+ .crewlet-image-upload--agent .crewlet-image-upload__trigger,
8048
+ .crewlet-image-upload--agent .crewlet-image-upload__overlay {
7115
8049
  border-radius: var(--crewlet-image-upload-corner);
7116
8050
  }
7117
8051
 
8052
+ /* AND THE SAME SQUIRCLE, where the browser draws one, for the same reason:
8053
+ Avatar.css states why its squircle is a whole one at the circle token, and
8054
+ this is that rule for the two frames over the picture. The suite holds the
8055
+ two blocks to one declaration list. */
8056
+ @supports (corner-shape: squircle) {
8057
+ .crewlet-image-upload--agent .crewlet-image-upload__trigger,
8058
+ .crewlet-image-upload--agent .crewlet-image-upload__overlay {
8059
+ corner-shape: squircle;
8060
+ border-radius: var(--radius-circle);
8061
+ }
8062
+ }
8063
+
7118
8064
  .crewlet-image-upload__trigger:disabled {
7119
8065
  cursor: default;
7120
8066
  }
@@ -7940,21 +8886,26 @@ svg.crewlet-datetime__chevron {
7940
8886
  }
7941
8887
 
7942
8888
 
7943
- /* Kbd-W66MXQI5.css */
7944
- /* A keycap: the key's name on a small raised tile. */
8889
+ /* Kbd-JPLDVJIP.css */
8890
+ /*
8891
+ * A keycap: the key's name on a small raised tile.
8892
+ *
8893
+ * THE APPROVED DESIGN'S CAP: the raised rung inside the strong hairline, at
8894
+ * the smallest radius, in the mono face at the micro step and the tertiary
8895
+ * ink. The raised fill is what makes it a KEY rather than a word in a box, so
8896
+ * the cap is flat on every side: the heavier bottom edge it used to carry was
8897
+ * a second way of saying "raised" that the fill now says, and it stood the
8898
+ * cap a pixel taller than the line it sits in.
8899
+ */
7945
8900
  .crewlet-kbd {
7946
8901
  display: inline-flex;
7947
8902
  align-items: center;
7948
- gap: var(--spacing-1);
8903
+ justify-content: center;
7949
8904
  min-width: 18px;
7950
- padding: 1px var(--spacing-1);
8905
+ padding: 0 var(--spacing-1);
7951
8906
  border-radius: var(--radius-xs);
7952
- border: 1px solid var(--color-border-default);
7953
- /* The thicker bottom edge is the whole of the "cap": one border, drawn
7954
- heavier on one side, reads as a key without a shadow that forced-colors
7955
- mode would drop. */
7956
- border-bottom-width: 2px;
7957
- background: var(--color-surface-inset);
8907
+ border: 1px solid var(--color-border-strong);
8908
+ background: var(--color-surface-elevated);
7958
8909
  /*
7959
8910
  * The MONO face, not the surrounding one. A keycap is a literal: the reader
7960
8911
  * is being told which character is printed on a key, and a proportional face
@@ -7968,41 +8919,46 @@ svg.crewlet-datetime__chevron {
7968
8919
  sentence, a shortcut in a menu row. Tightened it stood a pixel under the
7969
8920
  line it sits in and the row it was in wobbled by that pixel wherever a
7970
8921
  cap appeared and wherever one did not. */
7971
- line-height: var(--font-line-height-normal);
8922
+ line-height: var(--font-line-height-body);
7972
8923
  color: var(--color-text-tertiary);
7973
8924
  white-space: nowrap;
7974
8925
  vertical-align: middle;
7975
8926
  }
7976
8927
 
8928
+ /*
8929
+ * A key inside a CHORD's cap. The whole chord is one cap, so each key in it
8930
+ * is text on that cap and nothing more, run together with the next as the
8931
+ * platform prints a chord. It is a `kbd` of its own because that is what a key
8932
+ * inside a key combination is, and a user agent's `kbd` rule would otherwise
8933
+ * set its own face and size on it.
8934
+ */
8935
+ .crewlet-kbd__key {
8936
+ font: inherit;
8937
+ }
8938
+
7977
8939
  /*
7978
8940
  * A quieter cap: FLATTER, not fainter. The opacity this replaces multiplied
7979
8941
  * the ink as well as the frame, and 0.7 of a text step measures 3.43:1 on the
7980
8942
  * panel, so a hint printing the key a reader is told to press was the one
7981
- * thing on the row they could not read. The cap gives up its raised edge and
7982
- * its fill instead, and keeps the tertiary ink, which is measured at 4.5:1 on
7983
- * every surface the package paints on.
8943
+ * thing on the row they could not read. The cap gives up its raised fill and
8944
+ * takes the plain hairline instead, and keeps the tertiary ink, which is
8945
+ * measured at 4.5:1 on every surface the package paints on.
7984
8946
  */
7985
8947
  .crewlet-kbd--subtle {
7986
- border-bottom-width: 1px;
8948
+ border-color: var(--color-border-default);
7987
8949
  background: none;
7988
8950
  }
7989
8951
 
7990
8952
  /*
7991
- * A whole shortcut: the caps drawn together, and one sentence read instead of
7992
- * them. The caps are hidden from assistive technology by the component; this
7993
- * only lays them out.
8953
+ * A whole shortcut: the cap drawn, and one sentence read instead of it. The
8954
+ * cap is hidden from assistive technology by the component; this only lays
8955
+ * it out.
7994
8956
  */
7995
8957
  .crewlet-kbd-combo {
7996
8958
  display: inline-flex;
7997
8959
  align-items: center;
7998
8960
  }
7999
8961
 
8000
- .crewlet-kbd-keys {
8001
- display: inline-flex;
8002
- align-items: center;
8003
- gap: var(--spacing-1);
8004
- }
8005
-
8006
8962
 
8007
8963
  /* Layer-NAFSGCFA.css */
8008
8964
  /*
@@ -8287,7 +9243,7 @@ svg.crewlet-datetime__chevron {
8287
9243
  }
8288
9244
 
8289
9245
 
8290
- /* List-XTHESXLR.css */
9246
+ /* List-MYJIV6MP.css */
8291
9247
  /*
8292
9248
  * The non-tabular list. One row recipe, four framings.
8293
9249
  *
@@ -8434,14 +9390,24 @@ svg.crewlet-datetime__chevron {
8434
9390
  * A row that failed. The rail is the scannable half and the glyph beside it is
8435
9391
  * the honest one: a reader who cannot tell the rail's hue from the row above
8436
9392
  * still meets a mark and a word.
9393
+ *
9394
+ * Both take the danger INK step, not the fill, because both are drawn on the
9395
+ * row, and the row is sometimes the accent tint: a failed row can also be the
9396
+ * one the reader is on. The fill is measured to 3:1 on the opaque surfaces and
9397
+ * no further, so a fill rail on a selected or hovered row clears it only by
9398
+ * the luck of the current palette (the red this list drew measured 3.00:1 on
9399
+ * a hovered row inside a raised surface in dark); the ink clears 4.5:1 on
9400
+ * every row ground, the accent tint included, which is where the palette
9401
+ * suite holds a row's state rail (DATA_MARKS) and where the DataTable suite's
9402
+ * sheet scan now holds this one.
8437
9403
  */
8438
9404
  .crewlet-list__item--danger > .crewlet-list__row {
8439
- box-shadow: inset 2px 0 0 var(--color-feedback-danger);
9405
+ box-shadow: inset 2px 0 0 var(--color-feedback-danger-ink);
8440
9406
  }
8441
9407
 
8442
9408
  .crewlet-list__danger-mark {
8443
9409
  flex: none;
8444
- color: var(--color-feedback-danger);
9410
+ color: var(--color-feedback-danger-ink);
8445
9411
  }
8446
9412
 
8447
9413
  @media (prefers-reduced-motion: reduce) {
@@ -8601,7 +9567,7 @@ svg.crewlet-datetime__chevron {
8601
9567
  }
8602
9568
 
8603
9569
 
8604
- /* Listbox-ZXYYNN6U.css */
9570
+ /* Listbox-6WJNJQVQ.css */
8605
9571
  /*
8606
9572
  * The listbox register: one look for every list a field offers.
8607
9573
  *
@@ -8666,8 +9632,8 @@ svg.crewlet-datetime__chevron {
8666
9632
  * The SECONDARY step, not the primary one. A list of candidates is read by
8667
9633
  * running the eye down it for the one that matches, and rows drawn at full
8668
9634
  * strength all shout at once; the row the reader is actually on is the one
8669
- * that takes the accent and its ink. The step is held at 4.5:1 on every
8670
- * ground a row can sit on, so quieter is not fainter.
9635
+ * that lifts to the primary ink. The step is held at 4.5:1 on every ground a
9636
+ * row can sit on, so quieter is not fainter.
8671
9637
  */
8672
9638
  color: var(--color-text-secondary);
8673
9639
  font-size: var(--font-size-compact);
@@ -8679,14 +9645,39 @@ svg.crewlet-datetime__chevron {
8679
9645
  }
8680
9646
 
8681
9647
  /*
8682
- * The active row, whether the arrows put it there or a hover did. The accent
8683
- * is what means "here", and it is a tint plus its ink step rather than a fill
8684
- * with a label on it.
9648
+ * The active row, whether the arrows put it there or a hover did: the RAISED
9649
+ * rung with the label lifted to the primary ink, as the approved palette draws
9650
+ * it. Every list here opens on a card (a popover, a dialog), and raised is held
9651
+ * dE 3 off the card by @crewlethq/tokens because a chip or a well has no border
9652
+ * of its own, which is what this row is; every text step clears 4.5:1 on it.
9653
+ *
9654
+ * It used to be the accent's soft tint with the accent ink. The accent is the
9655
+ * primary action's fill and the focus ring, so a violet row under the arrows
9656
+ * read as a second primary on every surface that offers a list, the same
9657
+ * reason the rail's current row stopped wearing it. What the accent still
9658
+ * marks in a list is a CHOICE made (a multi-select's tick), not where the
9659
+ * arrows are.
8685
9660
  */
8686
9661
  .crewlet-listbox__option[aria-selected='true'],
8687
9662
  .crewlet-listbox__option:hover {
8688
- background: var(--color-brand-accent-soft);
8689
- color: var(--color-brand-accent-ink);
9663
+ background: var(--color-surface-elevated);
9664
+ color: var(--color-text-primary);
9665
+ }
9666
+
9667
+ /*
9668
+ * FORCED COLORS repaints every author background to Canvas, which took the
9669
+ * highlight with it: the arrows moved through a list in which no row looked
9670
+ * any different, in every Select, Combobox and command palette. An outline is
9671
+ * the one mark the mode keeps, drawn inside the row so the list's own clip
9672
+ * does not cut it, in the system's colour for exactly this.
9673
+ */
9674
+ @media (forced-colors: active) {
9675
+ .crewlet-listbox__option[aria-selected='true'] {
9676
+ outline-style: solid;
9677
+ outline-width: 2px;
9678
+ outline-color: Highlight;
9679
+ outline-offset: -2px;
9680
+ }
8690
9681
  }
8691
9682
 
8692
9683
  .crewlet-listbox__option[aria-disabled='true'] {
@@ -8982,7 +9973,7 @@ svg.crewlet-datetime__chevron {
8982
9973
  }
8983
9974
 
8984
9975
 
8985
- /* Meter-SKOOXQBC.css */
9976
+ /* Meter-5VCSFMZW.css */
8986
9977
  /*
8987
9978
  * The meter.
8988
9979
  *
@@ -9027,22 +10018,41 @@ svg.crewlet-datetime__chevron {
9027
10018
  }
9028
10019
 
9029
10020
  /*
9030
- * A 4px track, which is the engine's. A meter sits under a line of 12px text
9031
- * inside a card, and the 6px bar read as a divider rather than as a reading of
9032
- * something; four is the height at which the fill is still unmistakably a
9033
- * proportion and the bar is unmistakably chrome.
10021
+ * A 6px track with round ends, the approved design's meter, at both sizes. It
10022
+ * stands at the end of a stat tile's value line beside a 28px number and a
10023
+ * 28px sparkline, and under a line of 12px text inside a card; the design
10024
+ * draws it at six in both places, where the engine's older bar was four.
10025
+ *
10026
+ * The track is RAISED, the approved design's, and a rung rather than a well.
10027
+ * The fill is measured against it as a mark, and the palette suite measures a
10028
+ * mark on the four opaque rungs: on the inset well this track used to be, the
10029
+ * light warning and success fills measured 2.84:1 and 2.86:1 over the frame
10030
+ * once the states took the approved hues, a pair no palette rule could see.
10031
+ *
10032
+ * An opaque track has an edge only against a ground that is not itself, so a
10033
+ * meter is drawn on a CARD, where the design puts every one and where the
10034
+ * palette holds raised a visible step above the ground (dE 3.13 dark, 3.65
10035
+ * light). On the raised rung the unfilled remainder, and with it the extent
10036
+ * of the bar, would not be there at all.
9034
10037
  */
9035
10038
  .crewlet-meter__track {
9036
- height: 4px;
10039
+ height: 6px;
9037
10040
  border-radius: var(--radius-pill);
9038
- background: var(--color-surface-inset);
10041
+ background: var(--color-surface-elevated);
9039
10042
  overflow: hidden;
9040
10043
  }
9041
10044
 
10045
+ /*
10046
+ * The ordinary reading, `quantity`, is the first data series. A meter is a
10047
+ * figure of ONE quantity and its label names it, which is all a data hue
10048
+ * asks for; the accent it used to take means "act here", and a bar is not
10049
+ * something to act on. Every other tone below is a state, derived from the
10050
+ * fill or passed by the caller.
10051
+ */
9042
10052
  .crewlet-meter__fill {
9043
10053
  height: 100%;
9044
10054
  border-radius: var(--radius-pill);
9045
- background: var(--color-brand-accent);
10055
+ background: var(--color-data-1);
9046
10056
  transition: width var(--motion-duration-slow) var(--motion-easing-emphasized);
9047
10057
  }
9048
10058
 
@@ -9071,8 +10081,28 @@ svg.crewlet-datetime__chevron {
9071
10081
  }
9072
10082
  }
9073
10083
 
10084
+ /*
10085
+ * FORCED COLORS. The mode repaints every author background to Canvas, and the
10086
+ * track and the fill are nothing but backgrounds, so the bar used to disappear
10087
+ * whole, track and reading together, for exactly the reader who asked for
10088
+ * more contrast. A system colour an author writes is kept, so the fill is
10089
+ * drawn in CanvasText and the track in GrayText, the system's own pair for
10090
+ * "there" and "quieter", which is what a SegmentedMeter draws its parts and
10091
+ * its remainder in. The tone goes, as every hue does in this mode; the length
10092
+ * is the reading, and it stays.
10093
+ */
10094
+ @media (forced-colors: active) {
10095
+ .crewlet-meter__track {
10096
+ background: GrayText;
10097
+ }
10098
+
10099
+ .crewlet-meter__fill[data-tone] {
10100
+ background: CanvasText;
10101
+ }
10102
+ }
10103
+
9074
10104
 
9075
- /* Modal-XYQJ4BL6.css */
10105
+ /* Modal-JAYBS2KS.css */
9076
10106
  /*
9077
10107
  * The modal surface: the veil, the frame, and the three bands inside it.
9078
10108
  *
@@ -9295,10 +10325,11 @@ svg.crewlet-datetime__chevron {
9295
10325
  }
9296
10326
 
9297
10327
  /*
9298
- * The shell's one breakpoint. Below it there is no content beside a sheet to
9299
- * keep in view, so the sheet takes the whole width and its edge goes with it.
10328
+ * The shell's one breakpoint, strictly under it as the shell switches. Below
10329
+ * it there is no content beside a sheet to keep in view, so the sheet takes
10330
+ * the whole width and its edge goes with it.
9300
10331
  */
9301
- @media (max-width: 900px) {
10332
+ @media (width < 1024px) {
9302
10333
  .crewlet-modal--sheet {
9303
10334
  width: 100%;
9304
10335
  border-inline: none;
@@ -9324,6 +10355,14 @@ svg.crewlet-datetime__chevron {
9324
10355
  * it on the line the bar behind it draws, and holds the two buttons that
9325
10356
  * commit and abandon the form at a full control step with room around them.
9326
10357
  *
10358
+ * THE HEIGHT IS THE ROOM, NOT THE PADDING. The head centres what it holds, so
10359
+ * the room around the buttons is what the bar's height leaves, and the block
10360
+ * padding is only the least it keeps when a title wraps. It was the 16px step
10361
+ * while the bar was 64px, which a full control step filled exactly; at 52px
10362
+ * the same padding stood the head 12px past the bar behind it. At the 4px step
10363
+ * the head is the bar's height with the control step at every density, 36.48px
10364
+ * at comfortable included, and with a subtitle under the title.
10365
+ *
9327
10366
  * It used to be the tighter band, 49px with a close control alone, and the
9328
10367
  * commit pair sat in a foot below a body that scrolled 1,764px on a seat with
9329
10368
  * a dozen fields: the reader had to travel the whole form to reach Apply, and
@@ -9331,7 +10370,7 @@ svg.crewlet-datetime__chevron {
9331
10370
  */
9332
10371
  .crewlet-modal__header--sheet {
9333
10372
  min-height: var(--size-shell-topbar);
9334
- padding: var(--spacing-4) var(--spacing-6);
10373
+ padding: var(--spacing-1) var(--spacing-6);
9335
10374
  gap: var(--spacing-4);
9336
10375
  box-sizing: border-box;
9337
10376
  }
@@ -9622,7 +10661,7 @@ svg.crewlet-datetime__chevron {
9622
10661
  }
9623
10662
 
9624
10663
 
9625
- /* OrgLabel-D7U6QJZD.css */
10664
+ /* OrgLabel-CR233G34.css */
9626
10665
  /*
9627
10666
  * What a node of an org chart and a row of an org table both say
9628
10667
  * (OrgLabel.tsx).
@@ -9698,26 +10737,17 @@ svg.crewlet-datetime__chevron {
9698
10737
  had the fill alone and therefore the same defect; one rule now answers for
9699
10738
  both surfaces. */
9700
10739
  color: inherit;
9701
- fill: currentColor;
9702
- }
9703
-
9704
- /*
9705
- * THE DASHED RING is the boundary something standing for somebody outside the
9706
- * system wears, around the mark rather than instead of it: the card's own edge
9707
- * and the row's own mark carry the same dash, and the two together are what a
9708
- * reader recognises without reading a word.
9709
- */
9710
- .crewlet-org-label__icon--dashed {
9711
- position: relative;
9712
10740
  }
9713
10741
 
9714
- .crewlet-org-label__icon--dashed::before {
9715
- content: '';
9716
- position: absolute;
9717
- width: var(--size-target-min);
9718
- height: var(--size-target-min);
9719
- border: 1px dashed var(--color-border-hover);
9720
- border-radius: var(--radius-circle);
10742
+ /* THE FILL IS FOR A FILLED DRAWING, and a glyph is a stroke. Painting the
10743
+ inside of a Lucide glyph turns every closed shape in it solid and every
10744
+ open one into a smear (a person's head and shoulders, a unit's building, a
10745
+ warning's triangle, each a blob), so a `.crewlet-glyph` keeps the fill its
10746
+ own frame decides and takes the ink through its stroke. */
10747
+ .crewlet-org-label__icon svg:not(.crewlet-glyph),
10748
+ .crewlet-org-label__icon svg:not(.crewlet-glyph) g,
10749
+ .crewlet-org-label__icon svg:not(.crewlet-glyph) path {
10750
+ fill: currentColor;
9721
10751
  }
9722
10752
 
9723
10753
  /* ---- The name and its caption -------------------------------------------- */
@@ -10777,7 +11807,7 @@ svg.crewlet-datetime__chevron {
10777
11807
  }
10778
11808
 
10779
11809
 
10780
- /* PricingCard-JFI7RYXP.css */
11810
+ /* PricingCard-7EFXRSD2.css */
10781
11811
  /*
10782
11812
  * PricingCard, the plan-tier card surface.
10783
11813
  *
@@ -10816,13 +11846,12 @@ svg.crewlet-datetime__chevron {
10816
11846
  /* ── Card root ──────────────────────────────────────────────────── */
10817
11847
  .crewlet-pricing-card {
10818
11848
  text-align: left;
10819
- /* The panel recipe: on dark the top hairline is the elevation, on light the
10820
- shadow is. One card surface across the system, so a plan tier and a
11849
+ /* The card recipe, flat: the card's surface, its hairline and its 12px
11850
+ corner. One card surface across the system, so a plan tier and a
10821
11851
  dashboard panel are the same object. */
10822
11852
  background: var(--color-surface-subtle);
10823
11853
  border: 1px solid var(--color-border-default);
10824
11854
  border-radius: var(--radius-lg);
10825
- box-shadow: var(--shadow-xs), var(--shadow-hairline);
10826
11855
  padding: var(--spacing-4);
10827
11856
  display: flex;
10828
11857
  flex-direction: column;
@@ -10855,7 +11884,7 @@ svg.crewlet-datetime__chevron {
10855
11884
  .crewlet-pricing-card.is-selected {
10856
11885
  border-color: var(--color-brand-accent);
10857
11886
  background: var(--color-brand-accent-soft);
10858
- box-shadow: var(--shadow-selection), var(--shadow-hairline);
11887
+ box-shadow: var(--shadow-selection);
10859
11888
  }
10860
11889
 
10861
11890
  .crewlet-pricing-card.is-disabled,
@@ -10870,7 +11899,7 @@ svg.crewlet-datetime__chevron {
10870
11899
  }
10871
11900
 
10872
11901
  .crewlet-pricing-card.is-selected:has(.crewlet-pricing-card__amount--discounted) {
10873
- box-shadow: var(--shadow-selection), var(--shadow-hairline), var(--shadow-glow);
11902
+ box-shadow: var(--shadow-selection), var(--shadow-glow);
10874
11903
  }
10875
11904
 
10876
11905
  /* Compact a card's interior at small container widths, so a four-up grid on a
@@ -11173,35 +12202,62 @@ svg.crewlet-datetime__chevron {
11173
12202
  }
11174
12203
 
11175
12204
 
11176
- /* SearchTrigger-QXOYAUUY.css */
12205
+ /* SearchTrigger-Z5D4AAY7.css */
11177
12206
  /*
11178
12207
  * A button drawn as the field it stands in for.
11179
12208
  *
11180
- * Below the shell breakpoint it keeps the glyph and drops the label and the
11181
- * hint, which is why the name lives on the button rather than in its text.
12209
+ * TWO PLACES, TWO GROUNDS. The approved design draws it in the rail, the
12210
+ * whole width of the sidebar on the frame, and in a screen's own bar on the
12211
+ * sheet. In each it is one rung up from what it stands on, the sheet on the
12212
+ * frame and the card on the sheet, inside the default hairline, so it reads
12213
+ * as a field sunk into neither and lifted off both.
11182
12214
  */
11183
12215
 
11184
12216
  .crewlet-search-trigger {
11185
12217
  display: inline-flex;
11186
12218
  align-items: center;
11187
12219
  gap: var(--spacing-2);
11188
- /* The resting width of the box. A topbar with less room sets it. */
11189
- --crewlet-search-trigger-width: 220px;
11190
- min-width: var(--crewlet-search-trigger-width);
11191
- height: var(--size-control-md);
11192
- padding: 0 var(--spacing-2) 0 var(--spacing-3);
12220
+ /* The design's 10px inside each end: two steps and a half. */
12221
+ padding: 0 calc(var(--spacing-2) + var(--spacing-1) / 2);
11193
12222
  border: 1px solid var(--color-border-default);
11194
12223
  border-radius: var(--radius-md);
11195
- background: var(--color-surface-subtle);
11196
12224
  color: var(--color-text-tertiary);
11197
12225
  font-family: var(--font-family-sans);
11198
12226
  font-size: var(--font-size-compact);
12227
+ text-align: start;
11199
12228
  cursor: pointer;
11200
12229
  transition:
11201
12230
  border-color var(--motion-duration-fast) var(--motion-easing-default),
11202
12231
  color var(--motion-duration-fast) var(--motion-easing-default);
11203
12232
  }
11204
12233
 
12234
+ /*
12235
+ * THE RAIL'S FIELD: the full width of the sidebar, on the SHEET's ground, and
12236
+ * a step taller than a control. It is the rail's one field and the first
12237
+ * thing in it under the company's name, and the design stands it at 34px,
12238
+ * the medium control and one scale step, so it reads as the way in rather
12239
+ * than as one more button.
12240
+ */
12241
+ .crewlet-search-trigger--rail {
12242
+ display: flex;
12243
+ width: 100%;
12244
+ height: calc(var(--size-control-md) + var(--spacing-1));
12245
+ background: var(--color-surface-background);
12246
+ }
12247
+
12248
+ /*
12249
+ * A SCREEN'S OWN SEARCH, in a bar on the sheet: the CARD's ground, the
12250
+ * control height of the buttons beside it, and a resting width of its own.
12251
+ */
12252
+ .crewlet-search-trigger--toolbar {
12253
+ /* The resting width of the box, the design's. A bar with less room sets it. */
12254
+ --crewlet-search-trigger-width: 200px;
12255
+
12256
+ min-width: var(--crewlet-search-trigger-width);
12257
+ height: var(--size-control-md);
12258
+ background: var(--color-surface-subtle);
12259
+ }
12260
+
11205
12261
  .crewlet-search-trigger:hover {
11206
12262
  border-color: var(--color-border-hover);
11207
12263
  color: var(--color-text-primary);
@@ -11223,7 +12279,10 @@ svg.crewlet-datetime__chevron {
11223
12279
  color: var(--color-text-muted);
11224
12280
  }
11225
12281
 
12282
+ /* The label takes the room, so the hint stands at the box's end. */
11226
12283
  .crewlet-search-trigger__label {
12284
+ flex: 1 1 auto;
12285
+ min-width: 0;
11227
12286
  overflow: hidden;
11228
12287
  text-overflow: ellipsis;
11229
12288
  white-space: nowrap;
@@ -11237,13 +12296,16 @@ svg.crewlet-datetime__chevron {
11237
12296
  flex: none;
11238
12297
  }
11239
12298
 
11240
- @media (max-width: 900px) {
11241
- .crewlet-search-trigger {
12299
+ /* Under the shell's breakpoint, strictly, as the shell switches: a toolbar's
12300
+ field collapses to its glyph where the rail becomes a drawer. The rail's
12301
+ own field does not, because the drawer is as wide as the rail was. */
12302
+ @media (width < 1024px) {
12303
+ .crewlet-search-trigger--toolbar {
11242
12304
  min-width: 0;
11243
12305
  }
11244
12306
 
11245
- .crewlet-search-trigger__label,
11246
- .crewlet-search-trigger__shortcut {
12307
+ .crewlet-search-trigger--toolbar .crewlet-search-trigger__label,
12308
+ .crewlet-search-trigger--toolbar .crewlet-search-trigger__shortcut {
11247
12309
  display: none;
11248
12310
  }
11249
12311
  }
@@ -11435,24 +12497,136 @@ svg.crewlet-datetime__chevron {
11435
12497
  font-size: var(--font-size-compact);
11436
12498
  }
11437
12499
 
11438
- /* The one card that is chosen takes the accent, which is what "here, this
11439
- one" means everywhere else in the product. */
11440
- .crewlet-segmented--cards .crewlet-segmented__option.is-active {
11441
- border-color: var(--color-brand-accent);
11442
- background: var(--color-brand-accent-soft);
11443
- color: var(--color-brand-accent-ink);
12500
+ /* The one card that is chosen takes the accent, which is what "here, this
12501
+ one" means everywhere else in the product. */
12502
+ .crewlet-segmented--cards .crewlet-segmented__option.is-active {
12503
+ border-color: var(--color-brand-accent);
12504
+ background: var(--color-brand-accent-soft);
12505
+ color: var(--color-brand-accent-ink);
12506
+ }
12507
+
12508
+ .crewlet-segmented__description {
12509
+ font-size: var(--font-size-xs);
12510
+ font-weight: var(--font-weight-regular);
12511
+ line-height: var(--font-line-height-normal);
12512
+ color: var(--color-text-tertiary);
12513
+ white-space: normal;
12514
+ }
12515
+
12516
+ .crewlet-segmented--cards .crewlet-segmented__option.is-active .crewlet-segmented__description {
12517
+ color: var(--color-brand-accent-ink);
12518
+ }
12519
+
12520
+
12521
+ /* SegmentedMeter-KQNML2TW.css */
12522
+ /*
12523
+ * The segmented meter: a whole divided into the states its parts are in
12524
+ * (SegmentedMeter.tsx).
12525
+ *
12526
+ * THE APPROVED DESIGN'S STATE BAR. 8px tall with 2px between the parts, each
12527
+ * part its tone's FILL step and the remainder the quiet --color-border-strong:
12528
+ * "4 of 7 working" on the Home screen's first tile. The compact step is the
12529
+ * design's 6px progress bar under a project's name, the height of a Meter's
12530
+ * track. Both are the measure of one mark, fixed at every density, as a
12531
+ * Meter's track and a status dot are: a bar read by its proportions does not
12532
+ * shrink with the gaps around it.
12533
+ *
12534
+ * A FILL IS A MARK. Nothing is written on it, so it takes the fill step, which
12535
+ * the palette suite in @crewlethq/tokens measures at 3:1 against every opaque
12536
+ * rung, and the ground shows through the gap on either side of it: two states
12537
+ * are told apart by the gap between them and by the hue each clears on the
12538
+ * ground, never by a contrast between two fills, which no rule measures.
12539
+ *
12540
+ * THE REMAINDER IS THE EXTENT OF THE BAR, not a reading, as a Meter's track
12541
+ * is: what is left of seven seats once four work, one waits and one has
12542
+ * stopped. It is the strong hairline's colour, which stands dE 7.99 off its
12543
+ * nearest rung (the light frame) and 17.19 off its farthest, far past the dE 3
12544
+ * this kit holds every "can a reader notice it" difference to, so the whole is
12545
+ * visible on any ground the bar is put on. It is quieter than a fill by design:
12546
+ * the idle seats are the part of the picture nobody has to act on.
12547
+ */
12548
+
12549
+ .crewlet-segmented-meter {
12550
+ /* The gap between two parts, declared once because the width floor below
12551
+ takes it out of the bar as well. */
12552
+ --crewlet-segmented-meter-gap: 2px;
12553
+ /* How many parts share the bar. The component sets it from the parts it
12554
+ draws; one is what a bar that says nothing else holds. */
12555
+ --crewlet-segmented-meter-count: 1;
12556
+
12557
+ display: flex;
12558
+ gap: var(--crewlet-segmented-meter-gap);
12559
+ height: 8px;
12560
+ min-width: 0;
12561
+ /*
12562
+ * ROUND AT THE TWO ENDS AND SQUARE BETWEEN THE PARTS, which is the design's
12563
+ * bar: the corner is the bar's, clipped, rather than each part's, so a part
12564
+ * in the middle is a plain block and the ends are round whichever parts
12565
+ * happen to stand there. The design writes 3px; the ramp's smallest step is
12566
+ * --radius-xs, 4px, which is half the bar at both heights, so the ends are
12567
+ * round.
12568
+ */
12569
+ border-radius: var(--radius-xs);
12570
+ overflow: hidden;
12571
+ }
12572
+
12573
+ .crewlet-segmented-meter--compact {
12574
+ height: 6px;
11444
12575
  }
11445
12576
 
11446
- .crewlet-segmented__description {
11447
- font-size: var(--font-size-xs);
11448
- font-weight: var(--font-weight-regular);
11449
- line-height: var(--font-line-height-normal);
11450
- color: var(--color-text-tertiary);
11451
- white-space: normal;
12577
+ /*
12578
+ * A PART'S WIDTH IS ITS SHARE, set by the component as a flex basis in
12579
+ * percent of the whole. The bases add to 100%, the gaps push the row past its
12580
+ * box, and every part gives back in proportion to its basis, which is what
12581
+ * flex-shrink at 1 does: each ends at its share of the bar less the gaps.
12582
+ *
12583
+ * THE FLOOR is the kit's 7px status dot, the smallest mark this kit asks a
12584
+ * reader to tell by its hue: at its share alone one stopped seat in sixty is a
12585
+ * sixth of a pixel. It yields to an equal share of the bar where so many parts
12586
+ * are drawn that 7px each would not fit, so no part is ever pushed out of the
12587
+ * end. A part held at the floor overstates its share, and the name says the
12588
+ * exact figures.
12589
+ */
12590
+ .crewlet-segmented-meter__segment {
12591
+ flex-grow: 0;
12592
+ flex-shrink: 1;
12593
+ min-width: min(
12594
+ 7px,
12595
+ calc(
12596
+ (100% - (var(--crewlet-segmented-meter-count) - 1) * var(--crewlet-segmented-meter-gap)) /
12597
+ var(--crewlet-segmented-meter-count)
12598
+ )
12599
+ );
12600
+ height: 100%;
11452
12601
  }
11453
12602
 
11454
- .crewlet-segmented--cards .crewlet-segmented__option.is-active .crewlet-segmented__description {
11455
- color: var(--color-brand-accent-ink);
12603
+ .crewlet-segmented-meter__segment[data-tone='info'] { background: var(--color-feedback-info); }
12604
+ .crewlet-segmented-meter__segment[data-tone='success'] { background: var(--color-feedback-success); }
12605
+ .crewlet-segmented-meter__segment[data-tone='warning'] { background: var(--color-feedback-warning); }
12606
+ .crewlet-segmented-meter__segment[data-tone='danger'] { background: var(--color-feedback-danger); }
12607
+
12608
+ .crewlet-segmented-meter__remainder {
12609
+ background: var(--color-border-strong);
12610
+ }
12611
+
12612
+ /*
12613
+ * FORCED COLORS. The mode repaints every author background to Canvas, so a bar
12614
+ * drawn only in backgrounds disappears whole for exactly the reader who asked
12615
+ * for more contrast, and a bar is read by its LENGTHS, which that reader needs
12616
+ * as much as anybody. A system colour an author writes is kept, so the parts
12617
+ * are drawn in CanvasText and the remainder in GrayText, the system's own
12618
+ * pair for "there" and "quieter", and the gaps still stand between the parts.
12619
+ * The hues go, as every hue does in this mode: the name says which part is
12620
+ * which state.
12621
+ */
12622
+ @media (forced-colors: active) {
12623
+ .crewlet-segmented-meter__segment[data-tone] {
12624
+ background: CanvasText;
12625
+ }
12626
+
12627
+ .crewlet-segmented-meter__remainder {
12628
+ background: GrayText;
12629
+ }
11456
12630
  }
11457
12631
 
11458
12632
 
@@ -11843,7 +13017,7 @@ svg.crewlet-select__chevron {
11843
13017
  }
11844
13018
 
11845
13019
 
11846
- /* SidebarNav-QGSFKZYA.css */
13020
+ /* SidebarNav-X5NLZNWA.css */
11847
13021
  /*
11848
13022
  * The rail's navigation.
11849
13023
  *
@@ -11864,40 +13038,106 @@ svg.crewlet-select__chevron {
11864
13038
  }
11865
13039
 
11866
13040
  /*
11867
- * THE ROWS INSIDE A GROUP ARE FLUSH. A group is a run of destinations read as
11868
- * one block, and the space between two of them is already the row's own height
11869
- * against a 13px line; a step on top of that spends four pixels a rail cannot
11870
- * afford fifteen times over. It is what the group LABEL's bottom pad is for,
11871
- * and the rail's own gap between groups is what separates one run from the
11872
- * next.
11873
- *
11874
- * Measured rather than chosen: at one step per row the rail stood 823px in a
11875
- * 755px scroller, so the last two destinations in the product were reachable
11876
- * only by scrolling the rail. Flush it is 746px and every row is on screen.
13041
+ * THE ROWS INSIDE A GROUP ARE HALF A STEP APART: the approved design's 2px,
13042
+ * which is what keeps a hovered row's tint from touching the raised row under
13043
+ * it and reading as one band two rows tall. It is half a step rather than one
13044
+ * because a rail holds fifteen destinations and more: at 4px a row the rail
13045
+ * stood 823px in a 755px scroller when its rows were 36px, and the last two
13046
+ * destinations were reachable only by scrolling it. At the 30px row step the
13047
+ * same fifteen rows and fourteen 2px gaps are 478px against 540px flush at the
13048
+ * old step, so the gap is paid for many times over by the row it sits beside.
11877
13049
  */
11878
13050
  .crewlet-nav-group {
11879
13051
  display: flex;
11880
13052
  flex-direction: column;
11881
- gap: var(--spacing-0);
13053
+ gap: calc(var(--spacing-1) / 2);
13054
+ min-width: 0;
13055
+ }
13056
+
13057
+ /*
13058
+ * THE HEADING: the group's name and, at its end, an optional control (the add
13059
+ * beside "Projects"). It stands at the pointer-target floor, because that
13060
+ * control is a target and the heading is the row it is drawn in; with no
13061
+ * control the heading keeps the same height, so a rail whose groups differ
13062
+ * only in whether they can add something does not change its rhythm.
13063
+ *
13064
+ * Held off the run above by a margin rather than a padding, so its height
13065
+ * does not depend on the document's box-sizing: with the rail's own gap it is
13066
+ * 14px, the design's space between two runs, at density 1.
13067
+ *
13068
+ * Its end inset is a step SHORTER than a row's, because the control is a
13069
+ * 24px square with its glyph centred in it: the row pad would put the glyph
13070
+ * five pixels inside the line every count above and below it ends on.
13071
+ */
13072
+ .crewlet-nav-group__head {
13073
+ display: flex;
13074
+ align-items: center;
13075
+ gap: var(--spacing-2);
11882
13076
  min-width: 0;
13077
+ min-height: var(--size-target-min);
13078
+ margin-top: calc(var(--spacing-2) + var(--spacing-1) / 2);
13079
+ padding: 0 var(--spacing-2) 0 var(--size-nav-row-pad);
11883
13080
  }
11884
13081
 
13082
+ /*
13083
+ * The group's name in the design's register: sentence case at the caption
13084
+ * step, not the uppercase micro-label it was. It is the same case as every row
13085
+ * it names, so "Projects" reads as the word it is rather than as a label
13086
+ * shouted over the rows, and the quieter ink rather than the tracking is what
13087
+ * sets it apart from them.
13088
+ */
11885
13089
  .crewlet-nav-group__label {
11886
- padding: var(--spacing-3) var(--size-nav-row-pad) var(--spacing-1);
13090
+ flex: 1 1 auto;
13091
+ min-width: 0;
13092
+ overflow: hidden;
13093
+ text-overflow: ellipsis;
13094
+ white-space: nowrap;
11887
13095
  font-family: var(--font-family-sans);
11888
- font-size: var(--font-size-2xs);
11889
- font-weight: var(--font-weight-medium);
11890
- /* The rail's own micro-label register, which is one step tighter than the
11891
- wider step an Eyebrow takes: a group name here sits four pixels above the
11892
- row it names, and at the wider step "OPERATIONS" was visibly broader than
11893
- the rows beneath it rather than quieter than them. */
11894
- letter-spacing: var(--font-letter-spacing-wide);
11895
- text-transform: uppercase;
13096
+ font-size: var(--font-size-xs);
13097
+ font-weight: var(--font-weight-regular);
13098
+ line-height: var(--font-line-height-tight);
11896
13099
  /* The 4.5:1 step: a group name is a fact a reader has to read, not
11897
13100
  decoration. */
11898
13101
  color: var(--color-text-tertiary);
11899
13102
  }
11900
13103
 
13104
+ /* The heading's control. Pushed to the end whether or not the heading has
13105
+ words, and at the floor the heading stands at. */
13106
+ .crewlet-nav-group__action {
13107
+ display: inline-flex;
13108
+ align-items: center;
13109
+ justify-content: center;
13110
+ flex: none;
13111
+ width: var(--size-target-min);
13112
+ height: var(--size-target-min);
13113
+ margin-left: auto;
13114
+ padding: 0;
13115
+ border: none;
13116
+ border-radius: var(--radius-sm);
13117
+ background: transparent;
13118
+ color: var(--color-text-tertiary);
13119
+ cursor: pointer;
13120
+ transition:
13121
+ background var(--motion-duration-fast) var(--motion-easing-default),
13122
+ color var(--motion-duration-fast) var(--motion-easing-default);
13123
+ }
13124
+
13125
+ .crewlet-nav-group__action:hover {
13126
+ background: var(--color-surface-hover);
13127
+ color: var(--color-text-primary);
13128
+ }
13129
+
13130
+ /* Inside its own box, like every control in the rail: the rail is a clipping
13131
+ scroller. */
13132
+ .crewlet-nav-group__action:focus-visible {
13133
+ outline: 2px solid var(--color-focus);
13134
+ outline-offset: var(--size-focus-ring-inset-offset);
13135
+ }
13136
+
13137
+ .crewlet-nav-group__action-icon {
13138
+ display: inline-flex;
13139
+ }
13140
+
11901
13141
  .crewlet-nav-item {
11902
13142
  min-width: 0;
11903
13143
  }
@@ -11912,31 +13152,35 @@ svg.crewlet-select__chevron {
11912
13152
  .crewlet-nav-item__row {
11913
13153
  display: flex;
11914
13154
  align-items: center;
11915
- gap: var(--spacing-2);
13155
+ /* The design's 10px between a glyph and its word. */
13156
+ gap: calc(var(--spacing-2) + var(--spacing-1) / 2);
11916
13157
  flex: 1 1 auto;
11917
13158
  min-width: 0;
11918
13159
  width: 100%;
11919
- min-height: var(--size-row-md);
13160
+ /* The rail's own row step, 30px: a list's 36px row spent six pixels fifteen
13161
+ times over in a column the height of the window. */
13162
+ min-height: var(--size-nav-row);
11920
13163
  padding: 0 var(--size-nav-row-pad);
11921
13164
  border: none;
11922
- /* The chrome's radius, not a card's. A 12px corner on a 36px row leaves the
13165
+ /* The chrome's radius, not a card's. A 12px corner on a 30px row leaves the
11923
13166
  tint reading as a lozenge floating in the gutter rather than as a band the
11924
13167
  width of the rail. */
11925
13168
  border-radius: var(--radius-md);
11926
13169
  background: transparent;
11927
13170
  /*
11928
- * THE RAIL READS AT FULL INK. A destination is not secondary text: a rail of
11929
- * fifteen rows in the quiet step is a column of grey a reader has to hunt
11930
- * through, and the step down bought nothing the row's own tint does not
11931
- * already say. It is also the darker of the two on light and the lighter on
11932
- * dark, so the contrast on every ground the row can have goes up rather than
11933
- * down.
13171
+ * A RESTING ROW IS THE SECONDARY STEP, and the reader's own row and a
13172
+ * pointed one lift to the primary. That step is what says which row is
13173
+ * which before the fill does: at full ink every row carried the current
13174
+ * row's own weight, so the rail read heavier and brighter than the approved
13175
+ * design and the current row was found by its lift alone. The secondary step
13176
+ * is held at 4.5:1 on the rail and under the hover overlay by
13177
+ * @crewlethq/tokens (RAIL_PAINTS), so quieter is not fainter.
11934
13178
  *
11935
- * WHAT CARRIES HOVER IS THEREFORE THE TINT, not an ink step: there is no
11936
- * step left above this one. The glyph is the second half of it, lifting from
11937
- * the decoration ramp to the row's own ink.
13179
+ * The glyph has no colour of its own: it is drawn in currentColor and so is
13180
+ * this ink, on every row, which is what keeps a row from painting its word
13181
+ * and its glyph two different answers to "where am I".
11938
13182
  */
11939
- color: var(--color-text-primary);
13183
+ color: var(--color-text-secondary);
11940
13184
  font-family: var(--font-family-sans);
11941
13185
  /* THE CHROME IS NOT BODY TEXT. A rail row names a destination; it is read at
11942
13186
  a glance and never read through, so it takes the compact step in the
@@ -11955,43 +13199,44 @@ svg.crewlet-select__chevron {
11955
13199
 
11956
13200
  .crewlet-nav-item__row:hover {
11957
13201
  background: var(--color-surface-hover);
13202
+ color: var(--color-text-primary);
11958
13203
  text-decoration: none;
11959
13204
  }
11960
13205
 
11961
- .crewlet-nav-item__row:focus-visible {
11962
- outline: 2px solid var(--color-focus);
11963
- /* Inside the row's own box: the rail is a clipping scroller, so an outset
11964
- ring on the first or last row is cut off by it. */
11965
- outline-offset: var(--size-focus-ring-inset-offset);
11966
- }
11967
-
11968
13206
  /*
11969
- * WHERE THE READER IS: the accent's own soft tint, with the label and the
11970
- * glyph in the accent ink. That is the whole job of an accent in a chrome, and
11971
- * the rail is the one place in the chrome it appears.
13207
+ * WHERE THE READER IS: the row stands on RAISED, with the plain border drawn
13208
+ * round it as a hairline INSIDE the row, and lifts to the primary ink.
11972
13209
  *
11973
- * It was a neutral lift with the accent as a one-pixel bar outside the row's
11974
- * left edge, on the reading that accent text in a rail competes with the
11975
- * status hues beside it and cannot be separated from the row above by a reader
11976
- * with a colour vision deficiency. Neither holds here. Nothing in this rail
11977
- * carries a status hue except the attention count below, which is a tint
11978
- * BEHIND a word rather than a word in a hue; and the tint is what answers the
11979
- * second objection, because the row still lifts off its ground by more than a
11980
- * hovered one does whether or not the hue is seen at all (@crewlethq/tokens
11981
- * measures exactly that, and measures this ink on this composite: 5.76:1 in
11982
- * light, 5.96:1 in dark).
13210
+ * It is found the way a card is found. In light, raised is only dE 1.84 off
13211
+ * the frame the rail stands on, so the fill alone is a lift a reader may not
13212
+ * see; the hairline is what carries the row, and in dark it is also what
13213
+ * tells the current row from a hovered one, whose fill lands only dE 1.56
13214
+ * away. @crewlethq/tokens holds both halves by name: the row lifts off the
13215
+ * rail by dE 1.5 and the hairline clears dE 3 on the row it is drawn on.
11983
13216
  *
11984
- * What the bar cost was that one pixel of hue was the entire signal, at the
11985
- * one moment a reader is scanning the rail to find out where they are.
13217
+ * It used to be the accent's own soft tint with the label in the accent ink.
13218
+ * The accent is the fill of the primary action now, so a violet row in the
13219
+ * rail would read as a second primary on every screen, beside the one the
13220
+ * screen is actually asking for. Where the reader is, is the row's position,
13221
+ * its lift and its line; aria-current says it to a screen reader.
13222
+ *
13223
+ * THE HAIRLINE IS AN OUTLINE, not an inset box-shadow, for the reason the
13224
+ * focus ring is one: forced-colors mode drops every box-shadow and every
13225
+ * background and keeps outlines, so drawn as a shadow the current row would
13226
+ * be indistinguishable from its neighbours for exactly the readers that mode
13227
+ * exists for. The focus ring is the same property, so its rule is declared
13228
+ * after this one and a focused current row draws the ring instead.
11986
13229
  *
11987
13230
  * Drawn from aria-current, so the picture and what a screen reader is told
11988
13231
  * cannot come apart. It is declared after :hover deliberately: both selectors
11989
- * weigh the same, a row shows the current tint or the hover overlay and never
13232
+ * weigh the same, a row shows the current lift or the hover overlay and never
11990
13233
  * both, and later is what decides which.
11991
13234
  */
11992
13235
  .crewlet-nav-item__row[aria-current='page'] {
11993
- background: var(--color-brand-accent-soft);
11994
- color: var(--color-brand-accent-ink);
13236
+ background: var(--color-surface-elevated);
13237
+ outline: 1px solid var(--color-border-default);
13238
+ outline-offset: -1px;
13239
+ color: var(--color-text-primary);
11995
13240
  }
11996
13241
 
11997
13242
  .crewlet-nav-item__row[aria-disabled='true'] {
@@ -12001,20 +13246,25 @@ svg.crewlet-select__chevron {
12001
13246
 
12002
13247
  .crewlet-nav-item__row[aria-disabled='true']:hover {
12003
13248
  background: transparent;
12004
- color: var(--color-text-primary);
13249
+ color: var(--color-text-secondary);
12005
13250
  }
12006
13251
 
12007
13252
  /*
12008
- * THE GLYPH FOLLOWS THE LABEL. At rest it is quieter than the word beside it
12009
- * and takes the decoration step; on a hovered row and on the reader's own it
12010
- * takes the row's own colour, which on the current row is the accent ink.
12011
- *
12012
- * ONE inherit rather than a second ramp, because a second ramp is how a row
12013
- * comes to paint its label and its glyph two different answers to "where am
12014
- * I". The colour is set on the DRAWING rather than on the box around it, which
12015
- * is what says the decoration step is being spent on a glyph and not on text:
12016
- * the package's variable check holds that rule, and it is the rule the step
12017
- * exists for.
13253
+ * After the current row's rule, which draws its hairline on the same
13254
+ * property: both weigh the same, so source order is what lets a focused
13255
+ * current row draw the ring rather than the line.
13256
+ */
13257
+ .crewlet-nav-item__row:focus-visible {
13258
+ outline: 2px solid var(--color-focus);
13259
+ /* Inside the row's own box: the rail is a clipping scroller, so an outset
13260
+ ring on the first or last row is cut off by it. */
13261
+ outline-offset: var(--size-focus-ring-inset-offset);
13262
+ }
13263
+
13264
+ /*
13265
+ * THE GLYPH IS THE LABEL'S INK. Lucide draws in currentColor, so the glyph
13266
+ * takes whatever the row is painted in, at rest, pointed and current alike,
13267
+ * and there is no second ramp to fall out of step with the word beside it.
12018
13268
  */
12019
13269
  .crewlet-nav-item__icon {
12020
13270
  display: inline-flex;
@@ -12023,16 +13273,6 @@ svg.crewlet-select__chevron {
12023
13273
  flex: none;
12024
13274
  }
12025
13275
 
12026
- .crewlet-nav-item__icon svg {
12027
- color: var(--color-text-muted);
12028
- transition: color var(--motion-duration-fast) var(--motion-easing-default);
12029
- }
12030
-
12031
- .crewlet-nav-item__row:hover .crewlet-nav-item__icon svg,
12032
- .crewlet-nav-item__row[aria-current='page'] .crewlet-nav-item__icon svg {
12033
- color: inherit;
12034
- }
12035
-
12036
13276
  .crewlet-nav-item__label {
12037
13277
  flex: 1 1 auto;
12038
13278
  min-width: 0;
@@ -12041,7 +13281,36 @@ svg.crewlet-select__chevron {
12041
13281
  white-space: nowrap;
12042
13282
  }
12043
13283
 
12044
- .crewlet-nav-item__badge {
13284
+ /*
13285
+ * A PROJECT'S KEY, as a chip in the glyph's place: the prefix every item in
13286
+ * the project is filed under, in mono so ENG and PROD line up by letter. It
13287
+ * is the raised rung inside the plain hairline, in the secondary ink, which
13288
+ * the palette suite measures on every ground a row can have; on the reader's
13289
+ * own row, which is raised too, the hairline is what draws it.
13290
+ */
13291
+ .crewlet-nav-item__lead {
13292
+ display: inline-flex;
13293
+ align-items: center;
13294
+ flex: none;
13295
+ padding: 0 calc(var(--spacing-1) + 1px);
13296
+ border: 1px solid var(--color-border-default);
13297
+ border-radius: var(--radius-xs);
13298
+ background: var(--color-surface-elevated);
13299
+ color: var(--color-text-secondary);
13300
+ font-family: var(--font-family-mono);
13301
+ font-size: var(--font-size-2xs);
13302
+ font-weight: var(--font-weight-medium);
13303
+ letter-spacing: var(--font-letter-spacing-normal);
13304
+ line-height: var(--font-line-height-body);
13305
+ }
13306
+
13307
+ /*
13308
+ * THE COUNT: how many of something the destination holds, as a quiet figure
13309
+ * at the end of the row. Tabular, so a count that ticks up does not move the
13310
+ * words beside it. A mark before it (the working dot beside a count of agents
13311
+ * at work) stands half a step off the figure.
13312
+ */
13313
+ .crewlet-nav-item__count {
12045
13314
  display: inline-flex;
12046
13315
  align-items: center;
12047
13316
  flex: none;
@@ -12051,54 +13320,63 @@ svg.crewlet-select__chevron {
12051
13320
  color: var(--color-text-tertiary);
12052
13321
  }
12053
13322
 
12054
- /*
12055
- * THE SLOT IS WHAT PAINTS. A caller hands in the figure and the name a screen
12056
- * reader reads after the row's own ("3 things waiting on somebody"); the rail
12057
- * decides whether that is a quiet number at the end of the row or the one
12058
- * thing on the screen that should pull the eye. So whatever arrives
12059
- * contributes its text and its accessible name and nothing else, which is why
12060
- * a <Count> here draws its own text rather than a second pill inside this one.
12061
- */
12062
- .crewlet-nav-item__badge > * {
12063
- padding: 0;
12064
- border: none;
12065
- border-radius: 0;
12066
- background: transparent;
12067
- color: inherit;
12068
- min-width: 0;
12069
- font-size: inherit;
12070
- font-weight: inherit;
12071
- /* Not the `font` shorthand, which would reset font-variant and take the
12072
- tabular figures with it. */
12073
- font-variant-numeric: inherit;
12074
- line-height: inherit;
13323
+ .crewlet-nav-item__figure {
13324
+ display: inline-flex;
13325
+ align-items: center;
13326
+ gap: calc(var(--spacing-1) + 1px);
13327
+ }
13328
+
13329
+ .crewlet-nav-item__mark {
13330
+ display: inline-flex;
12075
13331
  }
12076
13332
 
12077
- /* A quiet badge takes the row's ink, the current row's accent included. The
12078
- attention badge keeps its own, which is the whole point of it, and the
12079
- :not() is what says so: both selectors would otherwise weigh the same and a
12080
- tone would be decided by which rule a later edit happened to move. */
12081
- .crewlet-nav-item__row[aria-current='page'] .crewlet-nav-item__badge:not(.crewlet-nav-item__badge--attention) {
13333
+ /* The count takes the row's ink on the current row, lifting from the tertiary
13334
+ step to the primary ink with the row it sits in: the tertiary step is
13335
+ measured on the rail and under the hover overlay, and the raised row is a
13336
+ ground it was never held to. */
13337
+ .crewlet-nav-item__row[aria-current='page'] .crewlet-nav-item__count {
12082
13338
  color: inherit;
12083
13339
  }
12084
13340
 
12085
13341
  /*
12086
- * THE ONE BADGE IN THE CHROME ALLOWED A STATUS HUE. A count of what is waiting
12087
- * on a person is the one thing that should pull the eye out of whatever screen
12088
- * the reader is on, and it stays a tint BEHIND a word rather than a word in a
12089
- * hue, so it reads to somebody who cannot separate the hue at all.
13342
+ * THE BADGE, THE ONE FIGURE IN THE CHROME ALLOWED A HUE, and it is the
13343
+ * accent. A count of what is waiting on the reader is the one thing in the
13344
+ * rail that asks them to act, which is what the accent means, and it is the
13345
+ * one thing that should pull the eye out of whatever screen they are on. It
13346
+ * is a FILL carrying a figure rather than a figure in a hue, so it reads to
13347
+ * somebody who cannot separate the hue at all: the filled pill is the signal,
13348
+ * the figure is the count.
12090
13349
  *
12091
- * Measured on every ground a row can have, the reader's own row included,
12092
- * which is a warning tint on the accent tint on the rail: @crewlethq/tokens'
12093
- * palette suite has that composite by name, at 5.08:1 in light and 9.75:1 in
12094
- * dark.
13350
+ * The design's 18px pill, at least as wide as it is tall so a single digit is
13351
+ * a round mark and not a lozenge, and following the density like the xs Tag
13352
+ * it matches. The label is the on-accent step, the primary action's own pair,
13353
+ * on every row alike, because the fill is opaque.
12095
13354
  */
12096
- .crewlet-nav-item__badge--attention {
12097
- padding: 0 var(--spacing-2);
13355
+ .crewlet-nav-item__badge {
13356
+ --crewlet-nav-item-badge-size: calc(18px * var(--density, 1));
13357
+ display: inline-flex;
13358
+ align-items: center;
13359
+ justify-content: center;
13360
+ flex: none;
13361
+ box-sizing: border-box;
13362
+ min-width: var(--crewlet-nav-item-badge-size);
13363
+ height: var(--crewlet-nav-item-badge-size);
13364
+ margin-left: auto;
13365
+ padding: 0 calc(var(--spacing-1) + 1px);
12098
13366
  border-radius: var(--radius-pill);
12099
- background: var(--color-feedback-warning-soft);
12100
- color: var(--color-feedback-warning-ink);
13367
+ background: var(--color-brand-accent);
13368
+ color: var(--color-text-on-accent);
13369
+ font-size: var(--font-size-2xs);
12101
13370
  font-weight: var(--font-weight-semibold);
13371
+ font-variant-numeric: tabular-nums;
13372
+ line-height: 1;
13373
+ }
13374
+
13375
+ /* Beside a count the badge is the second figure, not a second push to the
13376
+ end: two auto margins would split the room between them and float the
13377
+ count into the middle of the row. */
13378
+ .crewlet-nav-item__count + .crewlet-nav-item__badge {
13379
+ margin-left: var(--spacing-2);
12102
13380
  }
12103
13381
 
12104
13382
  .crewlet-nav-item__toggle {
@@ -12137,9 +13415,10 @@ svg.crewlet-select__chevron {
12137
13415
 
12138
13416
  /*
12139
13417
  * Nested rows carry an indent guide rather than more padding, because a run of
12140
- * indents with no line is a hierarchy a reader has to measure by eye. The
12141
- * guide takes the accent on the path the reader is on, which is the same
12142
- * signal the top-level rail gives.
13418
+ * indents with no line is a hierarchy a reader has to measure by eye. On the
13419
+ * path the reader is on the guide steps up to the strong border: the same
13420
+ * neutral lift the current row itself takes, and not the accent, which the
13421
+ * rail keeps for the one count that asks the reader to act.
12143
13422
  */
12144
13423
  .crewlet-nav-item__children {
12145
13424
  display: flex;
@@ -12153,12 +13432,12 @@ svg.crewlet-select__chevron {
12153
13432
  /* No type step of its own any more: every row in the rail reads at the compact
12154
13433
  step now, and the indent guide is what says a row is nested. */
12155
13434
  .crewlet-nav-item__children:has(.crewlet-nav-item__row[aria-current='page']) {
12156
- border-left-color: var(--color-brand-accent);
13435
+ border-left-color: var(--color-border-strong);
12157
13436
  }
12158
13437
 
12159
13438
  @media (prefers-reduced-motion: reduce) {
13439
+ .crewlet-nav-group__action,
12160
13440
  .crewlet-nav-item__row,
12161
- .crewlet-nav-item__icon svg,
12162
13441
  .crewlet-nav-item__chevron {
12163
13442
  transition: none;
12164
13443
  }
@@ -12589,28 +13868,41 @@ svg.crewlet-select__chevron {
12589
13868
  }
12590
13869
 
12591
13870
 
12592
- /* StatCard-KYPKZUWX.css */
13871
+ /* StatCard-KPAFD4E2.css */
12593
13872
  /*
12594
13873
  * The stat tile.
12595
13874
  *
12596
13875
  * THE TONE PAINTS THE VALUE, which is what the props always said and what the
12597
13876
  * stylesheet never did: 0.2.0 tinted the ICON, so a caller who passed a tone
12598
13877
  * and no icon got a tile identical to a neutral one. Ink only, and never a
12599
- * fill: a tinted block behind a 24px number reads as a button.
13878
+ * fill: a tinted block behind a 28px number reads as a button.
12600
13879
  */
12601
13880
 
12602
13881
  .crewlet-statcard {
13882
+ /*
13883
+ * The width of the figure at the end of the value's line. 96px is the
13884
+ * approved design's sparkline, and its meters and state bars stand within
13885
+ * four pixels of it: wide enough that a fortnight of points reads as a
13886
+ * shape, narrow enough that five tiles in a row still leave the number its
13887
+ * room.
13888
+ */
13889
+ --crewlet-statcard-trend-width: 96px;
13890
+
12603
13891
  display: flex;
12604
13892
  flex-direction: column;
12605
- gap: var(--spacing-1);
12606
- padding: var(--spacing-3) var(--spacing-4);
12607
- /* The panel recipe: the surface, the hairline, the 12px corner and the
12608
- elevation the engine gives every card on a screen, so a lone tile is the
12609
- same object as the panel beside it rather than a flatter cousin. */
13893
+ /* The design's 10px between the three lines, and its 16px inset with 14px
13894
+ under the last line: half a scale step each, derived from the steps so
13895
+ they follow the density with everything else. */
13896
+ gap: calc(var(--spacing-2) + var(--spacing-1) / 2);
13897
+ padding: var(--spacing-4) var(--spacing-4) calc(var(--spacing-3) + var(--spacing-1) / 2);
13898
+ /*
13899
+ * The card recipe: the card's surface, its hairline and its 12px corner,
13900
+ * FLAT, as every card is, so a lone tile is the same object as the panel
13901
+ * beside it rather than a raised cousin of it.
13902
+ */
12610
13903
  background: var(--color-surface-subtle);
12611
13904
  border: 1px solid var(--color-border-default);
12612
13905
  border-radius: var(--radius-lg);
12613
- box-shadow: var(--shadow-xs), var(--shadow-hairline);
12614
13906
  color: var(--color-text-primary);
12615
13907
  font-family: var(--font-family-sans);
12616
13908
  min-width: 0;
@@ -12622,35 +13914,104 @@ svg.crewlet-select__chevron {
12622
13914
  background: transparent;
12623
13915
  border: 0;
12624
13916
  border-radius: var(--radius-none);
12625
- box-shadow: none;
12626
13917
  }
12627
13918
 
12628
- .crewlet-statcard__value {
13919
+ /*
13920
+ * The label: SENTENCE CASE at the caption step, as the design sets it and as
13921
+ * the caller wrote it. The uppercased, tracked-open micro-caps it used to wear
13922
+ * are a table's column head: five of them over five numbers put a heading on
13923
+ * every tile, and uppercasing is a transform a caller's own words should not
13924
+ * have to survive.
13925
+ */
13926
+ .crewlet-statcard__label {
12629
13927
  display: flex;
12630
- align-items: baseline;
12631
- gap: var(--spacing-2);
13928
+ align-items: center;
13929
+ gap: var(--spacing-1);
13930
+ font-size: var(--font-size-xs);
13931
+ font-weight: var(--font-weight-regular);
13932
+ letter-spacing: var(--font-letter-spacing-normal);
13933
+ color: var(--color-text-tertiary);
12632
13934
  min-width: 0;
12633
- font-size: var(--font-size-2xl);
13935
+ }
13936
+
13937
+ .crewlet-statcard__icon {
13938
+ display: inline-flex;
13939
+ flex: none;
13940
+ }
13941
+
13942
+ /*
13943
+ * The value's line: the number at its start, the figure at its end, both on
13944
+ * the line's FOOT, so a 28px number and a 28px sparkline share a baseline
13945
+ * rather than centring on each other.
13946
+ */
13947
+ .crewlet-statcard__reading {
13948
+ display: flex;
13949
+ align-items: flex-end;
13950
+ justify-content: space-between;
13951
+ gap: calc(var(--spacing-2) + var(--spacing-1) / 2);
13952
+ min-width: 0;
13953
+ }
13954
+
13955
+ /*
13956
+ * THE SCREEN'S ONE DISPLAY NUMBER. The display step, semibold, on the tight
13957
+ * track, with tabular figures so a number that ticks up moves nothing beside
13958
+ * it.
13959
+ *
13960
+ * ITS LINE IS THE GLYPH'S OWN HEIGHT (a leading of 1). The value is one line
13961
+ * that never wraps, and any leading over it is air under the digits that
13962
+ * opens between the number and the line below it and stands the number
13963
+ * higher than the figure it shares a foot with.
13964
+ *
13965
+ * A BLOCK, NOT A FLEX ROW, because it is one line of text that has to END
13966
+ * rather than stop: `text-overflow` acts on a block container only, and as a
13967
+ * flex row the number and its unit were anonymous flex items no rule could
13968
+ * reach, so a value too long for its tile was cut mid-digit with nothing to
13969
+ * say a digit was lost. The unit sits on the same line as inline text, on
13970
+ * the number's baseline.
13971
+ */
13972
+ .crewlet-statcard__value {
13973
+ display: block;
13974
+ flex: 1 1 auto;
13975
+ min-width: 0;
13976
+ font-size: var(--font-size-display);
12634
13977
  font-weight: var(--font-weight-semibold);
12635
13978
  letter-spacing: var(--font-letter-spacing-tight);
12636
- /* 1.1, the engine's, which is tighter than the tight step: a 24px number
12637
- with 1.2 of leading sits low in its box and opens a gap between the value
12638
- and the line under it that the 4px gap was already spending. */
12639
- line-height: 1.1;
12640
- /* A number that ticks up must not move the label under it. */
13979
+ line-height: 1;
12641
13980
  font-variant-numeric: tabular-nums;
12642
13981
  overflow: hidden;
12643
13982
  text-overflow: ellipsis;
12644
13983
  white-space: nowrap;
12645
13984
  }
12646
13985
 
13986
+ /* The unit, "/ 7" after the 4: the quiet ink at a text step, medium, so it
13987
+ reads as part of the figure rather than as a second one. */
12647
13988
  .crewlet-statcard__unit {
13989
+ margin-inline-start: var(--spacing-1);
12648
13990
  font-size: var(--font-size-sm);
12649
- font-weight: var(--font-weight-regular);
13991
+ font-weight: var(--font-weight-medium);
12650
13992
  letter-spacing: var(--font-letter-spacing-normal);
12651
13993
  color: var(--color-text-tertiary);
12652
13994
  }
12653
13995
 
13996
+ /*
13997
+ * The figure at the end of the line. A figure (a sparkline, a meter, a state
13998
+ * bar) FILLS the slot, because none of them has a width of its own to offer.
13999
+ * A control keeps its own and stands at the slot's end: "Review" is a small
14000
+ * button beside the number it acts on, not a bar the width of a sparkline.
14001
+ */
14002
+ .crewlet-statcard__trend {
14003
+ display: flex;
14004
+ flex-direction: column;
14005
+ justify-content: flex-end;
14006
+ flex: none;
14007
+ width: var(--crewlet-statcard-trend-width);
14008
+ min-width: 0;
14009
+ }
14010
+
14011
+ .crewlet-statcard__trend > :where(button, a) {
14012
+ align-self: flex-end;
14013
+ }
14014
+
12654
14015
  /*
12655
14016
  * The placeholder is a line, not a pair of dashes. `--` is read aloud as
12656
14017
  * "dash dash" and looks exactly like a measured value of nothing; the tile
@@ -12664,46 +14025,57 @@ svg.crewlet-select__chevron {
12664
14025
  background: var(--color-surface-inset);
12665
14026
  }
12666
14027
 
12667
- .crewlet-statcard__label {
12668
- display: flex;
12669
- align-items: center;
12670
- gap: var(--spacing-1);
12671
- font-size: var(--font-size-2xs);
12672
- font-weight: var(--font-weight-medium);
12673
- letter-spacing: var(--font-letter-spacing-wide);
12674
- text-transform: uppercase;
12675
- color: var(--color-text-tertiary);
12676
- min-width: 0;
12677
- }
12678
-
12679
- .crewlet-statcard__icon {
12680
- display: inline-flex;
12681
- flex: none;
12682
- }
12683
-
12684
14028
  /*
12685
14029
  * The second line keeps its space whether or not there is one, so a row of
12686
- * tiles where only some carry a sub still sits on one baseline.
14030
+ * tiles where only some carry one still stands at one height: its leading is
14031
+ * set here and the reserve is exactly one line of it, where a reserve in `em`
14032
+ * was a line shorter than the one a sub actually draws.
12687
14033
  */
12688
14034
  .crewlet-statcard__sub {
12689
- min-height: 1.2em;
14035
+ min-height: calc(1em * var(--font-line-height-body));
12690
14036
  font-size: var(--font-size-xs);
12691
- /* The quiet step, with the label. The sub qualifies the number rather than
12692
- being a second one, and the engine keeps both of them a step under the
12693
- value they belong to. */
14037
+ line-height: var(--font-line-height-body);
14038
+ /* The quiet step, with the label. The line qualifies the number rather than
14039
+ being a second one. */
12694
14040
  color: var(--color-text-tertiary);
12695
14041
  overflow: hidden;
12696
14042
  text-overflow: ellipsis;
12697
14043
  white-space: nowrap;
12698
14044
  }
12699
14045
 
14046
+ /*
14047
+ * A CHANGE IS COLOURED BY WHETHER IT WAS WANTED, not by its direction: the
14048
+ * sign already says which way the number moved. Good news takes the success
14049
+ * ink and bad news the danger ink, the steps measured as TEXT on every rung;
14050
+ * a change that is neither takes the secondary ink, a step up from the words
14051
+ * after it, so the figure still leads the sentence.
14052
+ */
14053
+ .crewlet-statcard__delta {
14054
+ font-variant-numeric: tabular-nums;
14055
+ }
14056
+
14057
+ .crewlet-statcard__delta--good { color: var(--color-feedback-success-ink); }
14058
+ .crewlet-statcard__delta--bad { color: var(--color-feedback-danger-ink); }
14059
+ .crewlet-statcard__delta--neutral { color: var(--color-text-secondary); }
14060
+
14061
+ /*
14062
+ * A SECOND LINE THAT REPORTS A STATE takes that state's ink ("Oldest waiting
14063
+ * 2h 10m" is a person kept waiting: warning), the step measured as text on
14064
+ * every rung, as the value's tone does. The delta inside the line keeps its
14065
+ * own ink, which is a class on the delta and outranks this one on the line.
14066
+ */
14067
+ .crewlet-statcard__sub--success { color: var(--color-feedback-success-ink); }
14068
+ .crewlet-statcard__sub--warning { color: var(--color-feedback-warning-ink); }
14069
+ .crewlet-statcard__sub--danger { color: var(--color-feedback-danger-ink); }
14070
+ .crewlet-statcard__sub--info { color: var(--color-feedback-info-ink); }
14071
+
12700
14072
  .crewlet-statcard--success .crewlet-statcard__value { color: var(--color-feedback-success-ink); }
12701
14073
  .crewlet-statcard--warning .crewlet-statcard__value { color: var(--color-feedback-warning-ink); }
12702
14074
  .crewlet-statcard--danger .crewlet-statcard__value { color: var(--color-feedback-danger-ink); }
12703
14075
  .crewlet-statcard--info .crewlet-statcard__value { color: var(--color-feedback-info-ink); }
12704
14076
 
12705
14077
 
12706
- /* StatGroup-TGB6AEKM.css */
14078
+ /* StatGroup-HVG6O62W.css */
12707
14079
  /*
12708
14080
  * A row of stat tiles.
12709
14081
  *
@@ -12716,14 +14088,13 @@ svg.crewlet-select__chevron {
12716
14088
  .crewlet-stat-group {
12717
14089
  display: grid;
12718
14090
  grid-template-columns: repeat(var(--crewlet-stat-group-cols, 4), minmax(0, 1fr));
12719
- /* The flush-panel recipe: the surface, the hairline, the 12px corner and
12720
- `overflow: hidden`, which is what lets the tiles inside sit against the
12721
- corners without their own hairlines escaping past them. The engine puts
12722
- its stat row inside exactly this. */
14091
+ /* The flush-panel recipe: the card's surface, its hairline and its 12px
14092
+ corner, flat as every card is, and `overflow: hidden`, which is what lets
14093
+ the tiles inside sit against the corners without their own hairlines
14094
+ escaping past them. */
12723
14095
  background: var(--color-surface-subtle);
12724
14096
  border: 1px solid var(--color-border-default);
12725
14097
  border-radius: var(--radius-lg);
12726
- box-shadow: var(--shadow-xs), var(--shadow-hairline);
12727
14098
  overflow: hidden;
12728
14099
  }
12729
14100
 
@@ -12744,7 +14115,6 @@ svg.crewlet-select__chevron {
12744
14115
  background: transparent;
12745
14116
  border: 0;
12746
14117
  border-radius: var(--radius-none);
12747
- box-shadow: none;
12748
14118
  }
12749
14119
 
12750
14120
  /*
@@ -12763,13 +14133,14 @@ svg.crewlet-select__chevron {
12763
14133
 
12764
14134
  /*
12765
14135
  * Two columns under the shell breakpoint, which is where the engine drops its
12766
- * own stat row: 900px is a 280px rail plus a 620px content column, so it is
12767
- * the width at which a four-up row of numbers stops having a column each. The
14136
+ * own stat row, and strictly under it, as the shell switches. The step is
14137
+ * 1024px, a 236px rail, the 8px inset and a 780px floor for the sheet, and it
14138
+ * is the width at which the shell stops holding the page beside the rail. The
12768
14139
  * rules are written for the general case rather than per column count: the
12769
14140
  * first tile of each pair loses its left hairline, and everything on the
12770
14141
  * second row and below gains a top one.
12771
14142
  */
12772
- @media (max-width: 900px) {
14143
+ @media (width < 1024px) {
12773
14144
  .crewlet-stat-group {
12774
14145
  grid-template-columns: repeat(2, minmax(0, 1fr));
12775
14146
  }
@@ -12786,90 +14157,371 @@ svg.crewlet-select__chevron {
12786
14157
  }
12787
14158
 
12788
14159
 
12789
- /* StatusDot-HA2L2FSX.css */
14160
+ /* StatusDot-7OMCQCZF.css */
12790
14161
  /*
12791
- * The status dot: a 6px mark in its tone's fill, beside the word it belongs
14162
+ * The status dot: a 7px mark in its tone's fill, beside the word it belongs
12792
14163
  * to. See the component doc for why it is hidden from assistive technology.
14164
+ *
14165
+ * 7px is the approved design's dot. The size is written out rather than
14166
+ * taken from a scale because it is the measure of one mark, not a step
14167
+ * anything else shares, and it is fixed at every density: a mark read the
14168
+ * way a glyph is does not shrink with the gaps around it.
14169
+ *
14170
+ * TWO VALUES PER TONE: the fill the dot is painted in, and the HALO a pulsing
14171
+ * dot breathes out in, which is the same tone's soft step. The halo is held to
14172
+ * being SEEN rather than to a contrast ratio: it never touches the dot (see the
14173
+ * pulse below), so the dot clears 3:1 against the surface it stands on at every
14174
+ * point of the round, and the word beside it says the state. The halo only has
14175
+ * to stand off its ground by the dE 3 the palette suite holds every "can a
14176
+ * reader notice it" difference to. Every soft step does, by 4.48 at the least.
12793
14177
  */
12794
14178
 
12795
14179
  .crewlet-status-dot {
12796
14180
  display: inline-block;
12797
- width: 6px;
12798
- height: 6px;
14181
+ width: 7px;
14182
+ height: 7px;
12799
14183
  border-radius: var(--radius-circle);
12800
14184
  /*
12801
14185
  * The quiet state is still a mark, so it takes the tertiary step rather than
12802
- * the decoration one the engine spends here: a 6px dot has to clear 3:1 to
14186
+ * the decoration one the engine spends here: a 7px dot has to clear 3:1 to
12803
14187
  * be seen at all, and --color-text-muted measures 2.33:1 on a light page and
12804
14188
  * 2.25:1 on a dark one at their worst grounds. The tertiary step measures
12805
14189
  * 4.87:1 and 4.65:1 on the same pair, and is the nearest step that holds.
12806
14190
  */
12807
14191
  background: var(--color-text-tertiary);
14192
+ /*
14193
+ * The neutral family has no soft step, because it has no hue to tint with,
14194
+ * so its halo is a translucent overlay. Pressed is the one that reads like
14195
+ * the tones' halos: it stands dE 6.09 off its faintest ground (the light
14196
+ * frame) and 8.84 in dark, inside the 4.48 to 8.50 the soft steps span. The
14197
+ * hover overlay stands 3.03, on the floor, and the inset well 1.79, under it.
14198
+ */
14199
+ --crewlet-status-dot-halo: var(--color-surface-pressed);
12808
14200
  flex: none;
12809
14201
  }
12810
14202
 
12811
14203
  .crewlet-status-dot--info {
12812
14204
  background: var(--color-feedback-info);
14205
+ --crewlet-status-dot-halo: var(--color-feedback-info-soft);
12813
14206
  }
12814
14207
 
12815
14208
  .crewlet-status-dot--success {
12816
14209
  background: var(--color-feedback-success);
14210
+ --crewlet-status-dot-halo: var(--color-feedback-success-soft);
12817
14211
  }
12818
14212
 
12819
14213
  .crewlet-status-dot--warning {
12820
14214
  background: var(--color-feedback-warning);
14215
+ --crewlet-status-dot-halo: var(--color-feedback-warning-soft);
12821
14216
  }
12822
14217
 
12823
14218
  .crewlet-status-dot--danger {
12824
14219
  background: var(--color-feedback-danger);
14220
+ --crewlet-status-dot-halo: var(--color-feedback-danger-soft);
12825
14221
  }
12826
14222
 
12827
14223
  .crewlet-status-dot--brand {
12828
14224
  background: var(--color-brand-accent);
14225
+ --crewlet-status-dot-halo: var(--color-brand-accent-soft);
14226
+ }
14227
+
14228
+ /*
14229
+ * STILL HAPPENING: a halo breathes out round the dot and back in, the approved
14230
+ * design's working pulse. Five things are deliberate.
14231
+ *
14232
+ * THE DOT NEVER FADES. The halo is a box-shadow and it is the only property
14233
+ * the keyframes touch, so the fill stays at the step measured to 3:1 through
14234
+ * the whole round. The pulse this replaced faded the dot itself to 0.35, and
14235
+ * at the bottom of that fade every fill measured 1.35:1 to 2.17:1 against the
14236
+ * surfaces it sits on: for part of every round, a mark under its own floor.
14237
+ *
14238
+ * NOR DOES THE HALO TOUCH IT. The design casts the halo from the dot itself,
14239
+ * and a spread shadow starts at the edge of the box that casts it, so for the
14240
+ * whole round the dot's ground would be its own soft step on the surface
14241
+ * rather than the surface. On that ground the light info, success and warning
14242
+ * fills measure 2.65:1 to 2.95:1 (warning and success on the frame, where they
14243
+ * clear 3.00:1 and 3.01:1 bare): the same fault as the fade, smaller. So the
14244
+ * halo is cast by a RING BOX 2px outside the dot, the offset the Avatar state
14245
+ * ring and the outer focus ring stand at, and an outer shadow is never painted
14246
+ * inside the box that casts it: a band of the real ground always stands
14247
+ * between the dot and its halo, so the dot always stands on the surface its
14248
+ * fill was measured against. The fill does not move. Nothing in this kit
14249
+ * holds a mark to its own soft step, which is also why a Tag draws its dot in
14250
+ * its ink.
14251
+ *
14252
+ * A SHADOW ON A PSEUDO-ELEMENT, not an outline at the same offset, because an
14253
+ * outline's width is snapped to whole device pixels, as a border's is: at 1x
14254
+ * a width breathing to 3px is drawn 1px and then 2px and reaches 3px for an
14255
+ * instant, a flicker between two rings rather than a breath, where a spread
14256
+ * shadow grows smoothly. The ring box is absolutely positioned, so it takes
14257
+ * no room, and the pulsing dot is its containing block through a rule written
14258
+ * in :where(), which weighs nothing, so a position of your own on the dot
14259
+ * still wins, and any position but static keeps the ring on it.
14260
+ *
14261
+ * IT REACHES THE DESIGN'S 5PX, 2 of ground and 3 of halo, painted outside
14262
+ * every box, so it moves nothing beside the dot. Like the 7px it surrounds,
14263
+ * it is the measure of this one mark and is fixed at every density.
14264
+ *
14265
+ * ONE ROUND IS --motion-duration-breath, which is a PERIOD rather than a
14266
+ * transition: out by the half, back by the end, and no `alternate`, which
14267
+ * would play each half as a whole duration and take twice as long. That is
14268
+ * 0.45 rounds a second, far under the three flashes a second that are a
14269
+ * seizure risk, and the in-out ease makes both ends a rest. The halo is read
14270
+ * through the custom property each tone sets above, which the ring box
14271
+ * inherits, so whichever tone pulses breathes in its own soft step.
14272
+ */
14273
+ :where(.crewlet-status-dot.is-pulsing) {
14274
+ position: relative;
12829
14275
  }
12830
14276
 
12831
- .crewlet-status-dot--phase-onboarding {
12832
- background: var(--color-phase-onboarding);
14277
+ .crewlet-status-dot.is-pulsing::after {
14278
+ content: '';
14279
+ position: absolute;
14280
+ inset: -2px;
14281
+ border-radius: var(--radius-circle);
14282
+ /* Paint, never a target: the box reaches 2px past the dot. */
14283
+ pointer-events: none;
14284
+ animation: crewlet-status-dot-pulse var(--motion-duration-breath) var(--motion-easing-in-out) infinite;
12833
14285
  }
12834
14286
 
12835
- .crewlet-status-dot--phase-execute {
12836
- background: var(--color-phase-execute);
12837
- }
14287
+ /*
14288
+ * The spread moves and nothing else: the rests and the peak are one shadow in
14289
+ * one colour, so the only thing that interpolates is how far it reaches.
14290
+ */
14291
+ @keyframes crewlet-status-dot-pulse {
14292
+ 0%,
14293
+ 100% {
14294
+ box-shadow: 0 0 0 0 var(--crewlet-status-dot-halo);
14295
+ }
12838
14296
 
12839
- .crewlet-status-dot--phase-review {
12840
- background: var(--color-phase-review);
14297
+ 50% {
14298
+ box-shadow: 0 0 0 3px var(--crewlet-status-dot-halo);
14299
+ }
12841
14300
  }
12842
14301
 
12843
14302
  /*
12844
- * Still happening. Three things are deliberate: the pulse never goes to
12845
- * nothing, because a mark that disappears reads as a fault rather than as work
12846
- * in progress; it alternates rather than sawtooths, so the mark comes back the
12847
- * way it went; and the round trip is 1.8s, which is the engine's own breath
12848
- * and is 0.55 flashes a second, well clear of the three that are a seizure
12849
- * risk. Three of the slow step each way makes that round trip.
14303
+ * A DOT WITH ITS WORD: one line, the dot and then the word, the way every
14304
+ * dot in this kit is meant to be read.
14305
+ *
14306
+ * THE GAP CLEARS THE HALO. A pulsing dot's halo reaches 5px past its edge, 2
14307
+ * of ground and 3 of halo, painted outside every box, so it takes no room and
14308
+ * a gap narrower than that puts the halo on the first letter at every peak:
14309
+ * at the 4px an ordinary mark stands off its word, it struck the R of
14310
+ * "Reviewing". 7px is that reach and 2px of ground on the far side of it, the
14311
+ * same band that stands between the dot and its halo, so at the peak the word
14312
+ * stands off the halo exactly as the halo stands off the dot. It is written in
14313
+ * pixels, not a spacing step, because what it clears is fixed at every
14314
+ * density like the dot and the halo themselves, and it is the same for EVERY
14315
+ * tone, pulsing or not, so a column of statuses starts its words on one line
14316
+ * whichever of them is breathing.
12850
14317
  */
12851
- .crewlet-status-dot.is-pulsing {
12852
- animation: crewlet-status-dot-pulse calc(var(--motion-duration-slow) * 3) var(--motion-easing-default) infinite
12853
- alternate;
14318
+ .crewlet-status {
14319
+ display: inline-flex;
14320
+ align-items: center;
14321
+ gap: 7px;
14322
+ min-width: 0;
14323
+ max-width: 100%;
12854
14324
  }
12855
14325
 
12856
- @keyframes crewlet-status-dot-pulse {
12857
- from {
12858
- opacity: 1;
12859
- }
12860
- to {
12861
- opacity: 0.35;
12862
- }
14326
+ /* A status is one line, and the word is what gives way: the dot never does. */
14327
+ .crewlet-status__label {
14328
+ min-width: 0;
14329
+ overflow: hidden;
14330
+ text-overflow: ellipsis;
14331
+ white-space: nowrap;
12863
14332
  }
12864
14333
 
12865
14334
  /*
12866
- * A mark that cannot move should not pretend to. The dot still reads as its
12867
- * tone, and the word beside it still says what is happening.
14335
+ * HELD, not slowed: a mark that loops for as long as the work runs is exactly
14336
+ * what the setting is for. The stop names the selector that starts the pulse
14337
+ * and comes after it, so it wins on source order at the same specificity,
14338
+ * which is the pairing the package's literal check holds every stylesheet to.
14339
+ * The dot rests at its own fill with no halo, and the word beside it still
14340
+ * says the work is under way.
12868
14341
  */
12869
14342
  @media (prefers-reduced-motion: reduce) {
12870
- .crewlet-status-dot.is-pulsing {
14343
+ .crewlet-status-dot.is-pulsing::after {
14344
+ animation: none;
14345
+ }
14346
+ }
14347
+
14348
+
14349
+ /* Stepper-HW4JM3YH.css */
14350
+ /*
14351
+ * The stepper: where a sequence has got to (Stepper.tsx).
14352
+ *
14353
+ * THE APPROVED DESIGN'S STEP ROW. Each step is a 20px pill inside the default
14354
+ * hairline, the 11px step at the medium weight, 8px inside each end and 5px
14355
+ * between a mark and the word; two pills are joined by a 10px rule in the
14356
+ * strong hairline's colour with 6px either side of it. A finished step is the
14357
+ * secondary ink behind a check, the current step its tone's soft tint under
14358
+ * its ink behind its dot, and a step still to come the tertiary ink.
14359
+ *
14360
+ * EVERY INK IS A MEASURED PAIR. The secondary and tertiary steps are held to
14361
+ * 4.5:1 on every opaque rung, and each tone's ink to 4.5:1 on its own soft
14362
+ * tint over every rung, by the palette suite in @crewlethq/tokens; the pill
14363
+ * draws nothing else. The current pill is the design's `work-soft` under
14364
+ * `work-ink` in the default tone, and a Tag's colours in every tone, which is
14365
+ * what a chip naming a state is in this kit.
14366
+ */
14367
+
14368
+ .crewlet-stepper {
14369
+ display: flex;
14370
+ flex-wrap: wrap;
14371
+ align-items: center;
14372
+ /* The design's 6px between a pill and the rule beside it: a step and a half. */
14373
+ gap: calc(var(--spacing-1) * 1.5);
14374
+ min-width: 0;
14375
+ margin: 0;
14376
+ padding: 0;
14377
+ list-style: none;
14378
+ }
14379
+
14380
+ .crewlet-stepper__step {
14381
+ display: inline-flex;
14382
+ align-items: center;
14383
+ gap: calc(var(--spacing-1) * 1.5);
14384
+ min-width: 0;
14385
+ }
14386
+
14387
+ /*
14388
+ * THE RULE BETWEEN TWO STEPS is drawn by the second of them, so a sequence of
14389
+ * one draws none and nothing trails the last. A pseudo-element, because it is
14390
+ * furniture: it carries nothing a reader has to be told, and the list already
14391
+ * says the steps are in order. 10px by a hairline, the measure of this one
14392
+ * mark, and fixed at every density as a hairline is.
14393
+ */
14394
+ .crewlet-stepper__step + .crewlet-stepper__step::before {
14395
+ content: '';
14396
+ flex: none;
14397
+ width: 10px;
14398
+ height: 1px;
14399
+ background: var(--color-border-strong);
14400
+ }
14401
+
14402
+ .crewlet-stepper__chip {
14403
+ display: inline-flex;
14404
+ align-items: center;
14405
+ /* The design's 5px between the check or the dot and the word. */
14406
+ gap: calc(var(--spacing-1) * 1.25);
14407
+ box-sizing: border-box;
14408
+ /* The design's 20px pill, which follows the density with every other step
14409
+ height in the kit. It labels and takes no press, so the 24px target floor
14410
+ is not its to clear. */
14411
+ height: calc(20px * var(--density, 1));
14412
+ max-width: 100%;
14413
+ padding: 0 var(--spacing-2);
14414
+ border: 1px solid var(--color-border-default);
14415
+ border-radius: var(--radius-pill);
14416
+ color: var(--color-text-tertiary);
14417
+ font-family: var(--font-family-sans);
14418
+ font-size: var(--font-size-2xs);
14419
+ font-weight: var(--font-weight-medium);
14420
+ line-height: 1;
14421
+ white-space: nowrap;
14422
+ }
14423
+
14424
+ .crewlet-stepper__label {
14425
+ min-width: 0;
14426
+ overflow: hidden;
14427
+ text-overflow: ellipsis;
14428
+ }
14429
+
14430
+ .crewlet-stepper__check {
14431
+ flex: none;
14432
+ }
14433
+
14434
+ .crewlet-stepper__step--done > .crewlet-stepper__chip {
14435
+ color: var(--color-text-secondary);
14436
+ }
14437
+
14438
+ /*
14439
+ * THE CURRENT STEP, in its tone. The hairline goes transparent rather than
14440
+ * away, so the pill keeps its box and the row does not move by a pixel as the
14441
+ * current step advances along it, and so forced-colors mode, which draws a
14442
+ * transparent border in the system's own colour, still outlines it.
14443
+ */
14444
+ .crewlet-stepper--info .crewlet-stepper__step--current > .crewlet-stepper__chip {
14445
+ border-color: transparent;
14446
+ background: var(--color-feedback-info-soft);
14447
+ color: var(--color-feedback-info-ink);
14448
+ }
14449
+
14450
+ .crewlet-stepper--success .crewlet-stepper__step--current > .crewlet-stepper__chip {
14451
+ border-color: transparent;
14452
+ background: var(--color-feedback-success-soft);
14453
+ color: var(--color-feedback-success-ink);
14454
+ }
14455
+
14456
+ .crewlet-stepper--warning .crewlet-stepper__step--current > .crewlet-stepper__chip {
14457
+ border-color: transparent;
14458
+ background: var(--color-feedback-warning-soft);
14459
+ color: var(--color-feedback-warning-ink);
14460
+ }
14461
+
14462
+ .crewlet-stepper--danger .crewlet-stepper__step--current > .crewlet-stepper__chip {
14463
+ border-color: transparent;
14464
+ background: var(--color-feedback-danger-soft);
14465
+ color: var(--color-feedback-danger-ink);
14466
+ }
14467
+
14468
+ .crewlet-stepper--brand .crewlet-stepper__step--current > .crewlet-stepper__chip {
14469
+ border-color: transparent;
14470
+ background: var(--color-brand-accent-soft);
14471
+ color: var(--color-brand-accent-ink);
14472
+ }
14473
+
14474
+ /*
14475
+ * INSIDE THE PILL THE DOT IS THE PILL'S OWN INK, as a Tag's is, and for the
14476
+ * Tag's reason: StatusDot paints the fill step, measured as a mark on the
14477
+ * opaque rungs, and here it stands on the tone's soft tint instead, where
14478
+ * nothing measures it. The ink is the step that IS measured on that tint, at
14479
+ * 4.5:1, and the colour of the word beside it. A pulsing dot keeps
14480
+ * StatusDot's halo, the same soft step drawn once more over the pill, which
14481
+ * stands dE 3.92 off it at the least (the light warning pill on the frame).
14482
+ *
14483
+ * Two classes deep, so it beats StatusDot's own tone rule whichever order the
14484
+ * bundle writes the two files in.
14485
+ */
14486
+ .crewlet-stepper .crewlet-stepper__dot {
14487
+ background: currentColor;
14488
+ }
14489
+
14490
+ /*
14491
+ * FORCED COLORS repaints every background to Canvas, which takes the current
14492
+ * step's tint and its dot, so the one step the row is about would read like
14493
+ * any other. The current pill is drawn as the system draws a selection,
14494
+ * HighlightText on Highlight, with its dot in the same ink, and the rule
14495
+ * between two steps in GrayText; the chips' hairlines are borders, which the
14496
+ * mode keeps in its own colour.
14497
+ *
14498
+ * THE CURRENT PILL OPTS OUT OF THE ADJUSTMENT, which is safe only because
14499
+ * every colour it draws in that mode is a system colour. Left to it, Chromium
14500
+ * paints a Canvas backplate behind every run of text, and HighlightText is
14501
+ * written for Highlight, not for Canvas: in a dark high-contrast theme the
14502
+ * step's words drew black on black (measured in Chromium 153 with the mode
14503
+ * emulated). Opting out also keeps shadows, so the pulsing dot's halo, which
14504
+ * is the tone's soft tint and no system colour, is held still inside it.
14505
+ */
14506
+ @media (forced-colors: active) {
14507
+ .crewlet-stepper .crewlet-stepper__step--current > .crewlet-stepper__chip {
14508
+ forced-color-adjust: none;
14509
+ border-color: Highlight;
14510
+ background: Highlight;
14511
+ color: HighlightText;
14512
+ }
14513
+
14514
+ .crewlet-stepper .crewlet-stepper__dot {
14515
+ background: HighlightText;
14516
+ }
14517
+
14518
+ .crewlet-stepper .crewlet-stepper__dot.is-pulsing::after {
12871
14519
  animation: none;
12872
14520
  }
14521
+
14522
+ .crewlet-stepper__step + .crewlet-stepper__step::before {
14523
+ background: GrayText;
14524
+ }
12873
14525
  }
12874
14526
 
12875
14527
 
@@ -13217,7 +14869,7 @@ svg.crewlet-select__chevron {
13217
14869
  }
13218
14870
 
13219
14871
 
13220
- /* Tabs-MJ2E3VPK.css */
14872
+ /* Tabs-XCNPHA7B.css */
13221
14873
  /*
13222
14874
  * The pill register: Tabs and SegmentedControl.
13223
14875
  *
@@ -13304,21 +14956,29 @@ svg.crewlet-select__chevron {
13304
14956
 
13305
14957
  /* ─── Pill (segmented control) ────────────────────────────────── */
13306
14958
  /*
13307
- * A WELL WITH CHIPS IN IT, not a panel with buttons in it. The container is
13308
- * the inset surface and carries no boundary of its own: the chip that is on
13309
- * is what the reader looks for, and it is found by being the one thing lifted
13310
- * off the well rather than by a border around the whole set.
14959
+ * A WELL WITH CHIPS IN IT, not a panel with buttons in it: the approved
14960
+ * design's segmented control. The well is the RAISED rung inside the default
14961
+ * hairline, and the chip that is on is the CARD's own ground, lifted by a
14962
+ * hairline and a small shadow, so it is found by being the one thing that
14963
+ * matches the panel the row sits on.
14964
+ *
14965
+ * A RUNG AND A HAIRLINE, NOT A TRANSLUCENT WELL. The inset overlay it used to
14966
+ * be stands almost nowhere off a card, so the well had no extent and the
14967
+ * chips floated; the raised rung is held a visible step above the card by the
14968
+ * palette suite, and the hairline finds it on any other ground.
13311
14969
  *
13312
14970
  * The inset is 2px, which is smaller than the scale's first step on purpose:
13313
- * it is the gap a chip needs to read as sitting IN the well, and a 4px one
13314
- * makes the row a control step taller than the button beside it.
14971
+ * it is the gap a chip needs to read as sitting IN the well. With the 1px
14972
+ * boundary it is three pixels a side, and a 24px chip makes a 30px row: the
14973
+ * medium control step, the height of the button beside it.
13315
14974
  */
13316
14975
  .crewlet-tabs--pill {
13317
14976
  --crewlet-tabs-pill-inset: 2px;
13318
14977
 
13319
14978
  gap: var(--crewlet-tabs-pill-inset);
13320
14979
  padding: var(--crewlet-tabs-pill-inset);
13321
- background: var(--color-surface-inset);
14980
+ background: var(--color-surface-elevated);
14981
+ border: 1px solid var(--color-border-default);
13322
14982
  border-radius: var(--radius-md);
13323
14983
  width: fit-content;
13324
14984
  }
@@ -13406,19 +15066,22 @@ svg.crewlet-select__chevron {
13406
15066
 
13407
15067
  /*
13408
15068
  * A CHIP STANDS SHORTER THAN THE CONTROL IT SITS BESIDE, and it is the row
13409
- * that has to match: the well adds its inset above and below every chip, so a
13410
- * chip at a full control step makes the whole segmented row taller than the
13411
- * button next to it. Six pixels off the md step and four off the sm one is
13412
- * what the engine's own segmented row has always drawn.
13413
- *
13414
- * AND THE FLOOR IS TAKEN AGAIN AFTER THE SUBTRACTION. --size-control-sm
13415
- * carries a 24px floor of its own, but subtracting from a step subtracts from
13416
- * its floor too: at compact density `calc(var(--size-control-sm) - 4px)` is
13417
- * 20px, under the target a finger can hit. max() against --size-target-min
13418
- * leaves the value exactly 24px at density 1 and reachable at every other.
13419
- *
13420
- * The corner is one hairline tighter than the well around it rather than a
13421
- * step of its own, which is what reads as a chip sitting IN the well.
15069
+ * that has to match: the well adds its boundary and its inset above and below
15070
+ * every chip, so a chip at a full control step makes the whole segmented row
15071
+ * taller than the button next to it. Six pixels off the md step is exactly
15072
+ * that boundary and inset, and it leaves the design's 24px chip in a 30px row.
15073
+ *
15074
+ * AND THE FLOOR IS TAKEN AGAIN AFTER THE SUBTRACTION. Subtracting from a step
15075
+ * subtracts from its floor too: at compact density
15076
+ * `calc(var(--size-control-md) - 6px)` is 18.6px, under the target a finger
15077
+ * can hit. max() against --size-target-min holds every density at 24px or
15078
+ * more, and at density 1 the two agree.
15079
+ *
15080
+ * The corner is the small radius, the design's: the well's 8px less its 1px
15081
+ * boundary and 2px inset is 5px, and a chip a pixel rounder than that
15082
+ * concentric curve is what reads as a chip sitting IN the well rather than a
15083
+ * second well inside it. The side pad is the design's 10px, two steps and a
15084
+ * half.
13422
15085
  *
13423
15086
  * AND THE CONTENT IS CENTRED IN THE CHIP. It was aligned to the start, for a
13424
15087
  * chip stretched on a grid track, which is a case the pill chrome's own
@@ -13432,8 +15095,9 @@ svg.crewlet-select__chevron {
13432
15095
  */
13433
15096
  .crewlet-tabs--pill .crewlet-tabs__tab {
13434
15097
  min-height: max(var(--size-target-min), calc(var(--size-control-md) - 6px));
13435
- padding: 0 var(--spacing-3);
13436
- border-radius: var(--radius-chip);
15098
+ padding: 0 calc(var(--spacing-2) + var(--spacing-1) / 2);
15099
+ border-radius: var(--radius-sm);
15100
+ color: var(--color-text-secondary);
13437
15101
  font-size: var(--font-size-xs);
13438
15102
  }
13439
15103
 
@@ -13441,12 +15105,12 @@ svg.crewlet-select__chevron {
13441
15105
  * THE SMALL CHIP IS THE QUIET ONE. It is the register the rail's foot wears,
13442
15106
  * where a theme row and a density row sit beside a status pill and are read
13443
15107
  * past rather than read, so its side pad is the scale's first step rather
13444
- * than its second and its glyph is the step under the label register's.
15108
+ * than two and a half and its glyph is the step under the label register's.
13445
15109
  *
13446
- * The height does not follow: at the reader's default density this chip is
13447
- * already exactly --size-target-min, so a shorter one would be a target a
13448
- * finger misses. The whole reduction comes out of the width, where the pad is
13449
- * spent, and the floor above catches what is left.
15110
+ * The height does not follow: the medium chip is already exactly
15111
+ * --size-target-min at the reader's default density, so a shorter one would be
15112
+ * a target a finger misses. The whole reduction comes out of the width, where
15113
+ * the pad is spent, and the floor catches what the subtraction leaves.
13450
15114
  */
13451
15115
  .crewlet-tabs--pill.crewlet-tabs--sm .crewlet-tabs__tab {
13452
15116
  min-height: max(var(--size-target-min), calc(var(--size-control-sm) - 4px));
@@ -13473,9 +15137,17 @@ svg.crewlet-select__chevron {
13473
15137
  color: var(--color-text-primary);
13474
15138
  }
13475
15139
 
15140
+ /*
15141
+ * The chip that is on: the CARD's ground and the primary ink, lifted by the
15142
+ * default hairline drawn round it and the smallest shadow under it, the
15143
+ * design's chip. The hairline is the half that finds it: on a dark palette a
15144
+ * shadow over a dark well is nearly invisible. Both are one shadow list, and
15145
+ * neither token in it is ever `none`, which would drop the whole list.
15146
+ */
13476
15147
  .crewlet-tabs--pill .crewlet-tabs__tab.is-active {
13477
15148
  background: var(--color-surface-subtle);
13478
- box-shadow: var(--shadow-xs);
15149
+ color: var(--color-text-primary);
15150
+ box-shadow: var(--shadow-xs), 0 0 0 1px var(--color-border-default);
13479
15151
  }
13480
15152
 
13481
15153
  /*
@@ -13527,9 +15199,9 @@ svg.crewlet-select__chevron {
13527
15199
  }
13528
15200
 
13529
15201
 
13530
- /* Tag-VNZEYLB6.css */
15202
+ /* Tag-GBE7LQJP.css */
13531
15203
  /*
13532
- * The tag: a small pill naming a state, a phase or a value.
15204
+ * The tag: a small pill naming a state, a category or a value.
13533
15205
  *
13534
15206
  * THREE VARIABLES CARRY EVERY VARIANT. A tag is its tone's `soft` tint under
13535
15207
  * its tone's `ink`, with the `line` step as the boundary it grows when it can
@@ -13549,39 +15221,49 @@ svg.crewlet-select__chevron {
13549
15221
 
13550
15222
  .crewlet-tag {
13551
15223
  /*
13552
- * THE ENGINE'S BADGE. Its line box is 11px at the document's 1.5 leading
13553
- * plus a pixel of padding and a pixel of border on each side, which lands on
13554
- * 20.5px; the step below is the whole pixel that renders, and it scales with
13555
- * density the way every size token does.
15224
+ * THE APPROVED DESIGN'S PILL: 22px tall with fully round ends, the caption
15225
+ * step at the medium weight, and 9px of room inside each end, which is the
15226
+ * step a rounded end eats before the first letter clears it.
13556
15227
  *
13557
15228
  * The height is a STEP and the floor is separate, because the two answer
13558
- * different questions. A tag that only labels takes the engine's geometry
13559
- * exactly. A tag that ACTS is a pointer target, and 20px fails WCAG 2.2, so
13560
- * it takes the 24px floor as well: the engine draws its actionable badge at
13561
- * the inert one's height, which is the one place its look and the target
13562
- * rule disagree. Nothing else about the pill changes, so a row of tags still
13563
- * reads as one set.
15229
+ * different questions. A tag that only labels takes the design's geometry
15230
+ * exactly. A tag that ACTS is a pointer target, and 22px fails WCAG 2.2, so
15231
+ * it takes the 24px floor as well. Nothing else about the pill changes, so a
15232
+ * row of tags still reads as one set.
15233
+ *
15234
+ * THE NEUTRAL PILL IS THE RAISED RUNG under the secondary ink, the design's
15235
+ * quiet pill: a category, a count, a word that is not a state. Every other
15236
+ * variant below is its tone's soft tint under its ink.
15237
+ *
15238
+ * The boundary at rest is `--crewlet-tag-edge`: transparent for a tinted
15239
+ * pill, whose hue already separates it from any neutral ground, and the
15240
+ * strong border step for the neutral one (see its rule below).
13564
15241
  */
13565
- --crewlet-tag-height: calc(20px * var(--density, 1));
15242
+ --crewlet-tag-height: calc(22px * var(--density, 1));
13566
15243
  --crewlet-tag-floor: 0px;
13567
- --crewlet-tag-fill: var(--color-surface-inset);
15244
+ /* The design's 9px inside each round end: two steps and a quarter, so it
15245
+ follows the density with every other gap. The remove control and the
15246
+ press half of a split pill read it too, to reach the pill's own ends. */
15247
+ --crewlet-tag-pad: calc(var(--spacing-2) + var(--spacing-1) / 4);
15248
+ --crewlet-tag-fill: var(--color-surface-elevated);
13568
15249
  --crewlet-tag-ink: var(--color-text-secondary);
13569
15250
  --crewlet-tag-line: var(--color-border-hover);
15251
+ --crewlet-tag-edge: transparent;
13570
15252
 
13571
15253
  display: inline-flex;
13572
15254
  align-items: center;
13573
- gap: var(--spacing-1);
15255
+ /* The design's 6px between a dot or a glyph and the word: a step and a
15256
+ half. */
15257
+ gap: calc(var(--spacing-1) * 1.5);
13574
15258
  height: max(var(--crewlet-tag-height), var(--crewlet-tag-floor));
13575
- padding: 0 var(--spacing-2);
13576
- border: 1px solid transparent;
13577
- border-radius: var(--radius-xs);
15259
+ padding: 0 var(--crewlet-tag-pad);
15260
+ border: 1px solid var(--crewlet-tag-edge);
15261
+ border-radius: var(--radius-pill);
13578
15262
  background: var(--crewlet-tag-fill);
13579
15263
  color: var(--crewlet-tag-ink);
13580
15264
  font-family: var(--font-family-sans);
13581
- font-size: var(--font-size-2xs);
15265
+ font-size: var(--font-size-xs);
13582
15266
  font-weight: var(--font-weight-medium);
13583
- /* The engine tracks the badge a hundredth of an em open, which is the
13584
- normal step at this size: a hundredth of 11px is a tenth of a pixel. */
13585
15267
  letter-spacing: var(--font-letter-spacing-normal);
13586
15268
  line-height: 1;
13587
15269
  /* A tag is an atomic token: its label never breaks across lines inside the
@@ -13634,53 +15316,54 @@ svg.crewlet-select__chevron {
13634
15316
  /* ── sizes ─────────────────────────────────────────────────────────────── */
13635
15317
 
13636
15318
  /*
13637
- * THREE HEIGHTS OF ONE BADGE. The engine draws a single pill and spends its
15319
+ * THREE HEIGHTS OF ONE PILL. The design draws a single pill and spends its
13638
15320
  * variation on tone rather than on size, so the steps here differ by how much
13639
- * room the pill takes and not by what it is: the type, the radius, the weight
13640
- * and the tracking are the engine's at every one of them.
15321
+ * room the pill takes and not by what it is: the radius, the weight and the
15322
+ * tracking are the design's at every one of them.
13641
15323
  *
13642
- * xs is an 18px pill and is NON-INTERACTIVE for that reason: it is under the
13643
- * 24px target floor, and the component refuses a press at this step. It is for
13644
- * a mark inside a dense row, where the label is still the carrier.
15324
+ * xs is the design's 18px count pill, the one a rail row carries, and is
15325
+ * NON-INTERACTIVE for that reason: it is under the 24px target floor, and the
15326
+ * component refuses a press at this step. It is for a mark inside a dense
15327
+ * row, where the label is still the carrier, and it takes the micro step, the
15328
+ * design's 10.5px at the scale's floor.
13645
15329
  *
13646
15330
  * EVERY STEP SCALES WITH DENSITY, which is not decoration: written as a flat
13647
- * 18px, this one stayed put while the badge above it came down to
13648
- * 20 x 0.82 = 16.4px, so the dense mark rendered TALLER than the badge it is
13649
- * meant to sit inside a row of. A step that does not move with the rest of the
13650
- * scale is a step that overtakes one of its neighbours at some density.
15331
+ * 18px, this one stayed put while the pill above it came down with the
15332
+ * density, so the dense mark rendered TALLER than the pill it is meant to sit
15333
+ * inside a row of. A step that does not move with the rest of the scale is a
15334
+ * step that overtakes one of its neighbours at some density.
13651
15335
  */
13652
15336
  .crewlet-tag--xs {
13653
15337
  --crewlet-tag-height: calc(18px * var(--density, 1));
13654
- padding: 0 var(--spacing-1);
13655
- gap: 3px;
15338
+ --crewlet-tag-pad: calc(var(--spacing-1) * 1.5);
15339
+ gap: var(--spacing-1);
15340
+ font-size: var(--font-size-2xs);
13656
15341
  }
13657
15342
 
13658
- /* The engine's badge, and the default. */
15343
+ /* The design's pill, and the default. */
13659
15344
  .crewlet-tag--sm {
13660
- --crewlet-tag-height: calc(20px * var(--density, 1));
15345
+ --crewlet-tag-height: calc(22px * var(--density, 1));
13661
15346
  }
13662
15347
 
13663
15348
  /* The md step is a small control's own height, so a tag and a small button in
13664
- one toolbar sit on the same baseline. One type step up with it: 11px inside
13665
- a 28px pill reads as a label that lost its box. */
15349
+ one toolbar sit on the same line. */
13666
15350
  .crewlet-tag--md {
13667
15351
  --crewlet-tag-height: var(--size-control-sm);
13668
- font-size: var(--font-size-xs);
13669
15352
  }
13670
15353
 
13671
15354
  /*
13672
15355
  * A TAG THAT ACTS CLEARS 24px, at every density and every step. Last among the
13673
15356
  * steps so it is the floor whichever one is drawn, and a floor rather than a
13674
- * height so the md step keeps its 28px.
15357
+ * height so the md step keeps its 26px.
13675
15358
  */
13676
15359
  .crewlet-tag--acts {
13677
15360
  --crewlet-tag-floor: max(24px, calc(24px * var(--density, 1)));
13678
15361
  }
13679
15362
 
13680
- /* One step down from the sans, where there is a step to take: a mono face
13681
- draws larger than the sans at the same size, and a machine value beside a
13682
- word has to read as the same line. At the two smaller steps the sans is
13683
- already at the bottom of the scale and the mono stays beside it. */
15363
+ /* One step down from the sans: a mono face draws larger than the sans at the
15364
+ same size, and a machine value beside a word has to read as the same line.
15365
+ At xs the sans is already at the bottom of the scale and the mono stays
15366
+ beside it. */
13684
15367
  .crewlet-tag--monospace .crewlet-tag__label {
13685
15368
  font-family: var(--font-family-mono);
13686
15369
  font-size: var(--font-size-2xs);
@@ -13718,43 +15401,6 @@ svg.crewlet-select__chevron {
13718
15401
  --crewlet-tag-line: var(--color-brand-accent-soft-strong);
13719
15402
  }
13720
15403
 
13721
- /*
13722
- * The phase family has a soft step and no line step, because nothing else in
13723
- * the system needed a phase boundary. The ink is the boundary here: it is the
13724
- * same hue at a strength a 1px rule can be seen at, and a border is not text,
13725
- * so the rule that an ink step is never a BACKGROUND is untouched.
13726
- *
13727
- * A PHASE IS SET IN THE MICRO-LABEL REGISTER, uppercase and tracked open,
13728
- * where a state is set in the badge's own. Phase is the one categorical
13729
- * identity the product spends colour on outside a chart, and it is what a
13730
- * reader follows across four screens; the second register is what separates it
13731
- * at a glance from the state badge sitting beside it on the same row.
13732
- */
13733
- .crewlet-tag--phase-onboarding,
13734
- .crewlet-tag--phase-execute,
13735
- .crewlet-tag--phase-review {
13736
- letter-spacing: var(--font-letter-spacing-wide);
13737
- text-transform: uppercase;
13738
- }
13739
-
13740
- .crewlet-tag--phase-onboarding {
13741
- --crewlet-tag-fill: var(--color-phase-onboarding-soft);
13742
- --crewlet-tag-ink: var(--color-phase-onboarding-ink);
13743
- --crewlet-tag-line: var(--color-phase-onboarding-ink);
13744
- }
13745
-
13746
- .crewlet-tag--phase-execute {
13747
- --crewlet-tag-fill: var(--color-phase-execute-soft);
13748
- --crewlet-tag-ink: var(--color-phase-execute-ink);
13749
- --crewlet-tag-line: var(--color-phase-execute-ink);
13750
- }
13751
-
13752
- .crewlet-tag--phase-review {
13753
- --crewlet-tag-fill: var(--color-phase-review-soft);
13754
- --crewlet-tag-ink: var(--color-phase-review-ink);
13755
- --crewlet-tag-line: var(--color-phase-review-ink);
13756
- }
13757
-
13758
15404
  /* ── appearance ────────────────────────────────────────────────────────── */
13759
15405
 
13760
15406
  /*
@@ -13767,6 +15413,31 @@ svg.crewlet-select__chevron {
13767
15413
  border-color: var(--crewlet-tag-line);
13768
15414
  }
13769
15415
 
15416
+ /*
15417
+ * THE NEUTRAL PILL CARRIES A BOUNDARY, because its fill IS a surface. The
15418
+ * raised rung is also the ground of a palette's lead block, a raised card and
15419
+ * the rail's current row, and on any of them a raised pill with a transparent
15420
+ * boundary was the colour of what it stood on: the pill vanished and its words
15421
+ * read as loose text with odd gaps between them.
15422
+ *
15423
+ * THE STRONG STEP, NOT THE DEFAULT ONE. The design's own chip is found by 1px
15424
+ * of its line step (`.chip`), which is the default border here, and that
15425
+ * measured under the hairline dE of 3 on five grounds a pill lands on: 2.76 on
15426
+ * the light frame, 2.86 on a pressed row over a light card, 2.77 and 2.71 on an
15427
+ * inset well inside a raised surface, and 2.08 on a hovered row over the dark
15428
+ * sheet. The strong step is the design's line-2, the boundary it draws round a
15429
+ * key cap (`.kbd`), and it clears 3 on every rung and every overlay in both
15430
+ * themes. The suite measures all of them.
15431
+ *
15432
+ * The hover takes the strong step once more, because the press line a tinted
15433
+ * pill moves to on hover IS the strong step in both themes, and a hover that
15434
+ * lands on the resting boundary draws no hover at all.
15435
+ */
15436
+ .crewlet-tag--neutral.crewlet-tag--soft {
15437
+ --crewlet-tag-edge: var(--color-border-strong);
15438
+ --crewlet-tag-line: var(--color-border-strong-hover);
15439
+ }
15440
+
13770
15441
  /* The neutral outline is the engine's `.badge.outline`: the hairline step as
13771
15442
  the boundary, and the tertiary ink, which is a quieter register than the
13772
15443
  tinted outlines keep. It is the appearance for a value that is not a state
@@ -13825,9 +15496,9 @@ svg.crewlet-select__chevron {
13825
15496
  align-self: stretch;
13826
15497
  gap: inherit;
13827
15498
  min-width: 0;
13828
- padding: 0 var(--spacing-2);
15499
+ padding: 0 var(--crewlet-tag-pad);
13829
15500
  border: 0;
13830
- border-radius: var(--radius-xs) 0 0 var(--radius-xs);
15501
+ border-radius: var(--radius-pill) 0 0 var(--radius-pill);
13831
15502
  background: transparent;
13832
15503
  /* A button inherits none of these. */
13833
15504
  color: inherit;
@@ -13884,10 +15555,10 @@ svg.crewlet-select__chevron {
13884
15555
  min-width: 24px;
13885
15556
  margin-block-start: -1px;
13886
15557
  margin-block-end: -1px;
13887
- margin-right: calc(var(--spacing-2) * -1);
15558
+ margin-right: calc(var(--crewlet-tag-pad) * -1);
13888
15559
  padding: 0 var(--spacing-1);
13889
15560
  border: 0;
13890
- border-radius: 0 var(--radius-xs) var(--radius-xs) 0;
15561
+ border-radius: 0 var(--radius-pill) var(--radius-pill) 0;
13891
15562
  background: transparent;
13892
15563
  color: inherit;
13893
15564
  cursor: pointer;
@@ -15204,7 +16875,7 @@ svg.crewlet-time-window__tick {
15204
16875
  }
15205
16876
 
15206
16877
 
15207
- /* Toolbar-IP6LXN45.css */
16878
+ /* Toolbar-HUOSMNTH.css */
15208
16879
  /*
15209
16880
  * The toolbar row.
15210
16881
  *
@@ -15244,7 +16915,9 @@ svg.crewlet-time-window__tick {
15244
16915
  display: none;
15245
16916
  }
15246
16917
 
15247
- @media (max-width: 900px) {
16918
+ /* Under the shell's breakpoint, strictly, as the shell switches: the wide
16919
+ controls fold into the overflow where the rail becomes a drawer. */
16920
+ @media (width < 1024px) {
15248
16921
  .crewlet-toolbar__wide {
15249
16922
  display: none;
15250
16923
  }
@@ -15329,7 +17002,7 @@ svg.crewlet-time-window__tick {
15329
17002
  }
15330
17003
 
15331
17004
 
15332
- /* TreeCanvas-WBNQPHC7.css */
17005
+ /* TreeCanvas-HVOV4SQN.css */
15333
17006
  /*
15334
17007
  * A hierarchy drawn as cards on a canvas (TreeCanvas.tsx).
15335
17008
  *
@@ -15363,7 +17036,10 @@ svg.crewlet-time-window__tick {
15363
17036
  .crewlet-tree-canvas__card,
15364
17037
  .crewlet-tree-canvas__links,
15365
17038
  .crewlet-tree-canvas__gap,
15366
- .crewlet-tree-canvas__margin {
17039
+ .crewlet-tree-canvas__margin,
17040
+ .crewlet-tree-canvas__group,
17041
+ .crewlet-tree-canvas__group-head,
17042
+ .crewlet-tree-canvas__group-pad {
15367
17043
  position: absolute;
15368
17044
  top: 0;
15369
17045
  left: 0;
@@ -15502,15 +17178,6 @@ svg.crewlet-time-window__tick {
15502
17178
  --crewlet-tree-canvas-card-accent: var(--color-node-blue);
15503
17179
  }
15504
17180
 
15505
- /*
15506
- * A card that stands for somebody outside the system takes the dashed edge
15507
- * every such seat wears. The BOUNDARY says it rather than a hue, so it reads
15508
- * to somebody who cannot separate the hue at all.
15509
- */
15510
- .crewlet-tree-canvas__card--outline {
15511
- border-style: dashed;
15512
- }
15513
-
15514
17181
  /*
15515
17182
  * THE NODES INSIDE THE CARD. `role="treeitem"` is this component's own
15516
17183
  * contract, handed to the caller by `ctx.item(id)`, so the inset a node sits
@@ -15670,13 +17337,13 @@ svg.crewlet-time-window__tick {
15670
17337
  /*
15671
17338
  * A reveal is a state change rather than an entrance, so under reduced motion
15672
17339
  * it simply happens. The control is still shown and still reached the same way.
17340
+ * The `node` appearance's own quiet controls are stopped in its own section,
17341
+ * below the rules that start them: named here, above those rules, the stops
17342
+ * tied with them on specificity and lost on source order.
15673
17343
  */
15674
17344
  @media (prefers-reduced-motion: reduce) {
15675
17345
  .crewlet-tree-canvas__actions,
15676
- .crewlet-tree-canvas__under,
15677
- .crewlet-tree-canvas--node .crewlet-tree-canvas__under > :not(.crewlet-add-pill),
15678
- .crewlet-tree-canvas--node .crewlet-org-node__leading,
15679
- .crewlet-tree-canvas--node .crewlet-org-node-lead__clear {
17346
+ .crewlet-tree-canvas__under {
15680
17347
  transition: none;
15681
17348
  }
15682
17349
  }
@@ -15708,6 +17375,92 @@ svg.crewlet-time-window__tick {
15708
17375
  pointer-events: none;
15709
17376
  }
15710
17377
 
17378
+ /* ---------------------------------------------------------------------------
17379
+ * A GROUP: a box round a run of sibling cards, with a label along its top.
17380
+ *
17381
+ * The approved design's unit box: a hairline on the card rung with the unit's
17382
+ * name in the tertiary ink at 12px, and the project key chip at the end of
17383
+ * that line. The hairline is `--color-border-default` over
17384
+ * `--color-surface-subtle` standing on the canvas's own ground, which is the
17385
+ * pair the palette suite already holds to a visible step (the card hairline
17386
+ * rule); a card inside the box is the same rung and is found by its own
17387
+ * hairline, exactly as a card on a sheet is.
17388
+ *
17389
+ * THE ROOM IS THE LAYOUT'S. The padding round the members is the probe below,
17390
+ * and the room above them is the header's own measured height, so the box is
17391
+ * never drawn over a card it does not hold and a branch is never run through
17392
+ * it: both are reserved by `layoutForest` before anything is placed.
17393
+ * ------------------------------------------------------------------------- */
17394
+
17395
+ /*
17396
+ * The room beside and below a group's members, as a token: `--spacing-3`,
17397
+ * which is also the label's own inset, so the label starts on the line the
17398
+ * first member's edge does.
17399
+ */
17400
+ .crewlet-tree-canvas__group-pad {
17401
+ width: var(--spacing-3);
17402
+ height: var(--spacing-3);
17403
+ visibility: hidden;
17404
+ pointer-events: none;
17405
+ }
17406
+
17407
+ /*
17408
+ * THE BOX IS DASHED, as the approved org chart draws a unit: a card's own
17409
+ * edge is solid, and a box round several cards drawn the same way read as one
17410
+ * more, larger card. A dash says the edge is a grouping rather than a thing.
17411
+ * It is the STRONG border step, the artboard's, because a dash spends half its
17412
+ * length on gaps: at the plain hairline's step the edge all but disappeared
17413
+ * against the box's own fill.
17414
+ */
17415
+ .crewlet-tree-canvas__group {
17416
+ box-sizing: border-box;
17417
+ background: var(--color-surface-subtle);
17418
+ border: 1px dashed var(--color-border-strong);
17419
+ border-radius: var(--radius-xl);
17420
+ pointer-events: none;
17421
+ }
17422
+
17423
+ /*
17424
+ * THE LABEL'S LINE, and what the room above the members is measured from: one
17425
+ * line, at the box's width, truncated rather than wrapped, because a label
17426
+ * that wrapped would move every rank below it.
17427
+ */
17428
+ .crewlet-tree-canvas__group-head {
17429
+ box-sizing: border-box;
17430
+ display: flex;
17431
+ align-items: center;
17432
+ gap: var(--spacing-2);
17433
+ padding: var(--spacing-2) var(--spacing-3);
17434
+ font-size: var(--font-size-xs);
17435
+ line-height: var(--font-line-height-snug);
17436
+ color: var(--color-text-tertiary);
17437
+ white-space: nowrap;
17438
+ pointer-events: none;
17439
+ }
17440
+
17441
+ /*
17442
+ * ON THE BOX'S OWN FILL, over the branches: a branch dropping into a member
17443
+ * passes behind the words rather than striking through them, and the fill is
17444
+ * the box's, so nothing about the label reads as a second surface.
17445
+ */
17446
+ .crewlet-tree-canvas__group-label,
17447
+ .crewlet-tree-canvas__group-lead {
17448
+ background: var(--color-surface-subtle);
17449
+ }
17450
+
17451
+ .crewlet-tree-canvas__group-label {
17452
+ min-width: 0;
17453
+ overflow: hidden;
17454
+ text-overflow: ellipsis;
17455
+ }
17456
+
17457
+ /* The key AHEAD of the name, a project key chip, never cut: the name after
17458
+ it is what gives way when the line is short. */
17459
+ .crewlet-tree-canvas__group-lead {
17460
+ display: inline-flex;
17461
+ flex: none;
17462
+ }
17463
+
15711
17464
  /* ---------------------------------------------------------------------------
15712
17465
  * THE CHART ARRIVING, AND REARRANGING.
15713
17466
  *
@@ -15724,11 +17477,16 @@ svg.crewlet-time-window__tick {
15724
17477
  * ------------------------------------------------------------------------- */
15725
17478
 
15726
17479
  .crewlet-tree-canvas__card[data-enter='waiting'],
15727
- .crewlet-tree-canvas__links path[data-enter='waiting'] {
17480
+ .crewlet-tree-canvas__links path[data-enter='waiting'],
17481
+ .crewlet-tree-canvas__group[data-enter='waiting'],
17482
+ .crewlet-tree-canvas__group-head[data-enter='waiting'] {
15728
17483
  opacity: 0;
15729
17484
  }
15730
17485
 
15731
- .crewlet-tree-canvas__card[data-enter='shown'] {
17486
+ /* A group arrives with its first member, at the card's pace. */
17487
+ .crewlet-tree-canvas__card[data-enter='shown'],
17488
+ .crewlet-tree-canvas__group[data-enter='shown'],
17489
+ .crewlet-tree-canvas__group-head[data-enter='shown'] {
15732
17490
  animation: crewlet-tree-canvas-arrive var(--motion-duration-slow) var(--motion-easing-default) both;
15733
17491
  }
15734
17492
 
@@ -15754,9 +17512,20 @@ svg.crewlet-time-window__tick {
15754
17512
  * when the setting changed.
15755
17513
  */
15756
17514
  @media (prefers-reduced-motion: reduce) {
17515
+ /* Drawn, whatever step of the entrance it had reached: a card still WAITING
17516
+ is otherwise held at nothing. */
15757
17517
  .crewlet-tree-canvas__card[data-enter],
15758
- .crewlet-tree-canvas__links path[data-enter] {
17518
+ .crewlet-tree-canvas__links path[data-enter],
17519
+ .crewlet-tree-canvas__group[data-enter],
17520
+ .crewlet-tree-canvas__group-head[data-enter] {
15759
17521
  opacity: 1;
17522
+ }
17523
+
17524
+ /* And the entrance stopped by the selectors that start it. */
17525
+ .crewlet-tree-canvas__card[data-enter='shown'],
17526
+ .crewlet-tree-canvas__links path[data-enter='shown'],
17527
+ .crewlet-tree-canvas__group[data-enter='shown'],
17528
+ .crewlet-tree-canvas__group-head[data-enter='shown'] {
15760
17529
  animation: none;
15761
17530
  }
15762
17531
  }
@@ -15768,10 +17537,11 @@ svg.crewlet-time-window__tick {
15768
17537
 
15769
17538
  /*
15770
17539
  * THE CONNECTORS ARE THE CONTENT, and they take the step that is measured to
15771
- * be resolvable. The SHAPE is `layoutConnectors`, which draws a rounded step
15772
- * from each parent's bottom into each child's top; what is decided here is only
15773
- * how dark it is, and that the joins are round so a corner reads as a turn
15774
- * rather than as two lines meeting.
17540
+ * be resolvable. The SHAPE is `layoutConnectors`, which draws an orthogonal
17541
+ * elbow from each parent's bottom into each child's top, in SVG attributes
17542
+ * the layout computes rather than in a style a policy has to allow; what is
17543
+ * decided here is only how dark and how heavy it is, and that the joins are
17544
+ * round so a corner reads as a turn rather than as two lines meeting.
15775
17545
  *
15776
17546
  * A connector is the only thing on the chart that says who reports to whom:
15777
17547
  * remove it and the picture is a scatter of cards. That makes it a graphical
@@ -15782,11 +17552,22 @@ svg.crewlet-time-window__tick {
15782
17552
  * boundary step, which the palette suite already holds at 3:1 on every ground,
15783
17553
  * measures 4.83:1 and 4.78:1. Darker than the chart this is drawn from, and
15784
17554
  * deliberately: there the hierarchy was a line a reader had to hunt for.
17555
+ *
17556
+ * THE APPROVED DESIGN DRAWS IT IN `--color-border-strong`, AND THE FLOOR WINS.
17557
+ * The artboard's connector is the strong border step at 1.5px, and on the
17558
+ * canvas's ground that step measures 1.45:1 in dark and 1.43:1 in light (1.40
17559
+ * and 1.50 on a group box's card rung): a line a reader cannot make out, for
17560
+ * the one mark that says who reports to whom. The palette suite's data-mark
17561
+ * table holds a chart's connector to 3:1 on `--color-border-control`, so the
17562
+ * value moves up the border family to the first step that clears it, 4.40:1
17563
+ * and 4.04:1 (4.25 and 4.26 on the card rung). The WEIGHT is the design's:
17564
+ * 1.5px, heavier than the hairline this used to be, so a branch between two
17565
+ * ranks of 90px cards reads as a line of the chart rather than as a seam.
15785
17566
  */
15786
17567
  .crewlet-tree-canvas__links path {
15787
17568
  fill: none;
15788
17569
  stroke: var(--color-border-control);
15789
- stroke-width: 1;
17570
+ stroke-width: 1.5;
15790
17571
  stroke-linecap: round;
15791
17572
  stroke-linejoin: round;
15792
17573
  }
@@ -16161,6 +17942,20 @@ svg.crewlet-time-window__tick {
16161
17942
  pointer-events: auto;
16162
17943
  }
16163
17944
 
17945
+ /*
17946
+ * The node's quiet controls arrive as a state change too, so under reduced
17947
+ * motion they simply appear. Stopped HERE, after the rules that start their
17948
+ * fades: the three selectors tie with those rules on specificity, so the stop
17949
+ * has to come later in the file to win.
17950
+ */
17951
+ @media (prefers-reduced-motion: reduce) {
17952
+ .crewlet-tree-canvas--node .crewlet-tree-canvas__under > :not(.crewlet-add-pill),
17953
+ .crewlet-tree-canvas--node .crewlet-org-node__leading,
17954
+ .crewlet-tree-canvas--node .crewlet-org-node-lead__clear {
17955
+ transition: none;
17956
+ }
17957
+ }
17958
+
16164
17959
  /*
16165
17960
  * THE BRANCHES ARE HEAVIER HERE. A node is half the height of a card, so a
16166
17961
  * hairline between two ranks of them is a thread; this is the console chart's
@@ -16261,12 +18056,11 @@ svg.crewlet-time-window__tick {
16261
18056
  * chart this package is drawn to match does exactly this, and every step below
16262
18057
  * is its step.
16263
18058
  *
16264
- * IT IS THE ONLY DASHED THING ON THE CHART THAT IS NOT A HUMAN SEAT, and the
16265
- * two never collide: `cardOutline` marks a node of the data and this marks a
16266
- * node that is not one yet, so no card can carry both. What tells them apart
16267
- * is the hue and the breath: a human seat's edge is the chart's own boundary
16268
- * step and does not move, and this one is the accent, with a ring outside it
16269
- * that pulses for as long as the form is open.
18059
+ * IT IS THE ONLY DASHED CARD ON THE CHART, because a dashed edge marks a
18060
+ * place nothing fills yet and this is the one card that is not a node of the
18061
+ * data. Every node's card is solid, a person's seat included: who holds a seat
18062
+ * is its badge's outline, never the card's frame, which is why the chart has
18063
+ * no second dashed card for a person to be confused with this one.
16270
18064
  *
16271
18065
  * ITS GROUND IS EVERY OTHER CARD'S. The ghost holds a real form with real
16272
18066
  * labels, helps and refusals in it, so it is NOT tinted: every contrast
@@ -16410,8 +18204,11 @@ svg.crewlet-time-window__tick {
16410
18204
  @media (prefers-reduced-motion: reduce) {
16411
18205
  /* NOT `transform` on the card itself: its transform is where the layout
16412
18206
  put it, written as an inline style, and a rule here saying `none` would
16413
- be a rule that only ever fires when something else drops that style. */
16414
- .crewlet-tree-canvas__card--composing,
18207
+ be a rule that only ever fires when something else drops that style.
18208
+ Named with the chart's class, as the rule that starts its arrival names
18209
+ it: by its own class alone the stop was one class short of that rule,
18210
+ and the arrival played for a reader who had asked for none. */
18211
+ .crewlet-tree-canvas .crewlet-tree-canvas__card--composing,
16415
18212
  .crewlet-tree-canvas__links path[data-composing='true'] {
16416
18213
  opacity: 1;
16417
18214
  animation: none;