@felloinnovations/brand-kit 0.5.1 → 0.5.3

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 (104) hide show
  1. package/AGENTS.md +29 -9
  2. package/CHANGELOG.md +86 -0
  3. package/README.md +10 -4
  4. package/design-system/01-how-claude-decides.md +5 -3
  5. package/design-system/03-colour.md +19 -1
  6. package/design-system/05-space-and-layout.md +2 -1
  7. package/design-system/08-choosing-components.md +20 -4
  8. package/design-system/09-charts.md +6 -3
  9. package/design-system/11-page-recipes.md +40 -1
  10. package/design-system/13-motion.md +1 -1
  11. package/design-system/15-ai-experiences.md +11 -0
  12. package/design-system/17-decisions.md +41 -0
  13. package/design-system/components/AppShell/README.md +89 -21
  14. package/design-system/components/AppShell/preview.html +148 -3
  15. package/design-system/components/AppShell/style.css +47 -0
  16. package/design-system/components/Avatar/README.md +6 -3
  17. package/design-system/components/Avatar/preview.html +2 -1
  18. package/design-system/components/Avatar/style.css +3 -0
  19. package/design-system/components/Banner/README.md +9 -5
  20. package/design-system/components/Banner/preview.html +9 -0
  21. package/design-system/components/Banner/style.css +3 -0
  22. package/design-system/components/Button/README.md +29 -2
  23. package/design-system/components/Button/preview.html +33 -1
  24. package/design-system/components/Button/style.css +21 -0
  25. package/design-system/components/Calendar/README.md +148 -0
  26. package/design-system/components/Calendar/preview.html +449 -0
  27. package/design-system/components/Calendar/style.css +61 -0
  28. package/design-system/components/Card/README.md +13 -0
  29. package/design-system/components/Card/preview.html +23 -0
  30. package/design-system/components/Card/style.css +19 -0
  31. package/design-system/components/ChatCard/README.md +74 -3
  32. package/design-system/components/ChatCard/preview.html +126 -25
  33. package/design-system/components/ChatCard/style.css +6 -0
  34. package/design-system/components/Chip/README.md +16 -7
  35. package/design-system/components/Chip/preview.html +25 -1
  36. package/design-system/components/Chip/style.css +5 -0
  37. package/design-system/components/Combobox/README.md +10 -4
  38. package/design-system/components/Combobox/preview.html +19 -4
  39. package/design-system/components/Combobox/style.css +7 -1
  40. package/design-system/components/CommentThread/README.md +138 -0
  41. package/design-system/components/CommentThread/preview.html +134 -0
  42. package/design-system/components/CommentThread/style.css +41 -0
  43. package/design-system/components/DateInput/README.md +38 -4
  44. package/design-system/components/DateInput/preview.html +50 -2
  45. package/design-system/components/DateInput/style.css +6 -0
  46. package/design-system/components/Dialog/README.md +26 -3
  47. package/design-system/components/Dialog/preview.html +80 -0
  48. package/design-system/components/Dialog/style.css +28 -3
  49. package/design-system/components/EmptyState/README.md +1 -1
  50. package/design-system/components/Fold/README.md +21 -0
  51. package/design-system/components/Fold/preview.html +44 -1
  52. package/design-system/components/Fold/style.css +30 -0
  53. package/design-system/components/InlineEdit/README.md +116 -0
  54. package/design-system/components/InlineEdit/preview.html +135 -0
  55. package/design-system/components/InlineEdit/style.css +34 -0
  56. package/design-system/components/Input/README.md +20 -1
  57. package/design-system/components/Input/preview.html +24 -0
  58. package/design-system/components/Input/style.css +13 -1
  59. package/design-system/components/KanbanBoard/README.md +68 -4
  60. package/design-system/components/KanbanBoard/preview.html +129 -0
  61. package/design-system/components/KanbanBoard/style.css +31 -0
  62. package/design-system/components/PlanTimeline/README.md +144 -0
  63. package/design-system/components/PlanTimeline/preview.html +109 -0
  64. package/design-system/components/PlanTimeline/style.css +64 -0
  65. package/design-system/components/README.md +11 -6
  66. package/design-system/components/Skeleton/README.md +66 -2
  67. package/design-system/components/Skeleton/preview.html +83 -1
  68. package/design-system/components/Starter/README.md +1 -1
  69. package/design-system/components/Starter/preview.html +1 -1
  70. package/design-system/components/Stepper/README.md +81 -5
  71. package/design-system/components/Stepper/preview.html +64 -1
  72. package/design-system/components/Stepper/style.css +29 -0
  73. package/design-system/components/StreakCalendar/README.md +1 -0
  74. package/design-system/components/Table/README.md +7 -3
  75. package/design-system/components/Table/preview.html +15 -0
  76. package/design-system/components/Table/style.css +2 -0
  77. package/design-system/components/TextDiff/README.md +96 -0
  78. package/design-system/components/TextDiff/preview.html +42 -0
  79. package/design-system/components/TextDiff/style.css +21 -0
  80. package/design-system/components/Timeline/README.md +3 -1
  81. package/design-system/components/TrendLine/README.md +38 -7
  82. package/design-system/components/TrendLine/preview.html +140 -3
  83. package/design-system/components/TrendLine/style.css +12 -2
  84. package/design-system/components/bundle.css +483 -7
  85. package/design-system/tokens.json +15 -1
  86. package/dist/fello-core.css +2 -2
  87. package/dist/fello.css +2 -2
  88. package/dist/fello.scoped.css +2 -2
  89. package/dist/index.d.ts +1 -1
  90. package/dist/scoped.js +2 -2
  91. package/dist/tokens.d.ts +8 -0
  92. package/dist/tokens.js +8 -0
  93. package/package.json +7 -2
  94. package/scripts/check-drift.mjs +325 -0
  95. package/scripts/token-model.mjs +2 -1
  96. package/tokens/_dark.css +2 -0
  97. package/tokens/_product.css +2 -0
  98. package/tokens/palettes.ts +1 -1
  99. package/tokens/shadcn-compat.css +1 -1
  100. package/tokens/shadcn-compat.hsl.css +1 -1
  101. package/tokens/tokens.css +14 -1
  102. package/tokens/tokens.md +53 -46
  103. package/tokens/tokens.root.css +14 -1
  104. package/tokens/tokens.ts +9 -1
