@felloinnovations/brand-kit 0.4.0 → 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.
- package/AGENTS.md +198 -24
- package/CHANGELOG.md +197 -0
- package/README.md +34 -7
- package/design-system/01-how-claude-decides.md +26 -17
- package/design-system/02-principles.md +11 -6
- package/design-system/03-colour.md +134 -47
- package/design-system/04-type.md +45 -23
- package/design-system/05-space-and-layout.md +175 -52
- package/design-system/06-sizing-profiles.md +4 -4
- package/design-system/07-scrolling.md +66 -20
- package/design-system/08-choosing-components.md +50 -22
- package/design-system/09-charts.md +71 -28
- package/design-system/10-patterns.md +33 -10
- package/design-system/11-page-recipes.md +110 -23
- package/design-system/12-content.md +2 -1
- package/design-system/13-motion.md +330 -47
- package/design-system/14-accessibility.md +47 -24
- package/design-system/15-ai-experiences.md +11 -6
- package/design-system/16-creativity.md +1 -1
- package/design-system/17-decisions.md +357 -1
- package/design-system/18-checklist.md +79 -16
- package/design-system/19-public-pages.md +6 -4
- package/design-system/20-palettes.md +275 -0
- package/design-system/README.md +30 -17
- package/design-system/components/ActionList/README.md +96 -10
- package/design-system/components/ActionList/preview.html +52 -7
- package/design-system/components/ActionList/style.css +64 -0
- package/design-system/components/ActivityGrid/README.md +38 -2
- package/design-system/components/ActivityGrid/preview.html +1 -1
- package/design-system/components/ActivityGrid/style.css +35 -0
- package/design-system/components/AppShell/README.md +205 -75
- package/design-system/components/AppShell/preview.html +339 -58
- package/design-system/components/AppShell/style.css +154 -0
- package/design-system/components/Avatar/README.md +37 -10
- package/design-system/components/Avatar/preview.html +13 -4
- package/design-system/components/Avatar/style.css +14 -0
- package/design-system/components/Badge/README.md +41 -19
- package/design-system/components/Badge/preview.html +13 -10
- package/design-system/components/Badge/style.css +23 -0
- package/design-system/components/Banner/README.md +30 -9
- package/design-system/components/Banner/preview.html +1 -1
- package/design-system/components/Banner/style.css +19 -0
- package/design-system/components/Breadcrumb/README.md +58 -46
- package/design-system/components/Breadcrumb/preview.html +16 -16
- package/design-system/components/Breadcrumb/style.css +17 -0
- package/design-system/components/Button/README.md +113 -55
- package/design-system/components/Button/preview.html +98 -25
- package/design-system/components/Button/style.css +86 -0
- package/design-system/components/Card/README.md +158 -49
- package/design-system/components/Card/preview.html +141 -19
- package/design-system/components/Card/style.css +115 -0
- package/design-system/components/CardBoard/README.md +58 -37
- package/design-system/components/CardBoard/preview.html +26 -29
- package/design-system/components/ChatCard/README.md +115 -29
- package/design-system/components/ChatCard/preview.html +149 -32
- package/design-system/components/ChatCard/style.css +49 -0
- package/design-system/components/ChatShell/README.md +116 -0
- package/design-system/components/ChatShell/preview.html +201 -0
- package/design-system/components/ChatShell/style.css +86 -0
- package/design-system/components/ChatTurn/README.md +78 -35
- package/design-system/components/ChatTurn/preview.html +60 -28
- package/design-system/components/ChatTurn/style.css +50 -0
- package/design-system/components/CheckRow/README.md +141 -0
- package/design-system/components/CheckRow/preview.html +140 -0
- package/design-system/components/CheckRow/style.css +88 -0
- package/design-system/components/Checkbox/README.md +58 -22
- package/design-system/components/Checkbox/preview.html +112 -50
- package/design-system/components/Checkbox/style.css +45 -0
- package/design-system/components/Chip/README.md +78 -47
- package/design-system/components/Chip/preview.html +29 -4
- package/design-system/components/Chip/style.css +17 -0
- package/design-system/components/Combobox/README.md +44 -11
- package/design-system/components/Combobox/preview.html +35 -12
- package/design-system/components/Combobox/style.css +54 -0
- package/design-system/components/Composer/README.md +137 -35
- package/design-system/components/Composer/preview.html +115 -40
- package/design-system/components/Composer/style.css +81 -0
- package/design-system/components/ConfirmDialog/README.md +73 -52
- package/design-system/components/ConfirmDialog/preview.html +70 -26
- package/design-system/components/ConfirmDialog/style.css +5 -0
- package/design-system/components/Cover/preview.html +3 -3
- package/design-system/components/Cover/style.css +19 -0
- package/design-system/components/DateInput/README.md +77 -12
- package/design-system/components/DateInput/preview.html +27 -12
- package/design-system/components/DateInput/style.css +38 -0
- package/design-system/components/Dialog/README.md +112 -44
- package/design-system/components/Dialog/preview.html +141 -18
- package/design-system/components/Dialog/style.css +74 -0
- package/design-system/components/EmptyState/README.md +42 -12
- package/design-system/components/EmptyState/preview.html +11 -11
- package/design-system/components/EmptyState/style.css +9 -0
- package/design-system/components/EntryShell/README.md +73 -48
- package/design-system/components/EntryShell/preview.html +60 -27
- package/design-system/components/EntryShell/style.css +19 -0
- package/design-system/components/FeatureGrid/README.md +61 -39
- package/design-system/components/FeatureGrid/preview.html +2 -2
- package/design-system/components/FeatureGrid/style.css +20 -0
- package/design-system/components/FileUpload/README.md +33 -3
- package/design-system/components/FileUpload/preview.html +18 -4
- package/design-system/components/FileUpload/style.css +23 -0
- package/design-system/components/FilterBar/README.md +114 -0
- package/design-system/components/FilterBar/preview.html +82 -0
- package/design-system/components/FilterBar/style.css +22 -0
- package/design-system/components/Fold/README.md +84 -26
- package/design-system/components/Fold/preview.html +77 -34
- package/design-system/components/Fold/style.css +48 -0
- package/design-system/components/Footer/README.md +62 -39
- package/design-system/components/Footer/preview.html +5 -5
- package/design-system/components/Footer/style.css +30 -0
- package/design-system/components/FunnelBars/README.md +24 -3
- package/design-system/components/FunnelBars/preview.html +5 -5
- package/design-system/components/FunnelBars/style.css +13 -0
- package/design-system/components/GoalBars/README.md +54 -10
- package/design-system/components/GoalBars/preview.html +69 -28
- package/design-system/components/GoalBars/style.css +51 -0
- package/design-system/components/GoalTicks/README.md +74 -58
- package/design-system/components/GoalTicks/preview.html +41 -118
- package/design-system/components/GoalTicks/style.css +37 -0
- package/design-system/components/GoalTubes/README.md +29 -3
- package/design-system/components/GoalTubes/preview.html +6 -6
- package/design-system/components/GoalTubes/style.css +23 -0
- package/design-system/components/Heatmap/README.md +133 -0
- package/design-system/components/Heatmap/preview.html +168 -0
- package/design-system/components/Heatmap/style.css +119 -0
- package/design-system/components/Hero/README.md +58 -40
- package/design-system/components/Hero/preview.html +1 -1
- package/design-system/components/Hero/style.css +19 -0
- package/design-system/components/HoverCard/README.md +114 -0
- package/design-system/components/HoverCard/preview.html +107 -0
- package/design-system/components/HoverCard/style.css +59 -0
- package/design-system/components/IconButton/README.md +69 -38
- package/design-system/components/IconButton/preview.html +77 -43
- package/design-system/components/IconButton/style.css +45 -0
- package/design-system/components/Input/README.md +36 -11
- package/design-system/components/Input/preview.html +1 -1
- package/design-system/components/Input/style.css +23 -0
- package/design-system/components/KanbanBoard/README.md +93 -45
- package/design-system/components/KanbanBoard/preview.html +159 -43
- package/design-system/components/KanbanBoard/style.css +53 -0
- package/design-system/components/Kbd/README.md +25 -9
- package/design-system/components/Kbd/preview.html +6 -2
- package/design-system/components/Kbd/style.css +9 -0
- package/design-system/components/KitButton/README.md +81 -47
- package/design-system/components/KitButton/preview.html +35 -13
- package/design-system/components/KitButton/style.css +46 -0
- package/design-system/components/KitCard/README.md +75 -44
- package/design-system/components/KitCard/preview.html +18 -10
- package/design-system/components/KitCard/style.css +15 -0
- package/design-system/components/KitInput/README.md +54 -39
- package/design-system/components/KitInput/preview.html +7 -7
- package/design-system/components/KitInput/style.css +23 -0
- package/design-system/components/Leaderboard/README.md +76 -49
- package/design-system/components/Leaderboard/preview.html +61 -26
- package/design-system/components/Leaderboard/style.css +44 -0
- package/design-system/components/ListDetail/README.md +222 -0
- package/design-system/components/ListDetail/preview.html +213 -0
- package/design-system/components/ListDetail/style.css +148 -0
- package/design-system/components/LoadBar/README.md +79 -0
- package/design-system/components/LoadBar/preview.html +40 -0
- package/design-system/components/LoadBar/style.css +17 -0
- package/design-system/components/MarketingNav/README.md +76 -42
- package/design-system/components/MarketingNav/preview.html +37 -8
- package/design-system/components/MarketingNav/style.css +45 -0
- package/design-system/components/Matrix/README.md +129 -0
- package/design-system/components/Matrix/preview.html +99 -0
- package/design-system/components/Matrix/style.css +84 -0
- package/design-system/components/Menu/README.md +117 -41
- package/design-system/components/Menu/preview.html +85 -23
- package/design-system/components/Menu/style.css +61 -0
- package/design-system/components/Meter/README.md +39 -4
- package/design-system/components/Meter/preview.html +18 -1
- package/design-system/components/Meter/style.css +23 -0
- package/design-system/components/MetricTile/README.md +237 -0
- package/design-system/components/MetricTile/preview.html +241 -0
- package/design-system/components/MetricTile/style.css +129 -0
- package/design-system/components/Morph/README.md +106 -0
- package/design-system/components/Morph/preview.html +103 -0
- package/design-system/components/Morph/style.css +31 -0
- package/design-system/components/Motion/README.md +164 -0
- package/design-system/components/Motion/preview.html +2537 -0
- package/design-system/components/NumberInput/README.md +27 -8
- package/design-system/components/NumberInput/preview.html +21 -5
- package/design-system/components/NumberInput/style.css +34 -0
- package/design-system/components/PaceBar/README.md +75 -0
- package/design-system/components/PaceBar/preview.html +67 -0
- package/design-system/components/PaceBar/style.css +25 -0
- package/design-system/components/Page/README.md +57 -18
- package/design-system/components/Page/preview.html +15 -17
- package/design-system/components/Page/style.css +7 -0
- package/design-system/components/PageBar/README.md +90 -34
- package/design-system/components/PageBar/preview.html +60 -19
- package/design-system/components/PageBar/style.css +35 -0
- package/design-system/components/PageHero/README.md +87 -51
- package/design-system/components/PageHero/preview.html +35 -6
- package/design-system/components/PageHero/style.css +31 -0
- package/design-system/components/Pagination/README.md +70 -49
- package/design-system/components/Pagination/preview.html +24 -15
- package/design-system/components/Pagination/style.css +12 -0
- package/design-system/components/Panel/README.md +109 -51
- package/design-system/components/Panel/preview.html +118 -20
- package/design-system/components/Panel/style.css +51 -0
- package/design-system/components/PasswordInput/README.md +50 -18
- package/design-system/components/PasswordInput/preview.html +71 -21
- package/design-system/components/PasswordInput/style.css +31 -0
- package/design-system/components/Plate/README.md +75 -17
- package/design-system/components/Plate/preview.html +40 -7
- package/design-system/components/Plate/style.css +37 -0
- package/design-system/components/Popover/README.md +70 -49
- package/design-system/components/Popover/preview.html +44 -22
- package/design-system/components/Popover/style.css +41 -0
- package/design-system/components/PricingTable/README.md +69 -49
- package/design-system/components/PricingTable/preview.html +21 -21
- package/design-system/components/PricingTable/style.css +21 -0
- package/design-system/components/ProgressPetals/README.md +31 -3
- package/design-system/components/ProgressPetals/preview.html +14 -15
- package/design-system/components/ProgressPetals/style.css +27 -0
- package/design-system/components/README.md +151 -0
- package/design-system/components/Radio/README.md +40 -17
- package/design-system/components/Radio/preview.html +16 -1
- package/design-system/components/Radio/style.css +21 -0
- package/design-system/components/RankBar/README.md +29 -2
- package/design-system/components/RankBar/preview.html +14 -12
- package/design-system/components/RankBar/style.css +18 -0
- package/design-system/components/Ring/README.md +61 -11
- package/design-system/components/Ring/preview.html +55 -10
- package/design-system/components/Ring/style.css +49 -0
- package/design-system/components/ScoreHero/README.md +91 -0
- package/design-system/components/ScoreHero/preview.html +104 -0
- package/design-system/components/ScoreHero/style.css +32 -0
- package/design-system/components/Section/README.md +72 -33
- package/design-system/components/Section/preview.html +46 -16
- package/design-system/components/Section/style.css +18 -0
- package/design-system/components/Segmented/README.md +100 -55
- package/design-system/components/Segmented/preview.html +107 -26
- package/design-system/components/Segmented/style.css +94 -0
- package/design-system/components/SegmentedProgress/README.md +64 -0
- package/design-system/components/SegmentedProgress/preview.html +69 -0
- package/design-system/components/SegmentedProgress/style.css +11 -0
- package/design-system/components/Select/README.md +47 -12
- package/design-system/components/Select/preview.html +28 -2
- package/design-system/components/Select/style.css +22 -0
- package/design-system/components/ShareBar/README.md +69 -0
- package/design-system/components/ShareBar/preview.html +72 -0
- package/design-system/components/ShareBar/style.css +25 -0
- package/design-system/components/SideList/README.md +147 -0
- package/design-system/components/SideList/preview.html +139 -0
- package/design-system/components/SideList/style.css +94 -0
- package/design-system/components/Skeleton/README.md +52 -16
- package/design-system/components/Skeleton/preview.html +35 -23
- package/design-system/components/Skeleton/style.css +22 -0
- package/design-system/components/Slider/README.md +95 -0
- package/design-system/components/Slider/preview.html +49 -0
- package/design-system/components/Slider/style.css +13 -0
- package/design-system/components/Split/README.md +112 -0
- package/design-system/components/Split/preview.html +105 -0
- package/design-system/components/Split/style.css +30 -0
- package/design-system/components/Starter/README.md +21 -9
- package/design-system/components/Starter/preview.html +5 -5
- package/design-system/components/Stat/README.md +64 -43
- package/design-system/components/Stat/preview.html +3 -3
- package/design-system/components/Stat/style.css +15 -0
- package/design-system/components/StatTiles/README.md +88 -44
- package/design-system/components/StatTiles/preview.html +142 -71
- package/design-system/components/StatTiles/style.css +64 -0
- package/design-system/components/StatusLine/README.md +85 -0
- package/design-system/components/StatusLine/preview.html +49 -0
- package/design-system/components/StatusLine/style.css +14 -0
- package/design-system/components/StatusScreen/README.md +49 -35
- package/design-system/components/StatusScreen/preview.html +20 -5
- package/design-system/components/StatusScreen/style.css +9 -0
- package/design-system/components/StepLine/README.md +97 -0
- package/design-system/components/StepLine/preview.html +108 -0
- package/design-system/components/StepLine/style.css +62 -0
- package/design-system/components/Stepper/README.md +35 -13
- package/design-system/components/Stepper/style.css +13 -0
- package/design-system/components/StreakCalendar/README.md +22 -1
- package/design-system/components/StreakCalendar/preview.html +10 -10
- package/design-system/components/StreakCalendar/style.css +12 -0
- package/design-system/components/SuggestionChip/README.md +87 -0
- package/design-system/components/SuggestionChip/preview.html +42 -0
- package/design-system/components/SuggestionChip/style.css +20 -0
- package/design-system/components/Switch/README.md +44 -24
- package/design-system/components/Switch/preview.html +23 -8
- package/design-system/components/Switch/style.css +31 -0
- package/design-system/components/Table/README.md +129 -58
- package/design-system/components/Table/preview.html +106 -72
- package/design-system/components/Table/style.css +104 -0
- package/design-system/components/Tabs/README.md +71 -46
- package/design-system/components/Tabs/preview.html +56 -24
- package/design-system/components/Tabs/style.css +44 -0
- package/design-system/components/Testimonial/README.md +48 -32
- package/design-system/components/Testimonial/preview.html +14 -14
- package/design-system/components/Testimonial/style.css +12 -0
- package/design-system/components/TextArea/README.md +27 -11
- package/design-system/components/TextArea/preview.html +8 -2
- package/design-system/components/TextArea/style.css +12 -0
- package/design-system/components/ThemeSwitch/README.md +116 -0
- package/design-system/components/ThemeSwitch/preview.html +57 -0
- package/design-system/components/ThemeSwitch/style.css +6 -0
- package/design-system/components/TickRow/README.md +52 -36
- package/design-system/components/TickRow/preview.html +64 -41
- package/design-system/components/TickRow/style.css +23 -0
- package/design-system/components/TickStrip/README.md +95 -0
- package/design-system/components/TickStrip/preview.html +88 -0
- package/design-system/components/TickStrip/style.css +42 -0
- package/design-system/components/Tile/README.md +79 -18
- package/design-system/components/Tile/preview.html +91 -40
- package/design-system/components/Tile/style.css +36 -0
- package/design-system/components/Timeline/README.md +68 -48
- package/design-system/components/Timeline/preview.html +27 -15
- package/design-system/components/Timeline/style.css +25 -0
- package/design-system/components/Toast/README.md +70 -38
- package/design-system/components/Toast/preview.html +43 -8
- package/design-system/components/Toast/style.css +25 -0
- package/design-system/components/Tooltip/README.md +93 -35
- package/design-system/components/Tooltip/preview.html +69 -15
- package/design-system/components/Tooltip/style.css +78 -0
- package/design-system/components/TopBar/README.md +67 -53
- package/design-system/components/TopBar/preview.html +14 -27
- package/design-system/components/TopBar/style.css +35 -0
- package/design-system/components/TopicRail/README.md +108 -0
- package/design-system/components/TopicRail/preview.html +58 -0
- package/design-system/components/TopicRail/style.css +48 -0
- package/design-system/components/TrendBars/README.md +52 -14
- package/design-system/components/TrendBars/preview.html +65 -32
- package/design-system/components/TrendBars/style.css +25 -0
- package/design-system/components/TrendLine/README.md +164 -0
- package/design-system/components/TrendLine/preview.html +373 -0
- package/design-system/components/TrendLine/style.css +155 -0
- package/design-system/components/Well/README.md +64 -22
- package/design-system/components/Well/preview.html +14 -14
- package/design-system/components/Well/style.css +22 -0
- package/design-system/components/_house.css +324 -0
- package/design-system/components/bundle.css +4091 -744
- package/design-system/tokens.json +1314 -124
- package/dist/fello-core.css +2 -2
- package/dist/fello.css +6 -1369
- package/dist/fello.scoped.css +7 -0
- package/dist/index.d.ts +110 -11
- package/dist/index.js +781 -96
- package/dist/palettes.d.ts +464 -0
- package/dist/palettes.js +497 -0
- package/dist/scoped.d.ts +3 -0
- package/dist/scoped.js +16 -0
- package/dist/toast.d.ts +14 -0
- package/dist/toast.js +33 -29
- package/dist/tokens.d.ts +1686 -62
- package/dist/tokens.js +1668 -61
- package/package.json +20 -4
- package/scripts/check-palette.mjs +295 -0
- package/scripts/token-model.mjs +552 -0
- package/tokens/_dark.css +174 -0
- package/tokens/_palettes.css +46 -0
- package/tokens/_product.css +266 -53
- package/tokens/_source.hubl.css +39 -19
- package/tokens/design-tokens.json +319 -0
- package/tokens/palettes.ts +504 -0
- package/tokens/shadcn-compat.css +19 -19
- package/tokens/shadcn-compat.hsl.css +76 -0
- package/tokens/tokens.css +1292 -62
- package/tokens/tokens.md +588 -61
- package/tokens/tokens.root.css +1298 -62
- package/tokens/tokens.ts +1677 -64
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
/* ---- Matrix: Seth's answers grid (305:2341). A yes-or-no answer for each question (a row) and each source (a column),
|
|
2
|
+
in a rim: one column template shared by the head and every row (20 in, 16 out, a 200 px question column, equal
|
|
3
|
+
columns 2 apart), so the heads centre over their cells. Hovering or focusing a row dims every other row to 0.2 and
|
|
4
|
+
shows the whole question in a navy note over it. Under 40rem the question column takes the room and the source names
|
|
5
|
+
drop to their marks. ---- */
|
|
6
|
+
.ws-matrix { --ws-matrix-cols: 4; --ws-matrix-first: var(--space-9xl); --ws-matrix-cell: minmax(0, 1fr); --ws-matrix-dim: 0.2; container: ws-matrix / inline-size; display: flex; flex-direction: column; padding: var(--ws-rim); border-radius: var(--ws-radius-card); background: var(--ws-tray); }
|
|
7
|
+
.ws-matrix__table { display: flex; flex-direction: column; }
|
|
8
|
+
.ws-matrix__row { display: grid; grid-template-columns: var(--ws-matrix-first) repeat(var(--ws-matrix-cols), var(--ws-matrix-cell)); column-gap: var(--space-3xs); min-height: var(--ws-row-h); padding: var(--ws-line) var(--space-md) var(--ws-line) var(--ws-card-inset); background: var(--color-bg-page); }
|
|
9
|
+
/* Rows are joined by 0.5 px lines, full width, drawn inside the row's top (Seth's 48 includes its line, so a border would
|
|
10
|
+
add 0.5 a row); the rim's inner corners on the first and last row. */
|
|
11
|
+
.ws-matrix__body > .ws-matrix__row, .ws-matrix__foot { box-shadow: inset 0 var(--ws-hairline) 0 var(--ws-edge); }
|
|
12
|
+
.ws-matrix__head > .ws-matrix__row { border-radius: var(--ws-radius-card-inner) var(--ws-radius-card-inner) 0 0; }
|
|
13
|
+
.ws-matrix__table:last-child .ws-matrix__body > .ws-matrix__row:last-child, .ws-matrix__foot { border-radius: 0 0 var(--ws-radius-card-inner) var(--ws-radius-card-inner); }
|
|
14
|
+
/* Head: 16 above and below; "Question" in 13 / 18 medium muted; each source a 20 px mark and its name, 15 / 22 semibold,
|
|
15
|
+
centred over its column (the head cell carries the name as its aria-label too). */
|
|
16
|
+
.ws-matrix__head > .ws-matrix__row { align-items: center; padding-block: var(--space-md); }
|
|
17
|
+
.ws-matrix__corner { font-size: var(--ws-text-control); line-height: var(--ws-leading-control); font-weight: 500; color: var(--color-text-muted); text-align: left; }
|
|
18
|
+
.ws-matrix__col { display: flex; align-items: center; justify-content: center; gap: var(--space-xs); min-width: 0; font-size: var(--ws-text-section); line-height: var(--ws-leading-section); font-weight: 600; color: var(--color-text-heading); }
|
|
19
|
+
.ws-matrix__mark { flex-shrink: 0; width: var(--ws-icon-lg); height: var(--ws-icon-lg); }
|
|
20
|
+
.ws-matrix__name { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
21
|
+
/* The question: 14 / 20 medium navy with a 1 px dotted underline, the cue that the whole question shows on hover or focus. */
|
|
22
|
+
.ws-matrix__q-cell { display: flex; align-items: center; min-width: 0; padding-right: var(--space-md); }
|
|
23
|
+
.ws-matrix__q-wrap { position: relative; display: inline-flex; min-width: 0; }
|
|
24
|
+
.ws-matrix__q { min-width: 0; padding: 0; border: 0; background: none; font-size: var(--ws-text-body); line-height: calc(var(--space-md) + var(--space-xxs)); font-weight: 500; color: var(--color-text-heading); text-align: left; text-decoration: underline dotted var(--ws-line); text-underline-offset: var(--ws-halo); cursor: help; }
|
|
25
|
+
/* On touch the question's box grows to 24 without moving a thing. */
|
|
26
|
+
@media (pointer: coarse) { .ws-matrix__q { padding-block: var(--space-3xs); margin-block: calc(var(--space-3xs) * -1); } }
|
|
27
|
+
/* A cell: the row's height less its 1 px in, 2 px corners; named = the strong tone, not named = the empty track; the
|
|
28
|
+
source's mark centred in it (a dimmed mark on the empty track). Its words are for a screen reader. */
|
|
29
|
+
.ws-matrix__cell { display: flex; align-items: center; justify-content: center; min-height: calc(var(--ws-row-h) - var(--ws-line) * 2); border-radius: var(--ws-radius-chip); background: var(--ws-track); color: var(--color-text-heading); }
|
|
30
|
+
.ws-matrix__cell--yes { background: var(--ws-rating-strong); }
|
|
31
|
+
/* In dark the strong tone is a light teal, so the mark on it takes the ground's dark (navy on teal in light). */
|
|
32
|
+
[data-theme="dark"] .ws-matrix__cell--yes { color: var(--color-bg-page); }
|
|
33
|
+
@media (prefers-color-scheme: dark) { [data-theme="system"] .ws-matrix__cell--yes { color: var(--color-bg-page); } }
|
|
34
|
+
.ws-matrix__cell:not(.ws-matrix__cell--yes) > .ws-matrix__mark { opacity: var(--ws-dim); }
|
|
35
|
+
.ws-matrix__cell.ws-shimmer { background: var(--ws-shimmer); background-size: 300% 100%; }
|
|
36
|
+
/* The note (Seth's navy tip): the act fill, 4 px corners, 14 / 20 words that wrap at 300 (the note 324 with its 12 px
|
|
37
|
+
sides, as Tooltip --note), left-anchored so its words start on the question's, a 12 x 6 caret over the word, 3 above
|
|
38
|
+
it. No shadow. */
|
|
39
|
+
.ws-matrix__tip { position: absolute; z-index: 1; left: calc(var(--space-sm) * -1); bottom: calc(100% + var(--ws-halo) + var(--space-xxs-plus)); width: max-content; max-width: min(calc(var(--ws-float-width) + var(--space-sm) * 2), calc(100cqi - var(--space-lg))); padding: var(--space-xs-plus) var(--space-sm); border-radius: var(--ws-radius-control); background: var(--color-text-heading); color: var(--ws-on-act); font-size: var(--ws-text-body); line-height: calc(var(--space-md) + var(--space-xxs)); font-weight: 400; text-align: left; white-space: normal; visibility: hidden; opacity: 0; pointer-events: none; }
|
|
40
|
+
.ws-matrix__tip::after { content: ""; position: absolute; top: 100%; left: calc(var(--space-lg) + var(--space-xxs-plus)); width: var(--space-sm); height: var(--space-xxs-plus); background: inherit; clip-path: polygon(0 0, 100% 0, 50% 100%); }
|
|
41
|
+
.ws-matrix__q:focus + .ws-matrix__tip, .ws-matrix__q[aria-expanded="true"] + .ws-matrix__tip { visibility: visible; opacity: 1; }
|
|
42
|
+
/* Keyboard focus draws the ring 4 px round the question: the note's caret keeps its 3 px clear of the ring, not the word. */
|
|
43
|
+
.ws-matrix__q:focus-visible + .ws-matrix__tip { bottom: calc(100% + var(--ws-focus-offset) + var(--ws-focus-width) + var(--ws-halo) + var(--space-xxs-plus)); }
|
|
44
|
+
/* Focusing (or tapping) a row dims the others, as hover does. Row grounds, lines, the head and the foot stay. */
|
|
45
|
+
.ws-matrix__body:has(> .ws-matrix__row:focus-within) > .ws-matrix__row:not(:focus-within) > * { opacity: var(--ws-matrix-dim); }
|
|
46
|
+
@media (hover: hover) {
|
|
47
|
+
.ws-matrix__body > .ws-matrix__row:hover .ws-matrix__tip { visibility: visible; opacity: 1; }
|
|
48
|
+
.ws-matrix__body:has(> .ws-matrix__row:hover) > .ws-matrix__row:not(:hover) > * { opacity: var(--ws-matrix-dim); }
|
|
49
|
+
}
|
|
50
|
+
/* The note covers the row above, so Escape must hide it without moving the pointer (WCAG 1.4.13): a page script sets
|
|
51
|
+
data-tip="hidden" on the row and clears it when the pointer or focus leaves. */
|
|
52
|
+
.ws-matrix__body > .ws-matrix__row[data-tip="hidden"] .ws-matrix__tip { visibility: hidden; opacity: 0; }
|
|
53
|
+
/* Motion: the dim and the note fade on hover's 200 ms after a 40 ms intent; the note leaves on the 120 ms exit. */
|
|
54
|
+
@media (prefers-reduced-motion: no-preference) {
|
|
55
|
+
.ws-matrix__row > * { transition: opacity var(--ws-duration-hover) var(--ws-ease-soft); }
|
|
56
|
+
.ws-matrix__tip { transition: opacity var(--ws-duration-exit) var(--ws-ease-exit), visibility 0s linear var(--ws-duration-exit); }
|
|
57
|
+
.ws-matrix__q:focus + .ws-matrix__tip, .ws-matrix__q[aria-expanded="true"] + .ws-matrix__tip { transition: opacity var(--ws-duration-hover) var(--ws-ease-soft) var(--ws-hover-intent), visibility 0s linear var(--ws-hover-intent); }
|
|
58
|
+
}
|
|
59
|
+
@media (hover: hover) and (prefers-reduced-motion: no-preference) {
|
|
60
|
+
.ws-matrix__body > .ws-matrix__row:hover .ws-matrix__tip { transition: opacity var(--ws-duration-hover) var(--ws-ease-soft) var(--ws-hover-intent), visibility 0s linear var(--ws-hover-intent); }
|
|
61
|
+
}
|
|
62
|
+
/* Foot (Seth's "Behind the answers"): a folded row in the rim, 16 above and below, title, line, chevron. */
|
|
63
|
+
.ws-matrix__foot { background: var(--color-bg-page); }
|
|
64
|
+
.ws-matrix__foot > summary { display: flex; align-items: center; gap: var(--space-sm); padding: var(--space-md) var(--space-md) var(--space-md) var(--ws-card-inset); border-radius: inherit; list-style: none; cursor: pointer; }
|
|
65
|
+
.ws-matrix__foot > summary::-webkit-details-marker { display: none; }
|
|
66
|
+
.ws-matrix__foot > summary:focus-visible { outline-offset: calc(var(--ws-focus-width) * -1); }
|
|
67
|
+
.ws-matrix__foot-title { flex: none; font-size: var(--ws-text-section); line-height: var(--ws-leading-section); font-weight: 600; color: var(--color-text-heading); }
|
|
68
|
+
.ws-matrix__foot-line { flex: 1; min-width: 0; font-size: var(--ws-text-control); line-height: var(--ws-leading-control); font-weight: 500; color: var(--color-text-muted); }
|
|
69
|
+
.ws-matrix__foot > summary > svg { flex-shrink: 0; width: var(--ws-icon); height: var(--ws-icon); color: var(--color-text-heading); }
|
|
70
|
+
.ws-matrix__foot[open] > summary > svg { transform: rotate(180deg); }
|
|
71
|
+
.ws-matrix__foot-body { padding: 0 var(--space-md) var(--space-md) var(--ws-card-inset); }
|
|
72
|
+
@media (prefers-reduced-motion: no-preference) { .ws-matrix__foot > summary > svg { transition: transform var(--ws-duration-settle) var(--ws-ease-soft); } }
|
|
73
|
+
/* Narrow: the question column takes the room, each source column 32 wide and only its mark (the head cell's aria-label
|
|
74
|
+
names it, so a screen reader still hears the source); the question 8 from the cells. The foot's line drops under its
|
|
75
|
+
title, the chevron staying at the end of the title's line. */
|
|
76
|
+
@container ws-matrix (max-width: 40rem) {
|
|
77
|
+
.ws-matrix__row { grid-template-columns: minmax(0, 1fr) repeat(var(--ws-matrix-cols), var(--space-xl)); }
|
|
78
|
+
.ws-matrix__name { display: none; }
|
|
79
|
+
.ws-matrix__q-cell { padding-right: var(--space-xs); }
|
|
80
|
+
.ws-matrix__q { white-space: normal; }
|
|
81
|
+
.ws-matrix__foot > summary { flex-wrap: wrap; row-gap: var(--space-xxs); }
|
|
82
|
+
.ws-matrix__foot > summary > svg { margin-left: auto; }
|
|
83
|
+
.ws-matrix__foot-line { flex-basis: 100%; order: 1; }
|
|
84
|
+
}
|
|
@@ -1,67 +1,98 @@
|
|
|
1
|
-
A small panel of rows
|
|
1
|
+
A small panel of rows lifted off the page: the one menu, for an account, a page's "more", or a short list of choices.
|
|
2
2
|
|
|
3
3
|
## Use it when
|
|
4
4
|
|
|
5
|
-
- A button opens a short, flat list of actions or links (the account menu, a
|
|
6
|
-
-
|
|
7
|
-
-
|
|
5
|
+
- A button opens a short, flat list of actions or links (the account menu, a row's "more", a chat's options).
|
|
6
|
+
- The person picks one of a few ways to see something (sort, group), and the choice shows its tick.
|
|
7
|
+
- A few related actions are grouped, with a line between groups.
|
|
8
8
|
|
|
9
9
|
## Not for
|
|
10
10
|
|
|
11
|
-
- A thing's full detail
|
|
12
|
-
- A short task
|
|
13
|
-
- A
|
|
14
|
-
- A
|
|
11
|
+
- A thing's full detail: use `Panel`.
|
|
12
|
+
- A short task that needs the person's full attention: use `Dialog`.
|
|
13
|
+
- A note or a one-field form: use `Popover`.
|
|
14
|
+
- A long list of records: use rows or a `Table`.
|
|
15
|
+
- A switch between a few fixed views: use `Segmented`.
|
|
15
16
|
|
|
16
17
|
## Anatomy
|
|
17
18
|
|
|
18
|
-
- The panel (`ws-menu`):
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
- A row
|
|
19
|
+
- The panel (`ws-menu`): `--ws-raised` ground, 10 px corners (North's menu, `--ws-radius-menu`), the 0.5 px
|
|
20
|
+
hairline and the menu drop (`--ws-shadow-hairline`, `--ws-shadow-menu`), 4 px inside, at least 200 wide. Never
|
|
21
|
+
wider than the window less 32 or taller than it less 32; past that it scrolls on its own.
|
|
22
|
+
- A row (`ws-menu-item`): 8 above and below 13 / 18 medium navy words, 10 at the sides, 6 px corners
|
|
23
|
+
(`--ws-radius-row`), so 34 tall; 40 on touch. A 16 px muted line icon before the words when given
|
|
24
|
+
(`ws-menu-item__icon`), 8 apart. A row is a link when it goes somewhere, a button when it does something.
|
|
25
|
+
- A hint (`ws-menu-item__hint`, inside `ws-menu-item__words`): an 11 / 13 muted line under the words, 2 apart; the icon
|
|
26
|
+
then sits on the words' first line.
|
|
27
|
+
- A tick (`ws-menu-item__tick`): 16 px navy at the row's end, shown only on the chosen row of a choice.
|
|
28
|
+
- The line between groups (`ws-menu-line`): 1 px of `--ws-menu-line`, 4 above and below, the menu's full width.
|
|
22
29
|
|
|
23
30
|
## Variants and sizes
|
|
24
31
|
|
|
25
|
-
| Row
|
|
32
|
+
| Row | Element | `role` |
|
|
26
33
|
| --- | --- | --- |
|
|
27
|
-
| Goes somewhere |
|
|
28
|
-
| Does something |
|
|
29
|
-
| A
|
|
30
|
-
| The current item | `current` |
|
|
34
|
+
| Goes somewhere | `<a class="ws-menu-item">` | `menuitem` |
|
|
35
|
+
| Does something | `<button class="ws-menu-item">` | `menuitem` |
|
|
36
|
+
| A choice | `<button class="ws-menu-item">` with `ws-menu-item__tick` | `menuitemradio` or `menuitemcheckbox`, `aria-checked` |
|
|
37
|
+
| The current item | `aria-current="page"` (or `ws-menu-item--current`) | keeps the `--ws-menu-hover` tint |
|
|
31
38
|
|
|
32
39
|
## States
|
|
33
40
|
|
|
34
|
-
- **Default**:
|
|
35
|
-
- **Hover**: the
|
|
36
|
-
|
|
37
|
-
- **
|
|
38
|
-
- **
|
|
39
|
-
- **
|
|
40
|
-
- **
|
|
41
|
-
- **
|
|
41
|
+
- **Default**: rows on the raised ground.
|
|
42
|
+
- **Hover**: the navy wash (`--ws-hover`, .05) over `--ws-duration-hover`; only for pointers that hover, so a tap
|
|
43
|
+
never leaves it behind.
|
|
44
|
+
- **Pressed**: the press tint (`--ws-surface-press`), at once; the current row too.
|
|
45
|
+
- **Focus**: the 2 px navy ring drawn inside the row.
|
|
46
|
+
- **Current**: a steady `--ws-menu-hover` tint.
|
|
47
|
+
- **Chosen**: the tick shows (`aria-checked="true"`).
|
|
48
|
+
- **Disabled**: 50%, no presses; say why in its own words ("Billing (owner only)").
|
|
49
|
+
- **Long label**: the row grows to two lines; words are never cut.
|
|
50
|
+
- **Opening** (North js@620042, "Messages and steps settle"): it grows out of the corner it hangs from, 4 px toward
|
|
51
|
+
its button and .97 (`--ws-open-scale`), on the settle spring (`--ws-spring-settle`, .32 / .1, 450 ms to rest). A
|
|
52
|
+
native popover does it with `@starting-style`; one the app mounts plays `ws-menu-in`.
|
|
53
|
+
- **Leaving** (`data-leaving`, or a native popover closing): it goes back into that corner (the same 4 px and .97,
|
|
54
|
+
fading) over `--ws-duration-exit` (120 ms) on `--ws-ease-exit`, faster than it came, taking no presses. A native
|
|
55
|
+
popover keeps its box while it leaves (`display` and `overlay` transition with `allow-discrete`), and a close
|
|
56
|
+
mid-entrance turns back from where it is. Wait 120 ms after `data-leaving` before removing it.
|
|
57
|
+
- **Opened above** (it flipped, or the app placed it there): where the browser places it by anchor the nudge rides on
|
|
58
|
+
the margin, which the flip fallbacks turn with it, so it still comes from its button; it scales from the top right
|
|
59
|
+
either way (CSS cannot tell `transform-origin` which fallback won). An app that places it (Floating UI, Radix) sets
|
|
60
|
+
`data-side="top"`, and the nudge and the corner both turn round.
|
|
42
61
|
|
|
43
62
|
## Behaviour
|
|
44
63
|
|
|
45
|
-
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
64
|
+
- Placement (K9): open it in the top layer with the native `popover` attribute and its button's `popovertarget`.
|
|
65
|
+
Nothing then cuts it (a card, a dialog, a scroller). Where the browser places by anchor, it hangs 8 under its
|
|
66
|
+
button, right edges flush (left edges once it flips to the other side). A tall one stays under its button, capped
|
|
67
|
+
to the room below less 8 and scrolling inside, so it never covers the button; it flips above only when less than
|
|
68
|
+
200 px (or less than its own height) fits below, and a menu wider than either side of its button (a phone) centres
|
|
69
|
+
in the window under it. The button is its anchor when the button opens it (or `showPopover({ source: button })`).
|
|
70
|
+
In a React app, portal it (Radix, Floating UI) with
|
|
71
|
+
`flip` and `shift`; in a scoped app the portal root carries `class="fello"`. A native popover needs no portal: it
|
|
72
|
+
stays where it is in the page, so it keeps the `.fello` scope and the page's tokens.
|
|
73
|
+
- Keyboard: `popover="auto"` closes on Escape and on a press outside, and focus goes back to the button. Arrow keys
|
|
74
|
+
move between rows only where a library gives the menu roving focus; never hand-rolled.
|
|
75
|
+
- Pointer: a press on a row runs it, then the app closes the menu (`hidePopover()`); a link row closes it by going.
|
|
76
|
+
- Touch: rows are 40 tall.
|
|
77
|
+
- Reduced motion: it appears and goes at once. A browser without `@starting-style` or `linear()` shows and hides it
|
|
78
|
+
at once too; nothing else changes.
|
|
79
|
+
- The preview's last two stacks are live: press Sort, and Move (at the page's foot, so it opens above).
|
|
50
80
|
|
|
51
81
|
## Content
|
|
52
82
|
|
|
53
|
-
- Each row
|
|
54
|
-
- A
|
|
55
|
-
-
|
|
83
|
+
- Each row is a short verb phrase or a place's name, sentence case ("Invite your team").
|
|
84
|
+
- A hint says what the row does in a few words, never a second label.
|
|
85
|
+
- A disabled row's reason is part of its own words.
|
|
86
|
+
- Rare or destructive rows ("Sign out") sit last, after a line.
|
|
56
87
|
|
|
57
88
|
## Props
|
|
58
89
|
|
|
59
|
-
**`MenuItem`**
|
|
90
|
+
**`MenuItem`** (the reference implementation)
|
|
60
91
|
|
|
61
92
|
| Name | Type | Meaning |
|
|
62
93
|
| --- | --- | --- |
|
|
63
94
|
| `href` | string | Makes the row a link. |
|
|
64
|
-
| `scroll` | boolean | For a link: `false` keeps the page where it is
|
|
95
|
+
| `scroll` | boolean | For a link: `false` keeps the page where it is. |
|
|
65
96
|
| `current` | boolean | Marks the row the person is already on. |
|
|
66
97
|
| `className` | string | Layout only. |
|
|
67
98
|
| `children` | `ReactNode` | The row's icon and words. |
|
|
@@ -69,12 +100,57 @@ A small panel of rows, lifted off the page: the one menu, for an account, a page
|
|
|
69
100
|
|
|
70
101
|
## Rules
|
|
71
102
|
|
|
72
|
-
- One component for every menu
|
|
73
|
-
-
|
|
74
|
-
-
|
|
103
|
+
- One component for every menu: never a hand-styled dropdown.
|
|
104
|
+
- In one menu every row has an icon or none does, so the words share one edge (an icon row's words start 24 further in).
|
|
105
|
+
- A menu floats, so it is one of the few things with a shadow: the menu drop, never a lift on a card.
|
|
106
|
+
- It closes once the person has moved on: Escape, a press outside, a row chosen.
|
|
75
107
|
|
|
76
108
|
## Source
|
|
77
109
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
110
|
+
**Derived from**: Seth's North menu (style1.css:657-660: 10 px corners, 4 inside, rows 8 / 10 with 6 px corners, 13 px
|
|
111
|
+
medium words over a quieter line, navy .05 hover, `0 16px 32px -16px` drop; P1, popovers 8 under, from their corner,
|
|
112
|
+
js@620042), Revenue OS K9 (17 of 76 menus cut at 1440), and the field fixes (gated hover, press tint, disabled 50%).
|
|
113
|
+
**Precedent**: the first product built on the system.
|
|
114
|
+
|
|
115
|
+
## Markup
|
|
116
|
+
|
|
117
|
+
```html
|
|
118
|
+
<button type="button" class="ws-btn ws-btn--secondary" popovertarget="account-menu">Dana Reyes</button>
|
|
119
|
+
<div id="account-menu" class="ws-menu" role="menu" aria-label="Account" popover>
|
|
120
|
+
<a href="/profile" class="ws-menu-item" role="menuitem">
|
|
121
|
+
<svg class="ws-menu-item__icon" viewBox="0 0 16 16" fill="none"><circle cx="8" cy="5.5" r="2.5" stroke="currentColor" stroke-width="1.5"/><path d="M3 13c0-2.5 2.2-4 5-4s5 1.5 5 4" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/></svg>
|
|
122
|
+
Your profile
|
|
123
|
+
</a>
|
|
124
|
+
<div class="ws-menu-line" role="separator"></div>
|
|
125
|
+
<button type="button" class="ws-menu-item" role="menuitem">
|
|
126
|
+
<svg class="ws-menu-item__icon" viewBox="0 0 16 16" fill="none"><path d="M6 4H4a1 1 0 0 0-1 1v6a1 1 0 0 0 1 1h2M10 11l3-3-3-3M13 8H6" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/></svg>
|
|
127
|
+
Sign out
|
|
128
|
+
</button>
|
|
129
|
+
</div>
|
|
130
|
+
|
|
131
|
+
<!-- a choice: no icons, the tick at the row's end -->
|
|
132
|
+
<button type="button" class="ws-btn ws-btn--secondary" popovertarget="sort-menu">Sort</button>
|
|
133
|
+
<div id="sort-menu" class="ws-menu" role="menu" aria-label="Sort the list" popover>
|
|
134
|
+
<button type="button" class="ws-menu-item" role="menuitemradio" aria-checked="true">
|
|
135
|
+
<span class="ws-menu-item__words">
|
|
136
|
+
<span>Needs you first</span>
|
|
137
|
+
<span class="ws-menu-item__hint">Overdue calls, then the oldest reply</span>
|
|
138
|
+
</span>
|
|
139
|
+
<svg class="ws-menu-item__tick" viewBox="0 0 16 16" fill="none" aria-hidden="true"><path d="M3.5 8.5l3 3 6-7" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/></svg>
|
|
140
|
+
</button>
|
|
141
|
+
<button type="button" class="ws-menu-item" role="menuitemradio" aria-checked="false">
|
|
142
|
+
<span class="ws-menu-item__words">
|
|
143
|
+
<span>Newest first</span>
|
|
144
|
+
<span class="ws-menu-item__hint">By when the lead came in</span>
|
|
145
|
+
</span>
|
|
146
|
+
<svg class="ws-menu-item__tick" viewBox="0 0 16 16" fill="none" aria-hidden="true"><path d="M3.5 8.5l3 3 6-7" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/></svg>
|
|
147
|
+
</button>
|
|
148
|
+
</div>
|
|
149
|
+
<!-- where a browser needs the anchor said: style="anchor-name: --account" on the button,
|
|
150
|
+
style="position-anchor: --account" on the menu -->
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
## Styles
|
|
154
|
+
|
|
155
|
+
`Menu/style.css` reshapes the house `.ws-menu`, `.ws-menu-item` and `.ws-menu-line`; all are in `bundle.css` and
|
|
156
|
+
`fello.css`. Tokens only, so it turns dark with the page.
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
<!-- @dsCard group="Overlays" height=
|
|
1
|
+
<!-- @dsCard group="Overlays" height=310 -->
|
|
2
2
|
<!doctype html>
|
|
3
3
|
<html>
|
|
4
4
|
<head>
|
|
@@ -10,34 +10,96 @@
|
|
|
10
10
|
<body>
|
|
11
11
|
<div class="ws-stage ws-stage--grey">
|
|
12
12
|
|
|
13
|
-
<div class="ws-stack" style="width:
|
|
14
|
-
<span class="ws-muted">
|
|
15
|
-
<div class="ws-
|
|
16
|
-
<button type="button" class="ws-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
<
|
|
27
|
-
|
|
13
|
+
<div class="ws-stack" style="width: 260px;">
|
|
14
|
+
<span class="ws-muted">Hangs 8 under its button, right edges flush; the current row is tinted</span>
|
|
15
|
+
<div class="ws-stack" style="align-items: flex-end; gap: var(--space-xs);">
|
|
16
|
+
<button type="button" class="ws-btn ws-btn--secondary" aria-haspopup="menu" aria-expanded="true">Dana Reyes</button>
|
|
17
|
+
<div class="ws-menu" role="menu" aria-label="Account" style="width: 240px;">
|
|
18
|
+
<a href="#profile" class="ws-menu-item" role="menuitem" aria-current="page">
|
|
19
|
+
<svg class="ws-menu-item__icon" viewBox="0 0 16 16" fill="none"><circle cx="8" cy="5.5" r="2.5" stroke="currentColor" stroke-width="1.5"/><path d="M3 13c0-2.5 2.2-4 5-4s5 1.5 5 4" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/></svg>
|
|
20
|
+
Your profile
|
|
21
|
+
</a>
|
|
22
|
+
<button type="button" class="ws-menu-item" role="menuitem">
|
|
23
|
+
<svg class="ws-menu-item__icon" viewBox="0 0 16 16" fill="none"><path d="M8 2v2M8 12v2M3 8H1M15 8h-2M4 4l1.4 1.4M10.6 10.6L12 12M4 12l1.4-1.4M10.6 5.4L12 4" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/><circle cx="8" cy="8" r="2.5" stroke="currentColor" stroke-width="1.5"/></svg>
|
|
24
|
+
Settings
|
|
25
|
+
</button>
|
|
26
|
+
<div class="ws-menu-line" role="separator"></div>
|
|
27
|
+
<button type="button" class="ws-menu-item" role="menuitem">
|
|
28
|
+
<svg class="ws-menu-item__icon" viewBox="0 0 16 16" fill="none"><rect x="2.5" y="2.5" width="11" height="11" rx="2" stroke="currentColor" stroke-width="1.5"/><path d="M6 8h4M8 6v4" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/></svg>
|
|
29
|
+
Invite your team
|
|
30
|
+
</button>
|
|
31
|
+
<button type="button" class="ws-menu-item" role="menuitem" aria-disabled="true">
|
|
32
|
+
<svg class="ws-menu-item__icon" viewBox="0 0 16 16" fill="none"><rect x="3.5" y="7" width="9" height="6" rx="1.5" stroke="currentColor" stroke-width="1.5"/><path d="M5.5 7V5a2.5 2.5 0 0 1 5 0v2" stroke="currentColor" stroke-width="1.5"/></svg>
|
|
33
|
+
Billing (owner only)
|
|
34
|
+
</button>
|
|
35
|
+
<div class="ws-menu-line" role="separator"></div>
|
|
36
|
+
<button type="button" class="ws-menu-item" role="menuitem">
|
|
37
|
+
<svg class="ws-menu-item__icon" viewBox="0 0 16 16" fill="none"><path d="M6 4H4a1 1 0 0 0-1 1v6a1 1 0 0 0 1 1h2M10 11l3-3-3-3M13 8H6" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/></svg>
|
|
38
|
+
Sign out
|
|
39
|
+
</button>
|
|
40
|
+
</div>
|
|
41
|
+
</div>
|
|
42
|
+
</div>
|
|
43
|
+
|
|
44
|
+
<div class="ws-stack" style="width: 260px;">
|
|
45
|
+
<span class="ws-muted">Rows with a hint, and a choice that shows its tick</span>
|
|
46
|
+
<div class="ws-menu" role="menu" aria-label="Sort the list">
|
|
47
|
+
<button type="button" class="ws-menu-item" role="menuitemradio" aria-checked="true">
|
|
48
|
+
<span class="ws-menu-item__words">
|
|
49
|
+
<span>Needs you first</span>
|
|
50
|
+
<span class="ws-menu-item__hint">Overdue calls, then the oldest reply</span>
|
|
51
|
+
</span>
|
|
52
|
+
<svg class="ws-menu-item__tick" viewBox="0 0 16 16" fill="none" aria-hidden="true"><path d="M3.5 8.5l3 3 6-7" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/></svg>
|
|
28
53
|
</button>
|
|
29
|
-
<button type="button" class="ws-menu-item" role="
|
|
30
|
-
<
|
|
31
|
-
|
|
54
|
+
<button type="button" class="ws-menu-item" role="menuitemradio" aria-checked="false">
|
|
55
|
+
<span class="ws-menu-item__words">
|
|
56
|
+
<span>Newest first</span>
|
|
57
|
+
<span class="ws-menu-item__hint">By when the lead came in</span>
|
|
58
|
+
</span>
|
|
59
|
+
<svg class="ws-menu-item__tick" viewBox="0 0 16 16" fill="none" aria-hidden="true"><path d="M3.5 8.5l3 3 6-7" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/></svg>
|
|
32
60
|
</button>
|
|
33
|
-
<
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
61
|
+
<button type="button" class="ws-menu-item" role="menuitemradio" aria-checked="false">
|
|
62
|
+
<span class="ws-menu-item__words">
|
|
63
|
+
<span>Biggest deal first</span>
|
|
64
|
+
<span class="ws-menu-item__hint">By the quote, then by the stage</span>
|
|
65
|
+
</span>
|
|
66
|
+
<svg class="ws-menu-item__tick" viewBox="0 0 16 16" fill="none" aria-hidden="true"><path d="M3.5 8.5l3 3 6-7" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/></svg>
|
|
37
67
|
</button>
|
|
38
68
|
</div>
|
|
39
69
|
</div>
|
|
40
70
|
|
|
71
|
+
<div class="ws-stack" style="width: 260px;">
|
|
72
|
+
<span class="ws-muted">A long row wraps to two lines instead of cutting its words</span>
|
|
73
|
+
<div class="ws-menu" role="menu" aria-label="This lead">
|
|
74
|
+
<button type="button" class="ws-menu-item" role="menuitem">Copy the link</button>
|
|
75
|
+
<button type="button" class="ws-menu-item" role="menuitem">Move to the team list so someone new can try them</button>
|
|
76
|
+
<div class="ws-menu-line" role="separator"></div>
|
|
77
|
+
<button type="button" class="ws-menu-item" role="menuitem">Archive</button>
|
|
78
|
+
</div>
|
|
79
|
+
</div>
|
|
80
|
+
|
|
81
|
+
<div class="ws-stack" style="width: 260px;" data-live>
|
|
82
|
+
<span class="ws-muted">Live: press Sort. It grows out of its corner on the settle spring and goes back into it faster; Move, at the foot of the page, opens above when there is no room under it</span>
|
|
83
|
+
<div class="ws-cluster" style="justify-content: space-between;">
|
|
84
|
+
<button type="button" class="ws-btn ws-btn--secondary" popovertarget="menu-live" aria-haspopup="menu">Sort</button>
|
|
85
|
+
</div>
|
|
86
|
+
<div id="menu-live" class="ws-menu" popover role="menu" aria-label="Sort the list" style="width: 240px;">
|
|
87
|
+
<button type="button" class="ws-menu-item" role="menuitemradio" aria-checked="true" popovertarget="menu-live" popovertargetaction="hide">Needs you first<svg class="ws-menu-item__tick" viewBox="0 0 16 16" fill="none" aria-hidden="true"><path d="M3.5 8.5l3 3 6-7" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/></svg></button>
|
|
88
|
+
<button type="button" class="ws-menu-item" role="menuitemradio" aria-checked="false" popovertarget="menu-live" popovertargetaction="hide">Newest first<svg class="ws-menu-item__tick" viewBox="0 0 16 16" fill="none" aria-hidden="true"><path d="M3.5 8.5l3 3 6-7" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/></svg></button>
|
|
89
|
+
<button type="button" class="ws-menu-item" role="menuitemradio" aria-checked="false" popovertarget="menu-live" popovertargetaction="hide">Biggest deal first<svg class="ws-menu-item__tick" viewBox="0 0 16 16" fill="none" aria-hidden="true"><path d="M3.5 8.5l3 3 6-7" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/></svg></button>
|
|
90
|
+
</div>
|
|
91
|
+
</div>
|
|
92
|
+
|
|
93
|
+
<div class="ws-stack" style="width: 100%; align-items: flex-end;" data-live>
|
|
94
|
+
<button type="button" class="ws-btn ws-btn--secondary" popovertarget="menu-live-up" aria-haspopup="menu">Move</button>
|
|
95
|
+
<div id="menu-live-up" class="ws-menu" popover role="menu" aria-label="Move this lead" style="width: 240px;">
|
|
96
|
+
<button type="button" class="ws-menu-item" role="menuitem" popovertarget="menu-live-up" popovertargetaction="hide">To the team list</button>
|
|
97
|
+
<button type="button" class="ws-menu-item" role="menuitem" popovertarget="menu-live-up" popovertargetaction="hide">To Dana Reyes</button>
|
|
98
|
+
<div class="ws-menu-line" role="separator"></div>
|
|
99
|
+
<button type="button" class="ws-menu-item" role="menuitem" popovertarget="menu-live-up" popovertargetaction="hide">Archive</button>
|
|
100
|
+
</div>
|
|
101
|
+
</div>
|
|
102
|
+
|
|
41
103
|
</div>
|
|
42
104
|
</body>
|
|
43
105
|
</html>
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/* ---- Menu: the house .ws-menu in Seth's North shape (C43): 10 px corners on the hairline and the menu drop, 6 px rows of
|
|
2
|
+
13 px words with an 11 px hint, opened in the top layer and kept on screen ---- */
|
|
3
|
+
/* The panel: never taller or wider than the window (K9), its own scroll past that. Its corner is where it grows from:
|
|
4
|
+
the top right, under the button it hangs from (North P1). */
|
|
5
|
+
.ws-menu { max-width: calc(100vw - var(--space-xl)); max-height: calc(100dvh - var(--space-xl)); overflow-y: auto; overscroll-behavior: contain; border: 0; border-radius: var(--ws-radius-menu); color: inherit; box-shadow: var(--ws-shadow-hairline), var(--ws-shadow-menu); transform-origin: top right; }
|
|
6
|
+
/* A row: 8 above and below 13 / 18 words, 10 at the sides, 6 px corners; 40 tall on touch (house K10). The hover wash is
|
|
7
|
+
gated to pointers that hover, so a tap never leaves it behind; a press is the press tint. */
|
|
8
|
+
.ws-menu-item { padding: var(--space-xs) var(--space-xs-plus); border-radius: var(--ws-radius-row); text-decoration: none; font-size: var(--ws-text-control); line-height: var(--ws-leading-control); transition: background-color var(--ws-duration-hover) var(--ws-ease-soft); }
|
|
9
|
+
.ws-menu-item:hover { background: none; }
|
|
10
|
+
@media (hover: hover) { .ws-menu-item:hover { background: var(--ws-hover); } }
|
|
11
|
+
/* Both ways of marking the current row weigh the same, so neither loses its tint to the hover rules above. */
|
|
12
|
+
.ws-menu-item[aria-current], .ws-menu-item.ws-menu-item--current { background: var(--ws-menu-hover); }
|
|
13
|
+
/* The press comes last, so the current row answers a press too. */
|
|
14
|
+
.ws-menu-item:active { background: var(--ws-surface-press); transition-duration: var(--ws-duration-instant); }
|
|
15
|
+
.ws-menu-item:disabled, .ws-menu-item[aria-disabled="true"] { opacity: 0.5; pointer-events: none; }
|
|
16
|
+
/* The line between groups runs the menu's full width, past its 4 px padding (North D1). */
|
|
17
|
+
.ws-menu-line { margin-inline: calc(var(--space-xxs) * -1); }
|
|
18
|
+
.ws-menu-item__icon { flex-shrink: 0; width: var(--ws-icon); height: var(--ws-icon); color: var(--color-text-muted); }
|
|
19
|
+
/* A row with a hint: the words over an 11 / 13 line, the icon and the tick centred on the first line. */
|
|
20
|
+
.ws-menu-item__words { display: flex; flex: 1; flex-direction: column; gap: var(--space-3xs); min-width: 0; }
|
|
21
|
+
.ws-menu-item__hint { font-size: var(--ws-text-micro); line-height: var(--ws-leading-micro); font-weight: 400; color: var(--color-text-muted); }
|
|
22
|
+
.ws-menu-item:has(.ws-menu-item__hint) { align-items: flex-start; }
|
|
23
|
+
.ws-menu-item:has(.ws-menu-item__hint) > :is(.ws-menu-item__icon, .ws-menu-item__tick) { margin-block: calc((var(--ws-leading-control) - var(--ws-icon)) / 2); }
|
|
24
|
+
/* A choice (menuitemradio, menuitemcheckbox): the tick at the row's end shows only when it is chosen. */
|
|
25
|
+
.ws-menu-item__tick { flex-shrink: 0; width: var(--ws-icon); height: var(--ws-icon); margin-left: auto; color: var(--color-text-heading); visibility: hidden; }
|
|
26
|
+
.ws-menu-item[aria-checked="true"] > .ws-menu-item__tick { visibility: visible; }
|
|
27
|
+
/* The top layer (K9): opened with the native popover attribute it sits above every card, dialog and scroller that would
|
|
28
|
+
cut it. Where the browser places it by anchor, it hangs 8 under its button, right edges flush (left edges once it
|
|
29
|
+
flips to the other side). A tall one keeps hanging there, capped to the room below (8 short of the window's edge)
|
|
30
|
+
and scrolling inside, so it never slides over its button; it flips above only when less than 200 px (or less than
|
|
31
|
+
its own height) fits below. Wider than either side of its button (a phone), it centres in the window under it.
|
|
32
|
+
Without anchor placement, the app places it (Floating UI flip and shift). */
|
|
33
|
+
.ws-menu[popover]:not(:popover-open) { display: none; }
|
|
34
|
+
@supports (position-area: block-end) {
|
|
35
|
+
.ws-menu[popover] { inset: auto; margin: var(--space-xs) 0; position-area: block-end span-inline-start; justify-self: end; position-try-fallbacks: flip-block, flip-inline, flip-block flip-inline, --ws-menu-wide, --ws-menu-wide flip-block; max-height: calc(100% - var(--space-xs) * 2); min-height: calc-size(max-content, min(size, var(--space-9xl))); }
|
|
36
|
+
}
|
|
37
|
+
@position-try --ws-menu-wide { position-area: block-end span-all; justify-self: center; }
|
|
38
|
+
/* Motion (D7, North js@620042: from y -4 and scale .97 on "Messages and steps settle", the settle spring .32 / .1; out
|
|
39
|
+
the same way over .12 s): it grows out of the corner it hangs from, toward its button, and settles on the spring; it
|
|
40
|
+
goes back into that corner faster. --ws-menu-from is the nudge, toward the button: up under it, down over it. An app
|
|
41
|
+
that places it (Floating UI, Radix) says which side with data-side="top"; where the browser places it by anchor, the
|
|
42
|
+
nudge rides on the margin toward the button instead, which the flip fallbacks turn with it (the corner it scales
|
|
43
|
+
from stays the top right there: CSS cannot tell a fallback's side to transform-origin). A native popover enters and
|
|
44
|
+
leaves by transitions (@starting-style, display and overlay allow-discrete), so a close mid-entrance turns back from
|
|
45
|
+
where it is; one the app mounts plays ws-menu-in and, with data-leaving, ws-menu-out before it is removed. */
|
|
46
|
+
.ws-menu { --ws-menu-from: calc(var(--ws-nudge) * -1); }
|
|
47
|
+
.ws-menu[data-side="top"] { --ws-menu-from: var(--ws-nudge); transform-origin: bottom right; }
|
|
48
|
+
@keyframes ws-menu-in { from { opacity: 0; transform: translateY(var(--ws-menu-from)) scale(var(--ws-open-scale)); } }
|
|
49
|
+
@keyframes ws-menu-out { to { opacity: 0; transform: translateY(var(--ws-menu-from)) scale(var(--ws-open-scale)); } }
|
|
50
|
+
@media (prefers-reduced-motion: no-preference) {
|
|
51
|
+
.ws-menu:not([popover]) { animation: ws-menu-in var(--ws-spring-settle-duration) var(--ws-spring-settle) backwards; }
|
|
52
|
+
.ws-menu[data-leaving] { animation: ws-menu-out var(--ws-duration-exit) var(--ws-ease-exit) forwards; pointer-events: none; }
|
|
53
|
+
.ws-menu[popover] { transition: opacity var(--ws-spring-settle-duration) var(--ws-spring-settle), transform var(--ws-spring-settle-duration) var(--ws-spring-settle), margin-block var(--ws-spring-settle-duration) var(--ws-spring-settle), overlay var(--ws-duration-exit) allow-discrete, display var(--ws-duration-exit) allow-discrete; }
|
|
54
|
+
.ws-menu[popover]:not(:popover-open) { opacity: 0; transform: translateY(var(--ws-menu-from)) scale(var(--ws-open-scale)); transition-duration: var(--ws-duration-exit); transition-timing-function: var(--ws-ease-exit); }
|
|
55
|
+
@starting-style { .ws-menu[popover]:popover-open { opacity: 0; transform: translateY(var(--ws-menu-from)) scale(var(--ws-open-scale)); } }
|
|
56
|
+
@supports (position-area: block-end) {
|
|
57
|
+
.ws-menu[popover]:not([data-side]) { --ws-menu-from: 0px; }
|
|
58
|
+
.ws-menu[popover]:not([data-side]):not(:popover-open) { margin-block-start: calc(var(--space-xs) - var(--ws-nudge)); }
|
|
59
|
+
@starting-style { .ws-menu[popover]:not([data-side]):popover-open { margin-block-start: calc(var(--space-xs) - var(--ws-nudge)); } }
|
|
60
|
+
}
|
|
61
|
+
}
|
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
A
|
|
1
|
+
A count on a thin 4 px track: a running job's progress beside its words, or a share in a row with its name above it.
|
|
2
2
|
|
|
3
3
|
**Use it when**
|
|
4
4
|
|
|
5
5
|
- Something is running now and the backend actually counts its parts ("2 of 7"), so the bar is never a guess.
|
|
6
6
|
- A card's one act needs to show it is moving without a full `Stepper` (a mission pill at the foot of the screen, a running card in the chat).
|
|
7
|
+
- A short list of shares, each a row with its name and value above a thin track (Seth's "Seats Felix absorbs").
|
|
7
8
|
|
|
8
9
|
**Not for**
|
|
9
10
|
|
|
@@ -13,8 +14,14 @@ A running job's progress: a thin pill track that fills to the latest count, besi
|
|
|
13
14
|
|
|
14
15
|
**Anatomy**
|
|
15
16
|
|
|
16
|
-
- Track: `--space-xxs`
|
|
17
|
-
- Fill: the same
|
|
17
|
+
- Track: 4 px tall (`--space-xxs`), 2 px corners (Seth), `--ws-track` ground.
|
|
18
|
+
- Fill: the same shape, solid navy (`--color-text-heading`; teal when finished), its width the count's share, growing to a
|
|
19
|
+
new figure inside the fixed track rather than the track itself resizing.
|
|
20
|
+
- `--pill`: the 12 px mission pill, round ends.
|
|
21
|
+
- Rows (`.ws-meter__rows`): each row 8 above and below, 14 at the sides, a 0.5 px divider between rows (none above the first). On its line the name
|
|
22
|
+
(13/18 medium navy, one line, a `title` when it can truncate) and the value 8 after it (12/16 semibold navy, or
|
|
23
|
+
`--quiet` 12/16 medium muted for "none" and "stays"); 4 under it the track; 4 under that an 11/13 muted caption.
|
|
24
|
+
A row with no share has no track.
|
|
18
25
|
- Words beside it: `ws-muted`, tabular numerals ("2 of 7").
|
|
19
26
|
- Above the bar, the running step's own line: its words, a middle dot, and the elapsed clock ("0:42", "12:05", "1:02:05"), in `--color-text-interactive` (mid blue) while it ticks.
|
|
20
27
|
|
|
@@ -26,6 +33,13 @@ A running job's progress: a thin pill track that fills to the latest count, besi
|
|
|
26
33
|
| Without a count | Only the step and its clock show; no bar is drawn, ever, when the backend has not actually counted parts |
|
|
27
34
|
| Finished | The clock stops ticking (no interval), the bar (if any) sits at its final share |
|
|
28
35
|
|
|
36
|
+
**Parts and modifiers**
|
|
37
|
+
|
|
38
|
+
- `.ws-meter__card`: the running card: the step and its clock, then the meter, 4 apart, the card's padding inside.
|
|
39
|
+
- `.ws-meter__step`: the step's words, 14/20 in `--color-text-interactive`, tabular.
|
|
40
|
+
- `.ws-meter__step--done`: a finished step, in muted grey.
|
|
41
|
+
- `.ws-meter__fill--done`: a finished run's fill, in `--color-stat-positive`.
|
|
42
|
+
|
|
29
43
|
**States**
|
|
30
44
|
|
|
31
45
|
- Running: the clock ticks once a second from when the job started; the bar's width follows each new count.
|
|
@@ -38,7 +52,7 @@ A running job's progress: a thin pill track that fills to the latest count, besi
|
|
|
38
52
|
**Behaviour**
|
|
39
53
|
|
|
40
54
|
- Decorative to a screen reader (the bar carries no `aria-*` of its own); the words beside it ("2 of 7") and the step's own text are what a screen reader reads.
|
|
41
|
-
- Motion: the fill's width
|
|
55
|
+
- Motion: the fill's width moves over 700 ms on the settle curve (`--ws-duration-fill`, `--ws-ease-settle`) as each new count arrives; the clock re-renders its text once a second while running, brought up to date at once when the run started before the page caught up.
|
|
42
56
|
- No pointer or keyboard behaviour.
|
|
43
57
|
|
|
44
58
|
**Content**
|
|
@@ -62,6 +76,27 @@ A running job's progress: a thin pill track that fills to the latest count, besi
|
|
|
62
76
|
|
|
63
77
|
**Source**
|
|
64
78
|
|
|
79
|
+
- **Seth**: the 4 px track with 2 px corners and the seat rows, Tally report (319:3426 to 319:3432). His seat fill is
|
|
80
|
+
#2C4870 (agent/tally), the fill's `--ws-agent-tally` (the act itself in dark).
|
|
65
81
|
- **Derived from**: the system's fixed-track fill rule, "a card's progress meter: its bar grows to the new figure
|
|
66
82
|
inside a fixed track," and the no-invented-count rule.
|
|
67
83
|
- **Precedent**: the first product built on the system.
|
|
84
|
+
|
|
85
|
+
**Markup**
|
|
86
|
+
|
|
87
|
+
```html
|
|
88
|
+
<span class="ws-meter" aria-hidden="true">
|
|
89
|
+
<span class="ws-meter__track"><span class="ws-meter__fill" style="width: 28.6%;"></span></span>
|
|
90
|
+
<span class="ws-meter__words">2 of 7</span>
|
|
91
|
+
</span>
|
|
92
|
+
|
|
93
|
+
<ul class="ws-meter__rows" aria-label="Seats Felix absorbs">
|
|
94
|
+
<li class="ws-meter__row">
|
|
95
|
+
<span class="ws-meter__line"><span class="ws-meter__name">ISAs</span><span class="ws-meter__value">50%</span></span>
|
|
96
|
+
<span class="ws-meter__track" aria-hidden="true"><span class="ws-meter__fill" style="width: 50%;"></span></span>
|
|
97
|
+
<span class="ws-meter__caption">4, typical for your team</span>
|
|
98
|
+
</li>
|
|
99
|
+
</ul>
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
**Styles**: `Meter/style.css`, in `bundle.css` and `fello.css` as `.ws-meter`. Every value is a token.
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
<!-- @dsCard group="Progress" height=
|
|
1
|
+
<!-- @dsCard group="Progress" height=420 -->
|
|
2
2
|
<!doctype html>
|
|
3
3
|
<html>
|
|
4
4
|
<head>
|
|
@@ -55,6 +55,23 @@
|
|
|
55
55
|
</div>
|
|
56
56
|
</div>
|
|
57
57
|
|
|
58
|
+
<div class="ws-stack" style="width: 340px; max-width: 100%;">
|
|
59
|
+
<span class="ws-muted">Rows: a seat's share on the 4 px track, its caption under it, 0.5 px dividers</span>
|
|
60
|
+
<ul class="ws-meter__rows" aria-label="Seats Felix absorbs">
|
|
61
|
+
<li class="ws-meter__row">
|
|
62
|
+
<span class="ws-meter__line"><span class="ws-meter__name">ISAs</span><span class="ws-meter__value">50%</span></span>
|
|
63
|
+
<span class="ws-meter__track" aria-hidden="true"><span class="ws-meter__fill" style="width: 50%;"></span></span>
|
|
64
|
+
<span class="ws-meter__caption">4, typical for your team</span>
|
|
65
|
+
</li>
|
|
66
|
+
<li class="ws-meter__row">
|
|
67
|
+
<span class="ws-meter__line"><span class="ws-meter__name">Marketing managers</span><span class="ws-meter__value ws-meter__value--quiet">none, typical</span></span>
|
|
68
|
+
</li>
|
|
69
|
+
<li class="ws-meter__row">
|
|
70
|
+
<span class="ws-meter__line"><span class="ws-meter__name" title="Transaction coordinators and closing assistants">Transaction coordinators and closing assistants</span><span class="ws-meter__value ws-meter__value--quiet">stays</span></span>
|
|
71
|
+
</li>
|
|
72
|
+
</ul>
|
|
73
|
+
</div>
|
|
74
|
+
|
|
58
75
|
</div>
|
|
59
76
|
</body>
|
|
60
77
|
</html>
|