@ids-group-ltd/ids-design-system 0.2.1 → 0.3.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/package.json CHANGED
@@ -1,12 +1,8 @@
1
1
  {
2
2
  "name": "@ids-group-ltd/ids-design-system",
3
- "version": "0.2.1",
3
+ "version": "0.3.0",
4
4
  "description": "IDS Group Angular design system: components, tokens, themes",
5
5
  "license": "MIT",
6
- "repository": {
7
- "type": "git",
8
- "url": "git+https://bitbucket.org/itband/ids-design-system.git"
9
- },
10
6
  "homepage": "https://ids-ds.proto.ids-group.co.uk/",
11
7
  "keywords": [
12
8
  "angular",
@@ -43,5 +39,6 @@
43
39
  "sideEffects": false,
44
40
  "module": "fesm2022/ids-group-ltd-ids-design-system.mjs",
45
41
  "typings": "types/ids-group-ltd-ids-design-system.d.ts",
46
- "type": "module"
47
- }
42
+ "type": "module",
43
+ "schematics": "./schematics/collection.json"
44
+ }
@@ -0,0 +1,10 @@
1
+ {
2
+ "$schema": "../node_modules/@angular-devkit/schematics/collection-schema.json",
3
+ "schematics": {
4
+ "ng-add": {
5
+ "description": "Wire the IDS design system's global styles into a project.",
6
+ "factory": "./ng-add/index#ngAdd",
7
+ "schema": "./ng-add/schema.json"
8
+ }
9
+ }
10
+ }
@@ -0,0 +1,47 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ngAdd = ngAdd;
4
+ const DS_IMPORT = "@use '@ids-group-ltd/ids-design-system/styles/ds';";
5
+ /**
6
+ * `ng add @ids-group-ltd/ids-design-system` — wires the design system's global
7
+ * styles (palette + theme + tokens + globals) into the target project's styles
8
+ * entry. Idempotent. Components are standalone — import them directly where used.
9
+ */
10
+ function ngAdd(options) {
11
+ return (tree, context) => {
12
+ const angularJson = tree.read('angular.json');
13
+ if (!angularJson) {
14
+ context.logger.warn('ng-add: angular.json not found — skipping styles wiring.');
15
+ return tree;
16
+ }
17
+ const workspace = JSON.parse(angularJson.toString());
18
+ const projects = workspace.projects ?? {};
19
+ const projectName = options.project ??
20
+ workspace.defaultProject ??
21
+ Object.keys(projects).find((name) => projects[name].projectType === 'application');
22
+ const stylesEntry = projectName
23
+ ? findStylesFile(projects[projectName])
24
+ : undefined;
25
+ if (!stylesEntry || !tree.exists(stylesEntry)) {
26
+ context.logger.info(`ng-add: add \`${DS_IMPORT}\` to your global styles file manually.`);
27
+ return tree;
28
+ }
29
+ const current = tree.read(stylesEntry).toString();
30
+ if (current.includes(DS_IMPORT)) {
31
+ context.logger.info('ng-add: design system already imported — nothing to do.');
32
+ return tree;
33
+ }
34
+ tree.overwrite(stylesEntry, `${DS_IMPORT}\n${current}`);
35
+ context.logger.info(`ng-add: imported the design system into ${stylesEntry}.`);
36
+ return tree;
37
+ };
38
+ }
39
+ function findStylesFile(project) {
40
+ const styles = project?.architect?.build?.options?.styles;
41
+ if (!styles?.length) {
42
+ return undefined;
43
+ }
44
+ const first = styles[0];
45
+ const path = typeof first === 'string' ? first : first.input;
46
+ return path && /\.s?css$/.test(path) ? path : undefined;
47
+ }
@@ -0,0 +1,13 @@
1
+ {
2
+ "$schema": "http://json-schema.org/schema",
3
+ "$id": "IdsNgAdd",
4
+ "title": "IDS ng-add Options",
5
+ "type": "object",
6
+ "properties": {
7
+ "project": {
8
+ "type": "string",
9
+ "description": "Project to wire the design system into (defaults to the workspace default / first application)."
10
+ }
11
+ },
12
+ "required": []
13
+ }
@@ -39,7 +39,7 @@
39
39
  .optgroup-label {
40
40
  display: block;
41
41
  padding: var(--space-2) var(--space-3) var(--space-1);
42
- font: var(--font-weight-semibold) var(--font-size-xs)/var(--line-height-flat) var(--font-sans);
42
+ font: var(--font-weight-semibold) var(--font-size-xs) / var(--line-height-flat) var(--font-sans);
43
43
  color: var(--text-tertiary);
44
44
  text-transform: uppercase;
45
45
  letter-spacing: var(--letter-spacing-wide);
@@ -67,7 +67,7 @@
67
67
  padding: var(--space-2) var(--space-2-5);
68
68
  border: 0;
69
69
  background: transparent;
70
- font: var(--font-weight-medium) var(--font-size-s)/var(--line-height-flat) var(--font-sans);
70
+ font: var(--font-weight-medium) var(--font-size-s) / var(--line-height-flat) var(--font-sans);
71
71
  color: var(--text-primary);
72
72
  cursor: pointer;
73
73
  border-radius: var(--radius-sm);
@@ -98,7 +98,7 @@
98
98
 
99
99
  &:focus-visible {
100
100
  outline: none;
101
- box-shadow: var(--focus-ring);
101
+ box-shadow: var(--ds-control-focus-shadow);
102
102
  }
103
103
 
104
104
  &.is-selected {
@@ -1,35 +1,39 @@
1
1
  // Self-hosted DS default fonts (latin subset). Consumers override --font-sans / --font-mono to swap.
2
2
 
3
3
  @font-face {
4
- font-family: 'Mulish';
4
+ font-family: Mulish;
5
5
  font-style: normal;
6
6
  font-weight: 400;
7
7
  font-display: swap;
8
8
  src: url('./fonts/mulish-latin-400-normal.woff2') format('woff2');
9
9
  }
10
+
10
11
  @font-face {
11
- font-family: 'Mulish';
12
+ font-family: Mulish;
12
13
  font-style: normal;
13
14
  font-weight: 500;
14
15
  font-display: swap;
15
16
  src: url('./fonts/mulish-latin-500-normal.woff2') format('woff2');
16
17
  }
18
+
17
19
  @font-face {
18
- font-family: 'Mulish';
20
+ font-family: Mulish;
19
21
  font-style: normal;
20
22
  font-weight: 600;
21
23
  font-display: swap;
22
24
  src: url('./fonts/mulish-latin-600-normal.woff2') format('woff2');
23
25
  }
26
+
24
27
  @font-face {
25
- font-family: 'Mulish';
28
+ font-family: Mulish;
26
29
  font-style: normal;
27
30
  font-weight: 700;
28
31
  font-display: swap;
29
32
  src: url('./fonts/mulish-latin-700-normal.woff2') format('woff2');
30
33
  }
34
+
31
35
  @font-face {
32
- font-family: 'Mulish';
36
+ font-family: Mulish;
33
37
  font-style: normal;
34
38
  font-weight: 800;
35
39
  font-display: swap;
@@ -43,6 +47,7 @@
43
47
  font-display: swap;
44
48
  src: url('./fonts/jetbrains-mono-latin-400-normal.woff2') format('woff2');
45
49
  }
50
+
46
51
  @font-face {
47
52
  font-family: 'JetBrains Mono';
48
53
  font-style: normal;
@@ -50,6 +55,7 @@
50
55
  font-display: swap;
51
56
  src: url('./fonts/jetbrains-mono-latin-500-normal.woff2') format('woff2');
52
57
  }
58
+
53
59
  @font-face {
54
60
  font-family: 'JetBrains Mono';
55
61
  font-style: normal;
@@ -5,10 +5,10 @@
5
5
  .grid-3 { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--space-4); }
6
6
  .grid-4 { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: var(--space-4); }
7
7
 
8
- @media (max-width: 1100px) {
8
+ @media (width <= 1100px) {
9
9
  .grid-4 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
10
10
  }
11
11
 
12
- @media (max-width: 820px) {
12
+ @media (width <= 820px) {
13
13
  .grid-3, .grid-4 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
14
14
  }
package/styles/_link.scss CHANGED
@@ -30,7 +30,7 @@
30
30
 
31
31
  &:focus-visible {
32
32
  outline: none;
33
- box-shadow: var(--focus-ring);
33
+ box-shadow: var(--ds-control-focus-shadow);
34
34
  border-radius: var(--radius-sm);
35
35
  text-decoration-color: var(--_link-color);
36
36
  }
@@ -43,12 +43,13 @@
43
43
  }
44
44
 
45
45
  .icon {
46
- color: currentColor;
46
+ color: currentcolor;
47
47
  flex-shrink: 0;
48
48
  }
49
49
 
50
50
  &.quiet {
51
51
  color: var(--text-secondary);
52
+
52
53
  /* Pull the underline down to match the muted text — the base rule sets
53
54
  text-decoration-color to the link color, which would leave a bright
54
55
  underline under grey text at rest. */
@@ -27,24 +27,27 @@
27
27
  // Mobile (default, <= 640px) — 4 columns
28
28
  --page-gutter: var(--page-gutter-mobile);
29
29
  --page-margin: var(--page-margin-mobile);
30
+
30
31
  grid-template-columns: repeat(4, minmax(0, 1fr));
31
32
 
32
33
  // Tablet (641-1024px) — 8 columns
33
- @media (min-width: 641px) {
34
+ @media (width >= 641px) {
34
35
  --page-gutter: var(--page-gutter-tablet);
35
36
  --page-margin: var(--page-margin-tablet);
37
+
36
38
  grid-template-columns: repeat(8, minmax(0, 1fr));
37
39
  }
38
40
 
39
41
  // Desktop (1025-1440px) — 12 columns, fluid width
40
- @media (min-width: 1025px) {
42
+ @media (width >= 1025px) {
41
43
  --page-gutter: var(--page-gutter-desktop);
42
44
  --page-margin: var(--page-margin-desktop);
45
+
43
46
  grid-template-columns: repeat(12, minmax(0, 1fr));
44
47
  }
45
48
 
46
49
  // Desktop wide (>= 1441px) — 12 columns, container capped at --col-cap-content
47
- @media (min-width: 1441px) {
50
+ @media (width >= 1441px) {
48
51
  --page-gutter: var(--page-gutter-wide);
49
52
  --page-margin: var(--page-margin-wide);
50
53
  }
@@ -1,13 +1,18 @@
1
1
  // Reset — ported from CLAUDE_DESIGN_DS/tokens.css §Base.
2
2
 
3
3
  *, *::before, *::after { box-sizing: border-box; }
4
+
5
+ /* Opt into animating to/from intrinsic sizes (height: auto, max-content).
6
+ Inherited, so components can transition height:0 ↔ auto natively
7
+ (accordion, sidenav group) without max-height magic numbers. */
8
+ :root { interpolate-size: allow-keywords; }
4
9
  html, body {
5
10
  margin: 0;
6
11
  font-family: var(--font-sans);
7
12
  color: var(--text-primary);
8
13
  background: var(--surface-canvas);
9
14
  -webkit-font-smoothing: antialiased;
10
- text-rendering: optimizeLegibility;
15
+ text-rendering: optimizelegibility;
11
16
  }
12
17
  button, input, select, textarea { font-family: inherit; }
13
18
 
@@ -14,4 +14,4 @@ html { scrollbar-width: thin; scrollbar-color: var(--scrollbar-thumb) transparen
14
14
  *::-webkit-scrollbar-thumb:active { background: var(--scrollbar-thumb-active); background-clip: padding-box; }
15
15
 
16
16
  // Global text-selection — sourced from components-extras.css line 910.
17
- ::selection { background: var(--select-bg, color-mix(in srgb, var(--primary) 22%, transparent)); color: var(--text-primary); }
17
+ ::selection { background-color: var(--select-bg-color, color-mix(in srgb, var(--primary) 22%, transparent)); color: var(--text-primary); }
@@ -15,14 +15,14 @@
15
15
 
16
16
  :root {
17
17
  /* CATEGORICAL (8) ----------------------------------------- */
18
- --chart-cat-1: hsl(229, 100%, 59%); /* blue (primary) */
19
- --chart-cat-2: hsl(165, 72%, 38%); /* teal */
20
- --chart-cat-3: hsl( 24, 95%, 55%); /* orange */
21
- --chart-cat-4: hsl(330, 82%, 55%); /* magenta */
22
- --chart-cat-5: hsl(45, 95%, 50%); /* amber */
23
- --chart-cat-6: hsl(190, 85%, 45%); /* cyan */
24
- --chart-cat-7: hsl(280, 60%, 60%); /* lavender */
25
- --chart-cat-8: hsl(130, 45%, 50%); /* moss */
18
+ --chart-cat-1: hsl(229deg 100% 59%); /* blue (primary) */
19
+ --chart-cat-2: hsl(165deg 72% 38%); /* teal */
20
+ --chart-cat-3: hsl( 24deg 95% 55%); /* orange */
21
+ --chart-cat-4: hsl(330deg 82% 55%); /* magenta */
22
+ --chart-cat-5: hsl(45deg 95% 50%); /* amber */
23
+ --chart-cat-6: hsl(190deg 85% 45%); /* cyan */
24
+ --chart-cat-7: hsl(280deg 60% 60%); /* lavender */
25
+ --chart-cat-8: hsl(130deg 45% 50%); /* moss */
26
26
 
27
27
  /* SEQUENTIAL — single-hue, light → dark */
28
28
  --chart-seq-1: var(--blue-100);
@@ -38,13 +38,13 @@
38
38
  matches the reference one-for-one. Explicit HSL keeps the ramp
39
39
  independent of palette retunes — re-skinning brand/red/green
40
40
  should not shift the dataviz colour story. */
41
- --chart-div--3: hsl(0 70% 40%); /* large negative (worst) */
42
- --chart-div--2: hsl(0 60% 58%);
43
- --chart-div--1: hsl(0 50% 80%);
44
- --chart-div-0: hsl(225 8% 92%); /* zero */
45
- --chart-div-1: hsl(140 35% 80%);
46
- --chart-div-2: hsl(140 45% 55%);
47
- --chart-div-3: hsl(140 55% 35%); /* large positive (best) */
41
+ --chart-div--3: hsl(0deg 70% 40%); /* large negative (worst) */
42
+ --chart-div--2: hsl(0deg 60% 58%);
43
+ --chart-div--1: hsl(0deg 50% 80%);
44
+ --chart-div-0: hsl(225deg 8% 92%); /* zero */
45
+ --chart-div-1: hsl(140deg 35% 80%);
46
+ --chart-div-2: hsl(140deg 45% 55%);
47
+ --chart-div-3: hsl(140deg 55% 35%); /* large positive (best) */
48
48
 
49
49
  /* AXIS / GRID / LEGEND */
50
50
  --chart-axis-line: var(--neutral-300);
@@ -56,10 +56,10 @@
56
56
  --chart-axis-fs: var(--font-size-2xs);
57
57
 
58
58
  /* HIGHLIGHT / HOVER */
59
- --chart-hover-bg: hsla(225, 39%, 7%, .04);
59
+ --chart-hover-bg-color: hsl(225deg 39% 7% / 4%);
60
60
  --chart-cursor-line: var(--neutral-400);
61
- --chart-tooltip-bg: var(--neutral-900);
62
- --chart-tooltip-fg: var(--neutral-0);
61
+ --chart-tooltip-bg-color: var(--neutral-900);
62
+ --chart-tooltip-text-color: var(--neutral-0);
63
63
  --chart-tooltip-border: var(--neutral-700);
64
64
 
65
65
  /* DIMENSIONS */
@@ -84,17 +84,18 @@
84
84
  The alpha values stay constant across themes — only the
85
85
  hue/saturation/lightness become configurable.
86
86
  ============================================================ */
87
+
87
88
  /* --shadow-tint-h/s/l live in themes/default/_palette.scss — palette-level
88
89
  so dark palettes can override --shadow-tint-l → ~95% for soft light glows. */
89
90
 
90
- --shadow-1: 0 1px 2px hsla(var(--shadow-tint-h), var(--shadow-tint-s), var(--shadow-tint-l), .06),
91
- 0 1px 3px hsla(var(--shadow-tint-h), var(--shadow-tint-s), var(--shadow-tint-l), .08);
92
- --shadow-2: 0 4px 8px hsla(var(--shadow-tint-h), var(--shadow-tint-s), var(--shadow-tint-l), .06),
93
- 0 4px 16px hsla(var(--shadow-tint-h), var(--shadow-tint-s), var(--shadow-tint-l), .10);
94
- --shadow-3: 0 8px 16px hsla(var(--shadow-tint-h), var(--shadow-tint-s), var(--shadow-tint-l), .08),
95
- 0 16px 32px hsla(var(--shadow-tint-h), var(--shadow-tint-s), var(--shadow-tint-l), .14);
96
- --shadow-4: 0 16px 32px hsla(var(--shadow-tint-h), var(--shadow-tint-s), var(--shadow-tint-l), .12),
97
- 0 24px 48px hsla(var(--shadow-tint-h), var(--shadow-tint-s), var(--shadow-tint-l), .18);
91
+ --shadow-1: 0 1px 2px hsl(var(--shadow-tint-h) var(--shadow-tint-s) var(--shadow-tint-l) / 6%),
92
+ 0 1px 3px hsl(var(--shadow-tint-h) var(--shadow-tint-s) var(--shadow-tint-l) / 8%);
93
+ --shadow-2: 0 4px 8px hsl(var(--shadow-tint-h) var(--shadow-tint-s) var(--shadow-tint-l) / 6%),
94
+ 0 4px 16px hsl(var(--shadow-tint-h) var(--shadow-tint-s) var(--shadow-tint-l) / 10%);
95
+ --shadow-3: 0 8px 16px hsl(var(--shadow-tint-h) var(--shadow-tint-s) var(--shadow-tint-l) / 8%),
96
+ 0 16px 32px hsl(var(--shadow-tint-h) var(--shadow-tint-s) var(--shadow-tint-l) / 14%);
97
+ --shadow-4: 0 16px 32px hsl(var(--shadow-tint-h) var(--shadow-tint-s) var(--shadow-tint-l) / 12%),
98
+ 0 24px 48px hsl(var(--shadow-tint-h) var(--shadow-tint-s) var(--shadow-tint-l) / 18%);
98
99
  --shadow-popover: var(--shadow-2);
99
100
  --shadow-modal: var(--shadow-4);
100
101
  --shadow-toast: var(--shadow-3);
@@ -169,6 +170,7 @@
169
170
  --opacity-scrim: 0.55; /* modal/drawer backdrop overlay (light theme) */
170
171
  --opacity-state-hover: 0.08; /* hover layer over surface (overlay vs surface swap) */
171
172
  --opacity-state-pressed: 0.16; /* active/pressed layer */
173
+ --opacity-state-active: 0.24; /* deepest pressed layer (e.g. tag close on :active) */
172
174
 
173
175
  /* ============================================================
174
176
  Breakpoints
@@ -202,7 +204,7 @@
202
204
  --scrollbar-thumb: var(--neutral-300);
203
205
  --scrollbar-thumb-hover: var(--neutral-400);
204
206
  --scrollbar-thumb-active: var(--neutral-500);
205
- --select-bg: color-mix(in srgb, var(--primary) 22%, transparent);
207
+ --select-bg-color: color-mix(in srgb, var(--primary) 22%, transparent);
206
208
  --col-cap-text: 720px;
207
209
  --col-cap-content: 1280px;
208
210
 
@@ -282,6 +284,15 @@
282
284
  default their own --ds-*-pad to this, so a consumer retunes all at once. */
283
285
  --ds-container-pad: var(--space-6);
284
286
 
287
+ /* Shared focus indicators — components default their own --ds-*-focus-shadow
288
+ to these, so a consumer retunes focus per-group at once (field vs control)
289
+ or per-component. Two families: fields get the soft halo, interactive
290
+ controls/nav get the crisp ring (see themes/default/_theme.scss). */
291
+ --ds-field-focus-shadow: var(--focus-field);
292
+ --ds-field-focus-shadow-error: var(--focus-field-error);
293
+ --ds-control-focus-shadow: var(--focus-ring);
294
+ --ds-control-focus-shadow-error: var(--focus-ring-error);
295
+
285
296
  /* Table cell padding — density-aware, consumed by .tbl td/th. */
286
297
  --table-cell-pad-x: var(--space-4);
287
298
  --table-cell-pad-y: var(--space-3);
@@ -597,6 +608,7 @@
597
608
  }
598
609
  [data-density="cozy"] {
599
610
  --hit-cozy: 40px;
611
+
600
612
  /* defaults */
601
613
  }
602
614
  [data-density="comfy"] {
@@ -1,30 +1,31 @@
1
1
  // Type utility classes — ported from CLAUDE_DESIGN_DS/tokens.css §Type utilities.
2
2
  // These are GLOBAL by design — consumers apply them via class.
3
3
 
4
- .t-display { font: var(--font-weight-extrabold) var(--font-size-display)/var(--line-height-tight) var(--font-display); letter-spacing: var(--letter-spacing-tight); }
5
- .t-h1 { font: var(--font-weight-extrabold) var(--font-size-h1)/var(--line-height-tight) var(--font-heading); letter-spacing: var(--letter-spacing-tight); }
6
- .t-h2 { font: var(--font-weight-extrabold) var(--font-size-h2)/var(--line-height-snug) var(--font-heading); letter-spacing: var(--letter-spacing-snug); }
7
- .t-h3 { font: var(--font-weight-extrabold) var(--font-size-h3)/var(--line-height-snug) var(--font-heading); letter-spacing: var(--letter-spacing-snug); }
8
- .t-h4 { font: var(--font-weight-bold) var(--font-size-h4)/var(--line-height-snug) var(--font-heading); }
9
- .t-h5 { font: var(--font-weight-bold) var(--font-size-h5)/var(--line-height-snug) var(--font-heading); }
10
- .t-card-title { font: var(--font-weight-bold) var(--card-title-fs)/var(--line-height-snug) var(--font-heading); margin: 0; color: var(--text-primary); }
11
- .t-l { font: var(--font-weight-regular) var(--font-size-l)/var(--line-height-base) var(--font-sans); }
12
- .t-l-bold { font: var(--font-weight-bold) var(--font-size-l)/var(--line-height-base) var(--font-sans); }
13
- .t-m { font: var(--font-weight-regular) var(--font-size-m)/var(--line-height-base) var(--font-sans); }
14
- .t-m-bold { font: var(--font-weight-bold) var(--font-size-m)/var(--line-height-base) var(--font-sans); }
15
- .t-s { font: var(--font-weight-regular) var(--font-size-s)/var(--line-height-base) var(--font-sans); }
16
- .t-s-bold { font: var(--font-weight-bold) var(--font-size-s)/var(--line-height-base) var(--font-sans); }
17
- .t-xs { font: var(--font-weight-regular) var(--font-size-xs)/var(--line-height-base) var(--font-sans); }
18
- .t-xs-bold { font: var(--font-weight-bold) var(--font-size-xs)/var(--line-height-base) var(--font-sans); }
19
- .t-overline { font: var(--font-weight-bold) var(--font-size-2xs)/var(--line-height-base) var(--font-sans); letter-spacing: var(--letter-spacing-wider); text-transform: uppercase; color: var(--text-tertiary); }
20
- .t-caption { font: var(--font-weight-regular) var(--font-size-xs)/var(--line-height-base) var(--font-sans); color: var(--text-tertiary); }
21
- .t-mono { font: var(--font-weight-medium) var(--font-size-mono)/var(--line-height-base) var(--font-mono); }
22
- .t-mono-block { font: var(--font-weight-regular) var(--font-size-mono)/var(--line-height-loose) var(--font-mono); background: var(--surface-secondary); border: var(--border-width-default) solid var(--border-divider); border-radius: var(--radius-md); padding: var(--space-3) var(--space-4); }
4
+ .t-display { font: var(--font-weight-extrabold) var(--font-size-display) / var(--line-height-tight) var(--font-display); letter-spacing: var(--letter-spacing-tight); }
5
+ .t-h1 { font: var(--font-weight-extrabold) var(--font-size-h1) / var(--line-height-tight) var(--font-heading); letter-spacing: var(--letter-spacing-tight); }
6
+ .t-h2 { font: var(--font-weight-extrabold) var(--font-size-h2) / var(--line-height-snug) var(--font-heading); letter-spacing: var(--letter-spacing-snug); }
7
+ .t-h3 { font: var(--font-weight-extrabold) var(--font-size-h3) / var(--line-height-snug) var(--font-heading); letter-spacing: var(--letter-spacing-snug); }
8
+ .t-h4 { font: var(--font-weight-bold) var(--font-size-h4) / var(--line-height-snug) var(--font-heading); }
9
+ .t-h5 { font: var(--font-weight-bold) var(--font-size-h5) / var(--line-height-snug) var(--font-heading); }
10
+ .t-card-title { font: var(--font-weight-bold) var(--card-title-fs) / var(--line-height-snug) var(--font-heading); margin: 0; color: var(--text-primary); }
11
+ .t-l { font: var(--font-weight-regular) var(--font-size-l) / var(--line-height-base) var(--font-sans); }
12
+ .t-l-bold { font: var(--font-weight-bold) var(--font-size-l) / var(--line-height-base) var(--font-sans); }
13
+ .t-m { font: var(--font-weight-regular) var(--font-size-m) / var(--line-height-base) var(--font-sans); }
14
+ .t-m-bold { font: var(--font-weight-bold) var(--font-size-m) / var(--line-height-base) var(--font-sans); }
15
+ .t-s { font: var(--font-weight-regular) var(--font-size-s) / var(--line-height-base) var(--font-sans); }
16
+ .t-s-bold { font: var(--font-weight-bold) var(--font-size-s) / var(--line-height-base) var(--font-sans); }
17
+ .t-xs { font: var(--font-weight-regular) var(--font-size-xs) / var(--line-height-base) var(--font-sans); }
18
+ .t-xs-bold { font: var(--font-weight-bold) var(--font-size-xs) / var(--line-height-base) var(--font-sans); }
19
+ .t-overline { font: var(--font-weight-bold) var(--font-size-2xs) / var(--line-height-base) var(--font-sans); letter-spacing: var(--letter-spacing-wider); text-transform: uppercase; color: var(--text-tertiary); }
20
+ .t-caption { font: var(--font-weight-regular) var(--font-size-xs) / var(--line-height-base) var(--font-sans); color: var(--text-tertiary); }
21
+ .t-mono { font: var(--font-weight-medium) var(--font-size-mono) / var(--line-height-base) var(--font-mono); }
22
+ .t-mono-inline { font: var(--font-weight-regular) var(--font-size-mono) / 1 var(--font-mono); background: var(--surface-secondary); color: var(--text-primary); padding: 1px var(--space-1); border-radius: var(--radius-sm); }
23
+ .t-mono-block { font: var(--font-weight-regular) var(--font-size-mono) / var(--line-height-loose) var(--font-mono); background: var(--surface-secondary); border: var(--border-width-default) solid var(--border-divider); border-radius: var(--radius-md); padding: var(--space-3) var(--space-4); }
23
24
 
24
25
  .sr-only {
25
26
  position: absolute !important;
26
27
  width: 1px; height: 1px;
27
28
  padding: 0; margin: -1px;
28
- overflow: hidden; clip: rect(0,0,0,0);
29
+ overflow: hidden; clip-path: inset(50%);
29
30
  white-space: nowrap; border: 0;
30
31
  }
package/themes/README.md CHANGED
@@ -4,15 +4,15 @@ Colour lives in two files here: a **palette** (defines the concrete colours) and
4
4
 
5
5
  ## Architecture: three tiers
6
6
 
7
- | Tier | Lives in | Examples | Consumers |
8
- |---|---|---|---|
9
- | **Tier 1 — Palette** (defines colours) | `themes/<name>/_palette.scss` | `--blue-600`, `--cool-gray-0`, `--brand-gray-500`, `--red-500`, `--blue-h/s/l`, `--shadow-tint-h/s/l` | Only the theme file |
10
- | **Tier 2 — Theme** (sets roles) | `themes/<name>/_theme.scss` | `--primary: var(--blue-600)`, `--text-primary`, `--surface-default`, `--success`, `--focus-ring`, `--primary-h: var(--blue-h)`, font families; the `--neutral-*` family slot (cool-gray by default, brand-gray via `[data-neutrals="brand"]`) | Components |
11
- | **Tier 3 — Component / scale** | `styles/_tokens.scss` and inside `*.component.scss` | `--space-*`, `--radius-*`, `--ds-button-bg`, `--duration-fast`, `--layer-modal` | Components (their own) |
7
+ | Tier | Lives in | Examples | Consumers |
8
+ | -------------------------------------- | --------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------- |
9
+ | **Tier 1 — Palette** (defines colours) | `themes/<name>/_palette.scss` | `--blue-600`, `--cool-gray-0`, `--brand-gray-500`, `--red-500`, `--blue-h/s/l`, `--shadow-tint-h/s/l` | Only the theme file |
10
+ | **Tier 2 — Theme** (sets roles) | `themes/<name>/_theme.scss` | `--primary: var(--blue-600)`, `--text-primary`, `--surface-default`, `--success`, `--focus-ring`, `--primary-h: var(--blue-h)`, font families; the `--neutral-*` family slot (cool-gray by default, brand-gray via `[data-neutrals="brand"]`) | Components |
11
+ | **Tier 3 — Component / scale** | `styles/_tokens.scss` and inside `*.component.scss` | `--space-*`, `--radius-*`, `--ds-button-bg-color`, `--duration-fast`, `--layer-modal` | Components (their own) |
12
12
 
13
13
  **Hard rule:** components NEVER consume Tier 1 palette directly. If you write `var(--blue-600)` inside `button.component.scss`, that's a bug — introduce or reuse a Tier 2 role.
14
14
 
15
- **Why split palette from theme:** the palette says *what colours exist*; the theme says *what each role is*. A dark theme ships a different palette (different ramp values) + a theme map that re-points roles. Swapping either re-skins the system without touching components.
15
+ **Why split palette from theme:** the palette says _what colours exist_; the theme says _what each role is_. A dark theme ships a different palette (different ramp values) + a theme map that re-points roles. Swapping either re-skins the system without touching components.
16
16
 
17
17
  ## Available palette + theme
18
18
 
@@ -20,6 +20,7 @@ Colour lives in two files here: a **palette** (defines the concrete colours) and
20
20
  - **`default/_theme.scss`** — Light role map onto the default palette. Both are bundled into `styles/ds.scss` (palette → theme → tokens) so `@use 'styles/ds';` works out of the box.
21
21
 
22
22
  Future (each a `themes/<name>/` folder with `_palette.scss` + `_theme.scss`):
23
+
23
24
  - `themes/dark/` — Dark-mode flip (`--shadow-tint-l` → ~95%, neutrals inverted, etc.).
24
25
  - `themes/high-contrast/` — A11y boost.
25
26
 
@@ -29,15 +30,15 @@ Future (each a `themes/<name>/` folder with `_palette.scss` + `_theme.scss`):
29
30
 
30
31
  ```scss
31
32
  // Consumer styles.scss
32
- @use 'styles/ds'; // bundles default palette + theme + tokens + reset + ...
33
+ @use 'styles/ds'; // bundles default palette + theme + tokens + reset + ...
33
34
  ```
34
35
 
35
36
  ### Option B — explicit theme choice
36
37
 
37
38
  ```scss
38
39
  // Consumer styles.scss
39
- @use 'themes/dark/palette'; // pick a non-default theme: palette …
40
- @use 'themes/dark/theme'; // … then its role map
40
+ @use 'themes/dark/palette'; // pick a non-default theme: palette …
41
+ @use 'themes/dark/theme'; // … then its role map
41
42
  @use 'styles/tokens';
42
43
  @use 'styles/reset';
43
44
  @use 'styles/typography';
@@ -52,8 +53,8 @@ Palette + theme must come BEFORE `tokens` so role aliases resolve.
52
53
 
53
54
  ```scss
54
55
  // Consumer styles.scss
55
- @use 'styles/ds'; // default theme + DS
56
- @use './app/styles/brand-manage-my'; // overrides palette/roles via [data-brand]
56
+ @use 'styles/ds'; // default theme + DS
57
+ @use './app/styles/brand-manage-my'; // overrides palette/roles via [data-brand]
57
58
  ```
58
59
 
59
60
  This is the mm-broker pattern: load DS (default theme included), then overlay a brand at a more-specific selector (`[data-brand="manage-my"]`).
@@ -22,7 +22,7 @@
22
22
  // 210 → 227 toward the brand hue (229) as it darkens; chroma follows a
23
23
  // designed U-curve (S 40% → 12% → 37%). Appearance name, Carbon-style.
24
24
  // -----------------------------------------------------------------------
25
- --cool-gray-0: #FFFFFF;
25
+ --cool-gray-0: #FFF;
26
26
  --cool-gray-50: #F8FAFC;
27
27
  --cool-gray-100: #F1F4F9;
28
28
  --cool-gray-150: #E8ECF2;
@@ -44,19 +44,19 @@
44
44
  // cool-gray to within rounding.
45
45
  // -----------------------------------------------------------------------
46
46
  --neutral-h: var(--primary-h, var(--blue-h));
47
- --brand-gray-0: #FFFFFF;
48
- --brand-gray-50: hsl(calc(var(--neutral-h) - 19), 40.0%, 98.0%);
49
- --brand-gray-100: hsl(calc(var(--neutral-h) - 12), 40.0%, 96.1%);
50
- --brand-gray-150: hsl(calc(var(--neutral-h) - 13), 27.8%, 92.9%);
51
- --brand-gray-200: hsl(calc(var(--neutral-h) - 10), 25.0%, 89.0%);
52
- --brand-gray-300: hsl(calc(var(--neutral-h) - 10), 19.6%, 80.0%);
53
- --brand-gray-400: hsl(calc(var(--neutral-h) - 8), 14.3%, 65.7%);
54
- --brand-gray-500: hsl(calc(var(--neutral-h) - 6), 11.9%, 47.6%);
55
- --brand-gray-600: hsl(calc(var(--neutral-h) - 5), 14.9%, 35.5%);
56
- --brand-gray-700: hsl(calc(var(--neutral-h) - 4), 18.5%, 25.5%);
57
- --brand-gray-800: hsl(calc(var(--neutral-h) - 3), 23.1%, 17.8%);
58
- --brand-gray-900: hsl(calc(var(--neutral-h) - 2), 29.0%, 12.2%);
59
- --brand-gray-950: hsl(calc(var(--neutral-h) - 3), 37.1%, 6.9%);
47
+ --brand-gray-0: #FFF;
48
+ --brand-gray-50: hsl(calc(var(--neutral-h) - 19) 40.0% 98.0%);
49
+ --brand-gray-100: hsl(calc(var(--neutral-h) - 12) 40.0% 96.1%);
50
+ --brand-gray-150: hsl(calc(var(--neutral-h) - 13) 27.8% 92.9%);
51
+ --brand-gray-200: hsl(calc(var(--neutral-h) - 10) 25.0% 89.0%);
52
+ --brand-gray-300: hsl(calc(var(--neutral-h) - 10) 19.6% 80.0%);
53
+ --brand-gray-400: hsl(calc(var(--neutral-h) - 8) 14.3% 65.7%);
54
+ --brand-gray-500: hsl(calc(var(--neutral-h) - 6) 11.9% 47.6%);
55
+ --brand-gray-600: hsl(calc(var(--neutral-h) - 5) 14.9% 35.5%);
56
+ --brand-gray-700: hsl(calc(var(--neutral-h) - 4) 18.5% 25.5%);
57
+ --brand-gray-800: hsl(calc(var(--neutral-h) - 3) 23.1% 17.8%);
58
+ --brand-gray-900: hsl(calc(var(--neutral-h) - 2) 29.0% 12.2%);
59
+ --brand-gray-950: hsl(calc(var(--neutral-h) - 3) 37.1% 6.9%);
60
60
 
61
61
  // -----------------------------------------------------------------------
62
62
  // Blue — defined as HSL channels so we can compose hsla() halos and tints
@@ -68,16 +68,16 @@
68
68
  --blue-s: 100%;
69
69
  --blue-l: 59%;
70
70
 
71
- --blue-50: hsl(var(--blue-h), 100%, 97%);
72
- --blue-100: hsl(var(--blue-h), 95%, 94%);
73
- --blue-200: hsl(var(--blue-h), 95%, 89%);
74
- --blue-300: hsl(var(--blue-h), 98%, 82%);
75
- --blue-400: hsl(var(--blue-h), 100%, 75%);
76
- --blue-500: hsl(var(--blue-h), 100%, 66%);
77
- --blue-600: hsl(var(--blue-h), var(--blue-s), var(--blue-l));
78
- --blue-700: hsl(var(--blue-h), 85%, 52%);
79
- --blue-800: hsl(var(--blue-h), 79%, 40%);
80
- --blue-900: hsl(var(--blue-h), 77%, 30%);
71
+ --blue-50: hsl(var(--blue-h) 100% 97%);
72
+ --blue-100: hsl(var(--blue-h) 95% 94%);
73
+ --blue-200: hsl(var(--blue-h) 95% 89%);
74
+ --blue-300: hsl(var(--blue-h) 98% 82%);
75
+ --blue-400: hsl(var(--blue-h) 100% 75%);
76
+ --blue-500: hsl(var(--blue-h) 100% 66%);
77
+ --blue-600: hsl(var(--blue-h) var(--blue-s) var(--blue-l));
78
+ --blue-700: hsl(var(--blue-h) 85% 52%);
79
+ --blue-800: hsl(var(--blue-h) 79% 40%);
80
+ --blue-900: hsl(var(--blue-h) 77% 30%);
81
81
 
82
82
  // -----------------------------------------------------------------------
83
83
  // Orange — focus / secondary signal
@@ -124,14 +124,14 @@
124
124
  --red-s: 75%;
125
125
  --red-l: 49%;
126
126
 
127
- --red-50: hsl(var(--red-h), 86%, 97%);
128
- --red-100: hsl(var(--red-h), 86%, 95%);
129
- --red-200: hsl(var(--red-h), 86%, 88%);
130
- --red-300: hsl(var(--red-h), 84%, 76%);
131
- --red-400: hsl(var(--red-h), 87%, 57%);
132
- --red-500: hsl(var(--red-h), var(--red-s), var(--red-l));
133
- --red-600: hsl(var(--red-h), 78%, 41%);
134
- --red-700: hsl(var(--red-h), 78%, 31%);
127
+ --red-50: hsl(var(--red-h) 86% 97%);
128
+ --red-100: hsl(var(--red-h) 86% 95%);
129
+ --red-200: hsl(var(--red-h) 86% 88%);
130
+ --red-300: hsl(var(--red-h) 84% 76%);
131
+ --red-400: hsl(var(--red-h) 87% 57%);
132
+ --red-500: hsl(var(--red-h) var(--red-s) var(--red-l));
133
+ --red-600: hsl(var(--red-h) 78% 41%);
134
+ --red-700: hsl(var(--red-h) 78% 31%);
135
135
 
136
136
  // -----------------------------------------------------------------------
137
137
  // Sky — info role ramp. A brighter, cooler blue (#3B82F6) kept distinct