@@ -0,0 +1,109 @@
1
+ <!-- @dsCard group="Data" height=900 -->
2
+ <!doctype html>
3
+ <html>
4
+ <head>
5
+ <meta charset="utf-8">
6
+ <title>PlanTimeline</title>
7
+ <link rel="stylesheet" href="../../tokens.css">
8
+ <link rel="stylesheet" href="../bundle.css">
9
+ </head>
10
+ <body>
11
+ <div class="ws-stage ws-stage--grey ws-stage--column">
12
+
13
+ <div class="ws-stack">
14
+ <span class="ws-muted">A campaign's plan across its window: a phase a row, its tasks one step in, done teal, the phase in hand navy, a late task salmon, the rest to come; gates and launch day as diamonds; today one line through every row</span>
15
+ <section class="ws-card ws-card--inset ws-stack" aria-labelledby="plan-title">
16
+ <div class="ws-cluster ws-cluster--between">
17
+ <h3 class="ws-section" id="plan-title">Portal launch plan</h3>
18
+ <span class="ws-meta">Sep 1 to Nov 30</span>
19
+ </div>
20
+ <div class="ws-plan-timeline" style="--days: 91;" role="region" aria-label="Portal launch plan by date, today Nov 10" tabindex="0">
21
+ <div class="ws-plan-timeline__plot">
22
+ <div class="ws-plan-timeline__scale" aria-hidden="true">
23
+ <span class="ws-plan-timeline__tick" style="--at: 0;">Sep</span>
24
+ <span class="ws-plan-timeline__tick" style="--at: 30;">Oct</span>
25
+ <span class="ws-plan-timeline__tick" style="--at: 61;">Nov</span>
26
+ </div>
27
+ <ol class="ws-plan-timeline__rows">
28
+ <li class="ws-plan-timeline__row">
29
+ <span class="ws-plan-timeline__name"><span class="ws-plan-timeline__title">Plan</span><span class="ws-plan-timeline__when">Sep 1 to 14</span></span>
30
+ <span class="ws-plan-timeline__track">
31
+ <a class="ws-plan-timeline__bar ws-plan-timeline__bar--done" href="#plan" style="--start: 0; --span: 14;"><span class="ws-sr">Plan, done</span></a>
32
+ <span class="ws-plan-timeline__milestone ws-plan-timeline__milestone--done" style="--at: 14;" role="img" aria-label="Gate 1, Sep 15, passed" title="Gate 1, Sep 15, passed"></span>
33
+ </span>
34
+ </li>
35
+ <li class="ws-plan-timeline__row">
36
+ <span class="ws-plan-timeline__name"><span class="ws-plan-timeline__title">Build</span><span class="ws-plan-timeline__when">Sep 15 to Oct 19</span></span>
37
+ <span class="ws-plan-timeline__track">
38
+ <a class="ws-plan-timeline__bar ws-plan-timeline__bar--done" href="#build" style="--start: 14; --span: 35;"><span class="ws-sr">Build, done</span></a>
39
+ <span class="ws-plan-timeline__milestone ws-plan-timeline__milestone--done" style="--at: 49;" role="img" aria-label="Gate 2, Oct 20, passed" title="Gate 2, Oct 20, passed"></span>
40
+ </span>
41
+ </li>
42
+ <li class="ws-plan-timeline__row">
43
+ <span class="ws-plan-timeline__name"><span class="ws-plan-timeline__title">Pre-launch</span><span class="ws-plan-timeline__when">Oct 20 to Nov 16</span></span>
44
+ <span class="ws-plan-timeline__track">
45
+ <a class="ws-plan-timeline__bar" href="#pre-launch" aria-current="step" style="--start: 49; --span: 28;"><span class="ws-sr">Pre-launch, in hand</span></a>
46
+ <span class="ws-plan-timeline__milestone" style="--at: 77;" role="img" aria-label="Launch day, Nov 17" title="Launch day, Nov 17"></span>
47
+ </span>
48
+ </li>
49
+ <li class="ws-plan-timeline__row ws-plan-timeline__row--task">
50
+ <span class="ws-plan-timeline__name"><span class="ws-plan-timeline__title">Email sequence</span><span class="ws-plan-timeline__when">Oct 20 to Nov 6</span></span>
51
+ <span class="ws-plan-timeline__track">
52
+ <a class="ws-plan-timeline__bar ws-plan-timeline__bar--done" href="#emails" style="--start: 49; --span: 18;"><span class="ws-sr">Email sequence, done</span></a>
53
+ </span>
54
+ </li>
55
+ <li class="ws-plan-timeline__row ws-plan-timeline__row--task">
56
+ <span class="ws-plan-timeline__name"><span class="ws-plan-timeline__title">Landing page</span><span class="ws-plan-timeline__when ws-plan-timeline__when--late">Was due Nov 6</span></span>
57
+ <span class="ws-plan-timeline__track">
58
+ <a class="ws-plan-timeline__bar ws-plan-timeline__bar--late" href="#landing" style="--start: 56; --span: 11;"><span class="ws-sr">Landing page, 4 days late</span></a>
59
+ </span>
60
+ </li>
61
+ <li class="ws-plan-timeline__row ws-plan-timeline__row--task">
62
+ <span class="ws-plan-timeline__name"><span class="ws-plan-timeline__title">Webinar invites</span><span class="ws-plan-timeline__when">Nov 2 to 12</span></span>
63
+ <span class="ws-plan-timeline__track">
64
+ <a class="ws-plan-timeline__bar" href="#invites" aria-current="step" style="--start: 62; --span: 11;"><span class="ws-sr">Webinar invites, in hand</span></a>
65
+ </span>
66
+ </li>
67
+ <li class="ws-plan-timeline__row">
68
+ <span class="ws-plan-timeline__name"><span class="ws-plan-timeline__title">Launch</span><span class="ws-plan-timeline__when">Nov 17 to 23</span></span>
69
+ <span class="ws-plan-timeline__track">
70
+ <a class="ws-plan-timeline__bar ws-plan-timeline__bar--wait" href="#launch" style="--start: 77; --span: 7;"><span class="ws-sr">Launch, to come</span></a>
71
+ </span>
72
+ </li>
73
+ <li class="ws-plan-timeline__row">
74
+ <span class="ws-plan-timeline__name"><span class="ws-plan-timeline__title">Retro</span><span class="ws-plan-timeline__when">Nov 24 to 30</span></span>
75
+ <span class="ws-plan-timeline__track">
76
+ <a class="ws-plan-timeline__bar ws-plan-timeline__bar--wait" href="#retro" style="--start: 84; --span: 7;"><span class="ws-sr">Retro, to come</span></a>
77
+ </span>
78
+ </li>
79
+ </ol>
80
+ <span class="ws-plan-timeline__now" style="--at: 70;" aria-hidden="true"><span>Today</span></span>
81
+ </div>
82
+ </div>
83
+ </section>
84
+ </div>
85
+
86
+ <div class="ws-stack" style="max-width: 360px;">
87
+ <span class="ws-muted">Loading: the names and bars as ghosts where they will land, the scale already drawn</span>
88
+ <section class="ws-card ws-card--inset ws-stack" aria-labelledby="plan-loading" aria-busy="true">
89
+ <h3 class="ws-section" id="plan-loading">Portal launch plan</h3>
90
+ <div class="ws-plan-timeline" style="--days: 91;">
91
+ <div class="ws-plan-timeline__plot">
92
+ <div class="ws-plan-timeline__scale" aria-hidden="true">
93
+ <span class="ws-plan-timeline__tick" style="--at: 0;">Sep</span>
94
+ <span class="ws-plan-timeline__tick" style="--at: 30;">Oct</span>
95
+ <span class="ws-plan-timeline__tick" style="--at: 61;">Nov</span>
96
+ </div>
97
+ <ol class="ws-plan-timeline__rows" aria-hidden="true">
98
+ <li class="ws-plan-timeline__row"><span class="ws-plan-timeline__name"><span class="ws-skeleton ws-skeleton--line" style="width: 64px;"></span></span><span class="ws-plan-timeline__track"><span class="ws-plan-timeline__bar ws-shimmer" style="--start: 0; --span: 14;"></span></span></li>
99
+ <li class="ws-plan-timeline__row"><span class="ws-plan-timeline__name"><span class="ws-skeleton ws-skeleton--line" style="width: 80px;"></span></span><span class="ws-plan-timeline__track"><span class="ws-plan-timeline__bar ws-shimmer" style="--start: 14; --span: 35;"></span></span></li>
100
+ <li class="ws-plan-timeline__row"><span class="ws-plan-timeline__name"><span class="ws-skeleton ws-skeleton--line" style="width: 72px;"></span></span><span class="ws-plan-timeline__track"><span class="ws-plan-timeline__bar ws-shimmer" style="--start: 49; --span: 28;"></span></span></li>
101
+ </ol>
102
+ </div>
103
+ </div>
104
+ </section>
105
+ </div>
106
+
107
+ </div>
108
+ </body>
109
+ </html>
@@ -0,0 +1,64 @@
1
+ /* ---- PlanTimeline: a plan's phases and tasks as bars across its dates. A row a phase (a task one step in), its name and
2
+ dates stuck at the left; each bar from its start to its end on one scale (--days in the window, --start and --span in
3
+ days from its first day); the phase in hand navy, done teal, late salmon, to come on the track; milestones diamonds;
4
+ today one fine line in the needs step through every row. Past its box (a phone) it scrolls sideways inside itself, the
5
+ names staying put. ---- */
6
+ .ws-plan-timeline { --ws-plan-timeline-name: var(--space-8xl); --ws-plan-timeline-day: var(--space-xs); container: ws-plan-timeline / inline-size; min-width: 0; overflow-x: auto; overscroll-behavior-x: contain; scrollbar-width: thin; padding: var(--space-xxs) var(--space-xxs) var(--space-xxs) 0; margin: calc(var(--space-xxs) * -1) calc(var(--space-xxs) * -1) calc(var(--space-xxs) * -1) 0; }
7
+ /* 4 px of room above, below and at the far end (pulled back by the margin) so a bar's focus ring is never cut; none at
8
+ the start, where the names stick. */
9
+ .ws-plan-timeline:focus-visible { outline-offset: calc(var(--ws-focus-width) * -1); }
10
+ /* A bar reached by Tab scrolls clear of the stuck names (the wider name column, so it holds on a phone too). */
11
+ .ws-plan-timeline { scroll-padding-inline-start: calc(var(--space-8xl) + var(--space-xxs)); }
12
+ /* The plot: the names' column and the window, never narrower than a day at 8 px, so a long plan scrolls rather than
13
+ squeezing its bars to slivers. */
14
+ .ws-plan-timeline__plot { position: relative; min-width: calc(var(--ws-plan-timeline-name) + var(--days) * var(--ws-plan-timeline-day)); }
15
+ @container ws-plan-timeline (width < 40rem) { .ws-plan-timeline__plot { --ws-plan-timeline-name: var(--space-7xl); } }
16
+ /* The scale: a tick per month (or week) at its first day, 11 px medium muted, over the window only. Rows and the scale
17
+ are flex rows, not grids, so the stuck names can travel the whole row (a grid item sticks only inside its cell). */
18
+ .ws-plan-timeline__scale { position: relative; display: flex; height: var(--space-lg); }
19
+ .ws-plan-timeline__tick { position: absolute; top: 0; bottom: 0; left: calc(var(--ws-plan-timeline-name) + (100% - var(--ws-plan-timeline-name)) * var(--at) / var(--days)); display: flex; align-items: center; padding-left: var(--space-xxs); border-left: var(--ws-hairline) solid var(--ws-edge-card); font-size: var(--ws-text-micro); line-height: var(--ws-leading-micro); font-weight: 500; color: var(--color-text-muted); white-space: nowrap; }
20
+ .ws-plan-timeline__rows { display: flex; flex-direction: column; }
21
+ .ws-plan-timeline__row { display: flex; border-top: var(--ws-hairline) solid var(--ws-edge-card); }
22
+ /* The name and its dates, stuck at the left on the card's cream. */
23
+ .ws-plan-timeline__name { position: sticky; left: 0; z-index: 2; display: flex; flex: 0 0 var(--ws-plan-timeline-name); flex-direction: column; justify-content: center; min-width: 0; padding: var(--space-xs) var(--space-sm) var(--space-xs) 0; background: var(--ws-plan-timeline-ground, var(--color-bg-page)); }
24
+ /* Names and dates wrap rather than cut: the column is narrow on a phone and a plan's names are its whole point. */
25
+ .ws-plan-timeline__title { font-size: var(--ws-text-control); line-height: var(--ws-leading-control); font-weight: 500; color: var(--color-text-heading); overflow-wrap: anywhere; }
26
+ .ws-plan-timeline__when { font-size: var(--ws-text-dense); line-height: var(--space-md); color: var(--color-text-muted); }
27
+ .ws-plan-timeline__row:has([aria-current]) .ws-plan-timeline__title { font-weight: 600; }
28
+ /* A late phase or task says so under its name, in needs-you words. */
29
+ .ws-plan-timeline__when--late { font-weight: 500; color: var(--ws-word-needs); }
30
+ /* A task: one step in under its phase, its name in the body words, its bar thinner. */
31
+ .ws-plan-timeline__row--task .ws-plan-timeline__name { padding-left: var(--space-md); }
32
+ .ws-plan-timeline__row--task .ws-plan-timeline__title { font-weight: 400; color: var(--color-text-body); }
33
+ .ws-plan-timeline__track { position: relative; flex: 1; min-width: 0; min-height: var(--space-2xl); }
34
+ /* A bar: 4 px corners, at least 24 wide so a one-day task is still a target; a link when it opens the phase. */
35
+ .ws-plan-timeline__bar { --ws-plan-timeline-tone: var(--tone, var(--ws-track)); position: absolute; top: 50%; left: calc(var(--start) / var(--days) * 100%); width: max(calc(var(--span) / var(--days) * 100%), var(--space-lg)); height: var(--space-lg); border-radius: var(--ws-radius-control); background-color: var(--ws-plan-timeline-tone); transform: translateY(-50%); }
36
+ .ws-plan-timeline__bar--wait { box-shadow: inset 0 0 0 var(--ws-hairline) var(--ws-edge-card); }
37
+ .ws-plan-timeline__bar--done { --ws-plan-timeline-tone: var(--tone, var(--ws-chart-finished)); }
38
+ .ws-plan-timeline__bar[aria-current] { --ws-plan-timeline-tone: var(--tone, var(--color-text-heading)); }
39
+ .ws-plan-timeline__bar--late { --ws-plan-timeline-tone: var(--tone, var(--ws-chart-under-half)); }
40
+ .ws-plan-timeline__row--task .ws-plan-timeline__bar { height: var(--space-md); }
41
+ /* Every bar that opens keeps a 24 px target (a task's 16 px bar too), 40 on touch (K10). */
42
+ a.ws-plan-timeline__bar::after { content: ""; position: absolute; inset: calc((100% - var(--ws-plan-timeline-hit, var(--space-lg))) / 2) 0; }
43
+ @media (pointer: coarse) { .ws-plan-timeline { --ws-plan-timeline-hit: var(--ws-touch); } }
44
+ a.ws-plan-timeline__bar { color: var(--color-text-heading); cursor: pointer; }
45
+ @media (hover: hover) { a.ws-plan-timeline__bar:hover { background-image: linear-gradient(var(--ws-hover-strong), var(--ws-hover-strong)); } }
46
+ a.ws-plan-timeline__bar:focus-visible { outline: var(--ws-focus-width) solid var(--ws-focus-color); outline-offset: var(--ws-focus-offset); }
47
+ /* A milestone: a 10 px diamond on the day it falls, the cream inside a navy edge until it is reached, teal after. It
48
+ opens nothing (its phase's bar does); its name and date are in its label and title. */
49
+ .ws-plan-timeline__milestone { position: absolute; z-index: 1; top: 50%; left: calc(var(--at) / var(--days) * 100%); width: var(--space-xs-plus); height: var(--space-xs-plus); border-radius: var(--ws-radius-chip); background: var(--color-bg-page); box-shadow: inset 0 0 0 calc(var(--ws-hairline) * 3) var(--color-text-heading); transform: translate(-50%, -50%) rotate(45deg); }
50
+ .ws-plan-timeline__milestone--done { background: var(--ws-chart-finished); box-shadow: inset 0 0 0 calc(var(--ws-hairline) * 3) var(--color-bg-page); }
51
+ /* Today: its word over the window and one 1 px line down through every row, in the salmon's AA step; under the stuck
52
+ names when the plan scrolls. Leave it out when today is outside the window. */
53
+ .ws-plan-timeline__now { position: absolute; z-index: 1; top: 0; bottom: 0; left: calc(var(--ws-plan-timeline-name) + (100% - var(--ws-plan-timeline-name)) * var(--at) / var(--days)); display: flex; flex-direction: column; align-items: center; font-size: var(--ws-text-micro); line-height: var(--space-lg); font-weight: 600; color: var(--ws-word-needs); transform: translateX(-50%); pointer-events: none; }
54
+ /* On a track that scrolls (a phone) the plan opens on today: the browser scrolls to it once, on load. */
55
+ .ws-plan-timeline__now { scroll-snap-align: center; scroll-initial-target: nearest; }
56
+ .ws-plan-timeline__now > span { padding: 0 var(--space-xxs); background: var(--ws-plan-timeline-ground, var(--color-bg-page)); }
57
+ .ws-plan-timeline__now::after { content: ""; flex: 1; width: var(--ws-line); background: var(--ws-word-needs); }
58
+ /* The names' column over the scale, so a tick scrolled under it hides. */
59
+ .ws-plan-timeline__scale::before { content: ""; position: sticky; z-index: 2; left: 0; flex: 0 0 var(--ws-plan-timeline-name); background: var(--ws-plan-timeline-ground, var(--color-bg-page)); }
60
+ /* The far edge fades while days are hidden past it, lifting at the end; a focused plan drops it (the ring says it scrolls). */
61
+ @supports (animation-timeline: scroll()) {
62
+ .ws-plan-timeline { mask-image: linear-gradient(90deg, currentColor calc(100% - var(--ws-fade-end)), transparent); animation: ws-scroll-edges linear; animation-timeline: scroll(self inline); }
63
+ .ws-plan-timeline:focus-visible { mask-image: none; }
64
+ }
@@ -1,11 +1,11 @@
1
1
  # Components
2
2
 
3
- The catalog: 103 components by gallery group, one line each, plus `Cover`, the gallery's cover card (a preview only, no README, nothing to build with). Each folder holds `README.md` (when to use it, its parts, states and the markup to copy), `preview.html` (the gallery card) and `style.css` (its styles; `bundle.css` and `fello.css` carry them all). Choosing components maps a need to a name; the line here says what each one is. Generated by scripts/build-skill.mjs from each README's first paragraph: edit those, not this file.
3
+ The catalog: 108 components by gallery group, one line each, plus `Cover`, the gallery's cover card (a preview only, no README, nothing to build with). Each folder holds `README.md` (when to use it, its parts, states and the markup to copy), `preview.html` (the gallery card) and `style.css` (its styles; `bundle.css` and `fello.css` carry them all). Choosing components maps a need to a name; the line here says what each one is. Generated by scripts/build-skill.mjs from each README's first paragraph: edit those, not this file.
4
4
 
5
5
  ## Actions
6
6
 
7
7
  - [Button](Button/README.md): The one control for every act on the page: a click that does something, in one of six looks, never a styled `<button>`.
8
- - [Chip](Chip/README.md): A small fact in a 24 px tag, in one of six tones, a rating tone or the Example mark; its sibling `ChangeChip` says a number went up, down or stayed.
8
+ - [Chip](Chip/README.md): A small fact in a 24 px tag, in one of seven tones, a rating tone or the Example mark; its sibling `ChangeChip` says a number went up, down or stayed.
9
9
  - [IconButton](IconButton/README.md): A square button holding one icon and nothing else, for an act that needs no words to be understood.
10
10
  - [Segmented](Segmented/README.md): Every switch and tab row on the platform: Seth's grey well with a navy current item, one component so the current item always moves the same way.
11
11
 
@@ -36,7 +36,7 @@ The catalog: 103 components by gallery group, one line each, plus `Cover`, the g
36
36
  - [StepLine](StepLine/README.md): A bill or a rate over time as a step line against a dotted reference, the gap between them hatched, its moments named.
37
37
  - [StreakCalendar](StreakCalendar/README.md): Eight weeks of activity as rows, Monday to Sunday across: a done day a pill, an empty day a hairline cell, today outlined, days to come dashed.
38
38
  - [TrendBars](TrendBars/README.md): A trend over days as thin rising bars, with one day called out as the moment that explains the shape.
39
- - [TrendLine](TrendLine/README.md): A value over periods against an axis, as a line with its dots and the hatched area under it, or as columns that collapse into the line's points and back.
39
+ - [TrendLine](TrendLine/README.md): A value over periods against an axis, as a line with its dots and the hatched area under it, or as columns that collapse into the line's points and back; up to three series in one unit as lines with a key.
40
40
 
41
41
  ## Chat
42
42
 
@@ -51,13 +51,16 @@ The catalog: 103 components by gallery group, one line each, plus `Cover`, the g
51
51
  ## Data
52
52
 
53
53
  - [ActionList](ActionList/README.md): A card's ranked list of next acts: who or what, the reason in words, and the one act at the right of each row. `--brief` is North's "what changed" list on a page's head: one quiet line each, its acts appearing on the line.
54
+ - [Calendar](Calendar/README.md): Things on dates: a month (or a week) of days, Monday first, each day holding its items as rows that open, the steps and the view switch over it, today ringed; in a narrow column the same markup reads as an agenda.
54
55
  - [CheckRow](CheckRow/README.md): A rimmed list of checks, each row a name, a strip of ticks for its score, the score, a status and a chevron that opens it; or a list of fixes, each row a box to tick, the fix and its effort, its act, and a chevron that opens it in place. Seth's checks list (301:1728) and Fixes checklist (308:2466).
55
56
  - [KanbanBoard](KanbanBoard/README.md): Columns of cards for a pipeline: a stage per column, a card per thing moving through it, a count beside each stage's name. `--fill` makes it a board page: the rest of the page's height, every stage scrolling on its own, the sideways bar on screen.
56
57
  - [Leaderboard](Leaderboard/README.md): A list that ranks people against one number: a rank, a face and a name, a thin bar for the score, the score itself, with the person's own row lit so they find themselves at once. Every row shares one grid, so the bars start and end on the same lines and no number is ever cut.
57
58
  - [ListDetail](ListDetail/README.md): A list and the thing picked from it, side by side: the list one column wide, the open item two, on one three-column grid. Seth's Review inbox (313:2671) and North's board (a chart and the list that drives it), with Tally's vendors.
58
59
  - [Matrix](Matrix/README.md): A grid of yes-or-no answers: one row per question, one column per source, each cell lit when the answer is yes. Seth's answers grid (305:2341): which AI assistants named you, for each of the questions a buyer might ask.
60
+ - [PlanTimeline](PlanTimeline/README.md): A plan's phases and tasks as bars across its dates: a row a phase (its tasks one step in), each bar from its start to its end on one scale, the phase in hand navy, milestones as diamonds and today one line through every row.
59
61
  - [SideList](SideList/README.md): Short lists with no card of their own: a few groups down a side column, each with a small head and rows joined by fine lines, an act or a value at the right of each row. Its picker form, `__picks`, sits on a card's surface: rows as soft pills, one of them the current one.
60
62
  - [Table](Table/README.md): Rows of records inside one card, read down its columns: a head of muted labels, 40 px rows, a first column that stays while the rest scroll, numbers in fixed right-aligned columns, totals in the foot, columns that fold away by priority and a phone fold. This is the whole wide-table pattern; build every records table from it.
63
+ - [TextDiff](TextDiff/README.md): Two versions of a text side by side in one place: what was removed and what was added, by line or inside the words, told apart by a sign, a strike or an underline as well as by colour.
61
64
  - [Timeline](Timeline/README.md): A vertical feed of what happened, grouped by day, a coloured dot on a fine line telling what kind of thing each entry was.
62
65
 
63
66
  ## Desk
@@ -68,7 +71,7 @@ The catalog: 103 components by gallery group, one line each, plus `Cover`, the g
68
71
  ## Feedback
69
72
 
70
73
  - [Badge](Badge/README.md): A small count or mark riding on the corner of a face, an icon or a nav row, saying "there is something here" at a glance.
71
- - [Banner](Banner/README.md): A full-width notice for a state of the whole page or card, in one of four quiet tones, never a loud one.
74
+ - [Banner](Banner/README.md): A full-width notice for a state of the whole page or card, in one of five quiet tones, never a loud one.
72
75
  - [Popover](Popover/README.md): A small lifted card beside its control, for the time a tooltip is too thin and a dialog is too much.
73
76
  - [StatusScreen](StatusScreen/README.md): The whole-page word for something that failed: a page that is not there, a server error, or a connection that is not back yet.
74
77
 
@@ -76,8 +79,9 @@ The catalog: 103 components by gallery group, one line each, plus `Cover`, the g
76
79
 
77
80
  - [Checkbox](Checkbox/README.md): A real native checkbox under a skin, drawn with a navy tick when chosen, its label part of the thing you tap.
78
81
  - [Combobox](Combobox/README.md): A searchable field for choosing from a long list, matching as you type and offering to create a new value when nothing matches.
79
- - [DateInput](DateInput/README.md): A date field that works on its own, with a popover month grid for picking a day by eye instead of typing it.
82
+ - [DateInput](DateInput/README.md): A date field that works on its own, with a popover month grid for picking a day by eye instead of typing it; the same shell holds a time of day, and a date with a time.
80
83
  - [FileUpload](FileUpload/README.md): A drop zone for one or more files, with a row per file showing its progress, a tick when it lands, or why it was rejected.
84
+ - [InlineEdit](InlineEdit/README.md): Words that become a field in place: a value read and edited where it sits (a task's title, a brief's section, a milestone's name), the same box and the same type at rest and editing, so nothing jumps.
81
85
  - [Input](Input/README.md): A single line of typed text, drawn as a field reads as a field on a cream card: white ground, a fine edge, the mid-blue edge while typing.
82
86
  - [NumberInput](NumberInput/README.md): A number field with its figures right-aligned and tabular, an optional unit inside it, and small buttons to step the value.
83
87
  - [PasswordInput](PasswordInput/README.md): A password field with a visibility toggle and a strength line, so a person can see what they typed and how strong it is.
@@ -138,6 +142,7 @@ The catalog: 103 components by gallery group, one line each, plus `Cover`, the g
138
142
  ## People
139
143
 
140
144
  - [Avatar](Avatar/README.md): A person's own mark: their photo once it loads, or their initials in navy on a neutral disc before and instead; never coloured, never an app's face.
145
+ - [CommentThread](CommentThread/README.md): People commenting on a thing: remarks anchored to a piece of content, with replies, @mentions, an open or resolved state with a count, and a small composer.
141
146
 
142
147
  ## Progress
143
148
 
@@ -146,6 +151,6 @@ The catalog: 103 components by gallery group, one line each, plus `Cover`, the g
146
151
  - [PaceBar](PaceBar/README.md): Progress toward a goal on a 14 px track, with a dot where it should be by now. North's bar, used in tiles, lanes and lists.
147
152
  - [Ring](Ring/README.md): A circle's own share as one arc, or Seth's split ring: 96 radial ticks in each part's tone, the total in the hole, a key beside.
148
153
  - [SegmentedProgress](SegmentedProgress/README.md): Progress split by area and by step: Seth's "1 of 6" figure, a line under it, and one bar of segments with each area named.
149
- - [Stepper](Stepper/README.md): Ordered steps on a line that fills: done is a tick, the one in hand is ringed, the rest wait their turn.
154
+ - [Stepper](Stepper/README.md): Ordered steps on a line that fills: done is a tick, the one in hand is ringed, the rest wait their turn. Down the page by default; `--across` lays the stages left to right; `--milestones` makes them dated points on one row.
150
155
  - [TickRow](TickRow/README.md): One row of fixed-size ticks for a count out of a small whole: the done ticks in one tone, or each its stretch of the gradient.
151
156
  - [TickStrip](TickStrip/README.md): A share drawn as equal ticks across the whole width: the done ones in one tone, the rest the plain track. Seth's score strips.
@@ -4,11 +4,16 @@ nothing jumps when the real content lands.
4
4
  ## Use it when
5
5
 
6
6
  - A card, a row or a line of text has not loaded yet, and the layout it will take is already known.
7
- - A whole page is loading (`CanvasLoading`): a header pair and a bento of card-shaped rectangles, sized to match what will land.
7
+ - A whole page is loading its data (a dashboard, an account's page): the page ghost (A page, below). The page's own
8
+ `PageBar` shows at once with its name, the words and acts that wait on the data are ghosts, and the board holds a tile
9
+ or card skeleton where each real one will land.
8
10
  - A list or a well is still being read: a few rows stand in placeholders' places (`Well busy`, `WellRow hidden`).
9
11
 
10
12
  ## Not for
11
13
 
14
+ - A list page or a board page: the page's `PageBar` and `FilterBar` at once, then `Table`'s own ghost rows
15
+ (`ws-table__placeholder`) or `KanbanBoard`'s ghost cards (`ws-kanban-board__ghost`), their heads shown at once. Never a
16
+ bento of cards in place of a table or a board.
12
17
  - "There is an answer and it is nothing": use `EmptyState`.
13
18
  - A single control waiting on its own request (a pressed button): use the button's own `pending` state (a working dot), not a skeleton.
14
19
  - Content whose final size is unknown: a skeleton promises a shape; guessing wildly causes more jumping than a plain loading line would.
@@ -24,6 +29,18 @@ nothing jumps when the real content lands.
24
29
  cream 1.29:1), so a ghost in a foot or a band is the same ghost.
25
30
  - A chart ghost (`ws-skeleton__chart`): 160 px tall, the bars 4 px apart, each a ghost under the same shimmer as every
26
31
  other ghost. North's colour band over the drawing is not taken (0.5.1): loaders are one neutral tone.
32
+ - A page (the page ghost; no class of its own, the page's own layout and the ghosts above): the real `.ws-page` (or
33
+ `AppShell`'s body) with `aria-busy="true"` and one `ws-sr` status line, so the ghost lands where the page will and
34
+ nothing jumps.
35
+ - Its `PageBar` is the real bar, 56 tall either way: the name shows at once (a page knows its own name). Words that
36
+ wait on the data are ghosts on their own classes (`ws-page-bar__context ws-skeleton ws-skeleton--line`, 200 wide),
37
+ so they wrap, and hide in a shell's bar on a phone, as the words will. An act that needs the data is a button place
38
+ (`--button`); one that does not ("Sync now") stays a real button. A name that comes with the data (an account's
39
+ page) is a ghost line in the title's place.
40
+ - Its board is the real board: `ws-board ws-board--4` for a row of tiles (four, two or one, never three), `ws-board`
41
+ for the chart cards, each a card skeleton the shape of the card that lands. The chart ghost stands for a 160 px plot;
42
+ set it to the card's own plot height when that is shorter (`ws-card__bars` is 72), and a card with rows gets a ghost
43
+ row per row. Draw only the cards above the fold; the rest come as they load.
27
44
 
28
45
  ## Variants and sizes
29
46
 
@@ -33,6 +50,7 @@ nothing jumps when the real content lands.
33
50
  | A card or tile skeleton | A chart card or tile still loading, keeping the page's layout steady |
34
51
  | A chart ghost | The drawing inside a chart card that is still being built |
35
52
  | A button place | The band's act before the card knows it |
53
+ | A page | A whole page still loading its data: the real bar with its name, its waiting words and acts as ghosts, a board of tile and card skeletons |
36
54
 
37
55
  ## States
38
56
 
@@ -71,12 +89,16 @@ The kit's own `Skeleton` takes a `className` for its shape and size directly (he
71
89
 
72
90
  - Never invent a size: a skeleton's bars use the real content's own token sizes (a title's line height, a card's padding), so nothing jumps when the content replaces it.
73
91
  - A loading region is announced once (`aria-busy`, `aria-live="polite"` on the container), not per placeholder bar.
92
+ - A page's name never waits on its data, and a page ghost is the page's own bar and board, never a layout of its own:
93
+ what lands takes the ghost's place in the same grid.
74
94
  - With reduced motion, a skeleton is still visibly a placeholder (still grey ghosts), never indistinguishable from real, blank content.
75
95
 
76
96
  ## Source
77
97
 
78
98
  **Derived from**: North's loading (style1.css:1458-1469: the shimmer over blocks, the ghost shapes, the 116 x 38
79
- button place) and the kit's own `Skeleton`. North's sweep in the chart colours and its colour band over the chart are
99
+ button place), North's `CanvasLoading` for the page ghost (a header pair and a bento of card-shaped ghosts; here on the
100
+ page's own bar and board, the name shown at once, as `AppShell`, `Table` and `KanbanBoard` show their heads; Hemanth's
101
+ ask for a page-level loader, 10 Nov 2026) and the kit's own `Skeleton`. North's sweep in the chart colours and its colour band over the chart are
80
102
  not taken: loaders are one quiet grey (Amit, 10 Nov 2026, Decisions). It replaces the breathing
81
103
  pulse, which read as blank (1.10:1 on the cream, field evidence S01). **Precedent**: the first product built on the
82
104
  system.
@@ -96,6 +118,48 @@ system.
96
118
  </div>
97
119
  ```
98
120
 
121
+ A page (the preview draws four tiles and two chart cards; repeat the tile and the card for each one that lands):
122
+
123
+ ```html
124
+ <main class="ws-page" aria-busy="true">
125
+ <span class="ws-sr" role="status">Loading onboarding</span>
126
+ <header class="ws-page-bar">
127
+ <div class="ws-page-bar__words">
128
+ <h1 class="ws-page-bar__title">Onboarding</h1>
129
+ <span class="ws-page-bar__context ws-skeleton ws-skeleton--line" style="width: var(--space-9xl);" aria-hidden="true"></span>
130
+ </div>
131
+ <div class="ws-page-bar__acts" aria-hidden="true"><div class="ws-skeleton ws-skeleton--button"></div></div>
132
+ </header>
133
+ <div class="ws-board ws-board--4">
134
+ <div class="ws-card" aria-hidden="true">
135
+ <div class="ws-card__surface ws-card__surface--pad ws-stack">
136
+ <div class="ws-skeleton ws-skeleton--line" style="width: 50%;"></div>
137
+ <div class="ws-skeleton" style="height: var(--ws-leading-figure); width: 40%;"></div>
138
+ </div>
139
+ <div class="ws-card__foot"><div class="ws-skeleton ws-skeleton--line" style="width: 40%;"></div></div>
140
+ </div>
141
+ </div>
142
+ <div class="ws-board">
143
+ <div class="ws-card ws-card--compound" aria-hidden="true">
144
+ <div class="ws-skeleton__head">
145
+ <div class="ws-skeleton ws-skeleton--title" style="width: 55%;"></div>
146
+ <div class="ws-skeleton ws-skeleton--line" style="width: 80%;"></div>
147
+ </div>
148
+ <div class="ws-skeleton__body">
149
+ <div class="ws-skeleton__chart"><i style="height: 35%;"></i><i style="height: 60%;"></i><i style="height: 45%;"></i><i style="height: 75%;"></i></div>
150
+ </div>
151
+ <footer class="ws-band">
152
+ <div class="ws-band__words"><div class="ws-skeleton ws-skeleton--line" style="width: 50%;"></div></div>
153
+ <div class="ws-band__acts"><div class="ws-skeleton ws-skeleton--button"></div></div>
154
+ </footer>
155
+ </div>
156
+ </div>
157
+ </main>
158
+ ```
159
+
160
+ In `AppShell` the nav and the bar are already there: put the bar's ghosts in the shell's bar and the boards straight in
161
+ its body (`aria-busy="true"` and the status line on the body), with no `.ws-page` inside.
162
+
99
163
  ## Styles
100
164
 
101
165
  `Skeleton/style.css`, built into `bundle.css` and `fello.css`. The keyframe is the house's `ws-shimmer`. Tokens:
@@ -1,4 +1,4 @@
1
- <!-- @dsCard group="Cards" height=430 -->
1
+ <!-- @dsCard group="Cards" height=1180 -->
2
2
  <!doctype html>
3
3
  <html>
4
4
  <head>
@@ -51,5 +51,87 @@
51
51
  </div>
52
52
  </div>
53
53
  </div>
54
+
55
+ <div class="ws-stage ws-stage--column ws-stage--bleed">
56
+ <span class="ws-muted" style="padding: var(--ws-gap-component) var(--ws-gap-component) 0;">A whole page still loading: its own bar with the name shown at once, the context and the act as ghosts, then a board of tile and card skeletons where the real ones will land</span>
57
+ <main class="ws-page" aria-busy="true">
58
+ <span class="ws-sr" role="status">Loading onboarding</span>
59
+ <header class="ws-page-bar">
60
+ <div class="ws-page-bar__words">
61
+ <h1 class="ws-page-bar__title">Onboarding</h1>
62
+ <span class="ws-page-bar__context ws-skeleton ws-skeleton--line" style="width: var(--space-9xl);" aria-hidden="true"></span>
63
+ </div>
64
+ <div class="ws-page-bar__acts" aria-hidden="true">
65
+ <div class="ws-skeleton ws-skeleton--button"></div>
66
+ </div>
67
+ </header>
68
+ <div class="ws-board ws-board--4">
69
+ <div class="ws-card" aria-hidden="true">
70
+ <div class="ws-card__surface ws-card__surface--pad ws-stack">
71
+ <div class="ws-skeleton ws-skeleton--line" style="width: 50%;"></div>
72
+ <div class="ws-skeleton" style="height: var(--ws-leading-figure); width: 40%;"></div>
73
+ </div>
74
+ <div class="ws-card__foot">
75
+ <div class="ws-skeleton ws-skeleton--line" style="width: 40%;"></div>
76
+ </div>
77
+ </div>
78
+ <div class="ws-card" aria-hidden="true">
79
+ <div class="ws-card__surface ws-card__surface--pad ws-stack">
80
+ <div class="ws-skeleton ws-skeleton--line" style="width: 60%;"></div>
81
+ <div class="ws-skeleton" style="height: var(--ws-leading-figure); width: 30%;"></div>
82
+ </div>
83
+ <div class="ws-card__foot">
84
+ <div class="ws-skeleton ws-skeleton--line" style="width: 50%;"></div>
85
+ </div>
86
+ </div>
87
+ <div class="ws-card" aria-hidden="true">
88
+ <div class="ws-card__surface ws-card__surface--pad ws-stack">
89
+ <div class="ws-skeleton ws-skeleton--line" style="width: 45%;"></div>
90
+ <div class="ws-skeleton" style="height: var(--ws-leading-figure); width: 45%;"></div>
91
+ </div>
92
+ <div class="ws-card__foot">
93
+ <div class="ws-skeleton ws-skeleton--line" style="width: 35%;"></div>
94
+ </div>
95
+ </div>
96
+ <div class="ws-card" aria-hidden="true">
97
+ <div class="ws-card__surface ws-card__surface--pad ws-stack">
98
+ <div class="ws-skeleton ws-skeleton--line" style="width: 55%;"></div>
99
+ <div class="ws-skeleton" style="height: var(--ws-leading-figure); width: 35%;"></div>
100
+ </div>
101
+ <div class="ws-card__foot">
102
+ <div class="ws-skeleton ws-skeleton--line" style="width: 45%;"></div>
103
+ </div>
104
+ </div>
105
+ </div>
106
+ <div class="ws-board">
107
+ <div class="ws-card ws-card--compound" aria-hidden="true">
108
+ <div class="ws-skeleton__head">
109
+ <div class="ws-skeleton ws-skeleton--title" style="width: 55%;"></div>
110
+ <div class="ws-skeleton ws-skeleton--line" style="width: 80%;"></div>
111
+ </div>
112
+ <div class="ws-skeleton__body">
113
+ <div class="ws-skeleton__chart"><i style="height: 35%;"></i><i style="height: 60%;"></i><i style="height: 45%;"></i><i style="height: 75%;"></i><i style="height: 55%;"></i><i style="height: 90%;"></i><i style="height: 70%;"></i><i style="height: 50%;"></i></div>
114
+ </div>
115
+ <footer class="ws-band">
116
+ <div class="ws-band__words"><div class="ws-skeleton ws-skeleton--line" style="width: 50%;"></div></div>
117
+ <div class="ws-band__acts"><div class="ws-skeleton ws-skeleton--button"></div></div>
118
+ </footer>
119
+ </div>
120
+ <div class="ws-card ws-card--compound" aria-hidden="true">
121
+ <div class="ws-skeleton__head">
122
+ <div class="ws-skeleton ws-skeleton--title" style="width: 45%;"></div>
123
+ <div class="ws-skeleton ws-skeleton--line" style="width: 70%;"></div>
124
+ </div>
125
+ <div class="ws-skeleton__body">
126
+ <div class="ws-skeleton__chart"><i style="height: 60%;"></i><i style="height: 40%;"></i><i style="height: 70%;"></i><i style="height: 50%;"></i><i style="height: 80%;"></i><i style="height: 65%;"></i><i style="height: 45%;"></i><i style="height: 55%;"></i></div>
127
+ </div>
128
+ <footer class="ws-band">
129
+ <div class="ws-band__words"><div class="ws-skeleton ws-skeleton--line" style="width: 40%;"></div></div>
130
+ <div class="ws-band__acts"><div class="ws-skeleton ws-skeleton--button"></div></div>
131
+ </footer>
132
+ </div>
133
+ </div>
134
+ </main>
135
+ </div>
54
136
  </body>
55
137
  </html>
@@ -23,7 +23,7 @@ paste the CSS into the `<style>`, then replace the sample content with the real
23
23
  `fello-core.css`, then the styles of each component the page uses (each component's card lists them; this page needs
24
24
  `Page`, `PageBar`, `Card`, `Button` and `Well`; the whole `fello.css` is too big to paste). The buttons and the well
25
25
  rows need their own blocks: `fello-core.css` holds only their 0.4 look. A plain page links the whole file instead,
26
- pinned: `https://brand-kit-site-production.up.railway.app/v/0.5.1/fello.css`.
26
+ pinned: `https://brand-kit-site-production.up.railway.app/v/0.5.3/fello.css`.
27
27
  - `<main class="ws-page">`: the page (see `Page`), Seth's 32 gutter.
28
28
  - `PageBar`: the page's 56 px header, its one `h1` (16 / 22 semibold) and a word of context beside it, and its acts
29
29
  with the page's one navy primary last.
@@ -7,7 +7,7 @@
7
7
  <title>Starter</title>
8
8
  <!-- In a claude.ai artifact, paste fello-core.css into the <style> below, then the styles of each component you use
9
9
  (each component's card lists them): an artifact may load no stylesheet but Google Fonts. On a plain page, link the
10
- whole kit instead, pinned: https://brand-kit-site-production.up.railway.app/v/0.5.1/fello.css -->
10
+ whole kit instead, pinned: https://brand-kit-site-production.up.railway.app/v/0.5.3/fello.css -->
11
11
  <link rel="preconnect" href="https://fonts.googleapis.com">
12
12
  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
13
13
  <link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Instrument+Sans:wght@400..700&display=swap">