@lifecorner/angular-ui-kit 3.27.0 → 3.27.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (35) hide show
  1. package/fesm2022/lifecorner-angular-ui-kit-callout.mjs +2 -2
  2. package/fesm2022/lifecorner-angular-ui-kit-callout.mjs.map +1 -1
  3. package/fesm2022/lifecorner-angular-ui-kit-chat.mjs +2 -2
  4. package/fesm2022/lifecorner-angular-ui-kit-chat.mjs.map +1 -1
  5. package/fesm2022/lifecorner-angular-ui-kit-datepicker.mjs +2 -2
  6. package/fesm2022/lifecorner-angular-ui-kit-datepicker.mjs.map +1 -1
  7. package/fesm2022/lifecorner-angular-ui-kit-document-viewer.mjs +2 -2
  8. package/fesm2022/lifecorner-angular-ui-kit-document-viewer.mjs.map +1 -1
  9. package/fesm2022/lifecorner-angular-ui-kit-gallery.mjs +2 -2
  10. package/fesm2022/lifecorner-angular-ui-kit-gallery.mjs.map +1 -1
  11. package/fesm2022/lifecorner-angular-ui-kit-input.mjs +2 -2
  12. package/fesm2022/lifecorner-angular-ui-kit-input.mjs.map +1 -1
  13. package/fesm2022/lifecorner-angular-ui-kit-kanban-board.mjs +2 -2
  14. package/fesm2022/lifecorner-angular-ui-kit-kanban-board.mjs.map +1 -1
  15. package/fesm2022/lifecorner-angular-ui-kit-log-viewer.mjs +4 -4
  16. package/fesm2022/lifecorner-angular-ui-kit-log-viewer.mjs.map +1 -1
  17. package/fesm2022/lifecorner-angular-ui-kit-notification-center.mjs +2 -2
  18. package/fesm2022/lifecorner-angular-ui-kit-notification-center.mjs.map +1 -1
  19. package/fesm2022/lifecorner-angular-ui-kit-rich-text-editor.mjs +2 -2
  20. package/fesm2022/lifecorner-angular-ui-kit-rich-text-editor.mjs.map +1 -1
  21. package/fesm2022/lifecorner-angular-ui-kit-select.mjs +2 -2
  22. package/fesm2022/lifecorner-angular-ui-kit-select.mjs.map +1 -1
  23. package/fesm2022/lifecorner-angular-ui-kit-table.mjs +4 -4
  24. package/fesm2022/lifecorner-angular-ui-kit-table.mjs.map +1 -1
  25. package/fesm2022/lifecorner-angular-ui-kit-tag-input.mjs +2 -2
  26. package/fesm2022/lifecorner-angular-ui-kit-tag-input.mjs.map +1 -1
  27. package/fesm2022/lifecorner-angular-ui-kit-textarea.mjs +2 -2
  28. package/fesm2022/lifecorner-angular-ui-kit-textarea.mjs.map +1 -1
  29. package/package.json +1 -1
  30. package/src/styles/_theme-dark.scss +154 -137
  31. package/src/styles/_theme-light.scss +158 -138
  32. package/src/styles/focus-indicators.spec.ts +14 -8
  33. package/src/styles/theme-contrast.spec.ts +14 -2
  34. package/src/styles/theme-modes.spec.ts +40 -0
  35. package/src/styles/touch-targets-contrast.spec.ts +286 -0
@@ -14,9 +14,14 @@
14
14
  @use './tokens/animation' as *;
15
15
  @use './tokens/size' as *;
16
16
 
17
- // Default theme (light) on :root
18
- :root,
19
- :root.light {
17
+ // Every colour token of the light theme: --color-*, --gradient-*, --shadow-*,
18
+ // --elevation-*, --accent-line and --app-background-image (request 043, F-25).
19
+ // The root rule below emits them, and `.lc-header--light` emits them a second
20
+ // time: derived tokens (`--color-primary: var(--color-primary-500)`) resolve
21
+ // where they are declared, so only the full set on the header gives its slot
22
+ // content (buttons, links, the theme toggle, the account menu) the light
23
+ // values inside a dark page.
24
+ @mixin -light-theme-colors {
20
25
  // ============================================================================
21
26
  // Colors - Primary
22
27
  // ============================================================================
@@ -91,65 +96,6 @@
91
96
  --color-accent-rust: #{$color-accent-rust};
92
97
  --color-accent-violet: #{$color-accent-violet};
93
98
 
94
- // ============================================================================
95
- // Spacing
96
- // ============================================================================
97
- --spacing-0: #{$spacing-0};
98
- --spacing-0-5: #{$spacing-0-5};
99
- --spacing-1: #{$spacing-1};
100
- --spacing-1-5: #{$spacing-1-5};
101
- --spacing-2: #{$spacing-2};
102
- --spacing-2-5: #{$spacing-2-5};
103
- --spacing-3: #{$spacing-3};
104
- --spacing-3-5: #{$spacing-3-5};
105
- --spacing-4: #{$spacing-4};
106
- --spacing-5: #{$spacing-5};
107
- --spacing-6: #{$spacing-6};
108
- --spacing-7: #{$spacing-7};
109
- --spacing-8: #{$spacing-8};
110
- --spacing-9: #{$spacing-9};
111
- --spacing-10: #{$spacing-10};
112
- --spacing-11: #{$spacing-11};
113
- --spacing-12: #{$spacing-12};
114
- --spacing-14: #{$spacing-14};
115
- --spacing-16: #{$spacing-16};
116
-
117
- // ============================================================================
118
- // Typography - Font Families
119
- // ============================================================================
120
- --typography-font-family-base: #{$typography-font-family-base};
121
- --typography-font-family-mono: #{$typography-font-family-mono};
122
-
123
- // ============================================================================
124
- // Typography - Font Sizes
125
- // ============================================================================
126
- --typography-font-size-xs: #{$typography-font-size-xs};
127
- --typography-font-size-sm: #{$typography-font-size-sm};
128
- --typography-font-size-base: #{$typography-font-size-base};
129
- --typography-font-size-lg: #{$typography-font-size-lg};
130
- --typography-font-size-xl: #{$typography-font-size-xl};
131
- --typography-font-size-2xl: #{$typography-font-size-2xl};
132
- --typography-font-size-3xl: #{$typography-font-size-3xl};
133
- --typography-font-size-4xl: #{$typography-font-size-4xl};
134
- --typography-font-size-5xl: #{$typography-font-size-5xl};
135
- --typography-font-size-6xl: #{$typography-font-size-6xl};
136
- --typography-font-size-7xl: #{$typography-font-size-7xl};
137
-
138
- // ============================================================================
139
- // Typography - Font Weights
140
- // ============================================================================
141
- --typography-font-weight-normal: #{$typography-font-weight-normal};
142
- --typography-font-weight-medium: #{$typography-font-weight-medium};
143
- --typography-font-weight-semibold: #{$typography-font-weight-semibold};
144
- --typography-font-weight-bold: #{$typography-font-weight-bold};
145
-
146
- // ============================================================================
147
- // Typography - Line Heights
148
- // ============================================================================
149
- --typography-line-height-tight: #{$typography-line-height-tight};
150
- --typography-line-height-normal: #{$typography-line-height-normal};
151
- --typography-line-height-relaxed: #{$typography-line-height-relaxed};
152
-
153
99
  // ============================================================================
154
100
  // Elevation (Box Shadows) — light-tuned
155
101
  // ============================================================================
@@ -162,58 +108,6 @@
162
108
  --elevation-3: 0 4px 6px -2px rgba(16, 24, 40, 0.05), 0 12px 16px -4px rgba(16, 24, 40, 0.10);
163
109
  --elevation-4: 0 8px 8px -4px rgba(16, 24, 40, 0.04), 0 20px 24px -4px rgba(16, 24, 40, 0.10);
164
110
 
165
- // ============================================================================
166
- // Border Radius
167
- // ============================================================================
168
- --border-radius-none: #{$border-radius-none};
169
- --border-radius-sm: #{$border-radius-sm};
170
- --border-radius-md: #{$border-radius-md};
171
- --border-radius-lg: #{$border-radius-lg};
172
- --border-radius-xl: #{$border-radius-xl};
173
- --border-radius-2xl: #{$border-radius-2xl};
174
- --border-radius-full: #{$border-radius-full};
175
-
176
- // ============================================================================
177
- // Animation
178
- // ============================================================================
179
- --animation-duration-base: #{$animation-duration-fast};
180
- --animation-easing-ease-in: #{$animation-easing-ease-in};
181
- --animation-easing-ease-out: #{$animation-easing-ease-out};
182
- --animation-easing-ease-in-out: #{$animation-easing-ease-in-out};
183
-
184
- // ============================================================================
185
- // Size - Interactive Elements
186
- // ============================================================================
187
- --size-interactive-xs-height: #{$size-interactive-xs-height};
188
- --size-interactive-xs-padding: #{$size-interactive-xs-padding};
189
- --size-interactive-xs-font-size: #{$size-interactive-xs-font-size};
190
-
191
- --size-interactive-sm-height: #{$size-interactive-sm-height};
192
- --size-interactive-sm-padding: #{$size-interactive-sm-padding};
193
- --size-interactive-sm-font-size: #{$size-interactive-sm-font-size};
194
-
195
- --size-interactive-md-height: #{$size-interactive-md-height};
196
- --size-interactive-md-padding: #{$size-interactive-md-padding};
197
- --size-interactive-md-font-size: #{$size-interactive-md-font-size};
198
-
199
- --size-interactive-lg-height: #{$size-interactive-lg-height};
200
- --size-interactive-lg-padding: #{$size-interactive-lg-padding};
201
- --size-interactive-lg-font-size: #{$size-interactive-lg-font-size};
202
-
203
- // ============================================================================
204
- // Size - Minimum Touch Target
205
- // ============================================================================
206
- --size-min-touch-width: #{$size-min-touch-width};
207
- --size-min-touch-height: #{$size-min-touch-height};
208
-
209
- // ============================================================================
210
- // Layout - Content Width
211
- // ============================================================================
212
- // Canonical cap for page content. `lc-container size="xxl"` reads this, so an
213
- // app shell that centres its own content against the same custom property
214
- // stays in lockstep with the container instead of hard-coding a width.
215
- --lc-content-max-width: #{$size-content-max-width};
216
-
217
111
  // ============================================================================
218
112
  // Semantic Color Mappings for Light Theme (DS2.0 — mirrors dark token names)
219
113
  // ============================================================================
@@ -415,6 +309,147 @@
415
309
  --color-skeleton: #e6eff1;
416
310
  --color-skeleton-highlight: #f2f7f8;
417
311
 
312
+ // Semantic color scale aliases — map the numeric scale some components use
313
+ // onto the three canonical semantic shades so they always resolve.
314
+ --color-error-50: #{$color-error-light};
315
+ --color-error-100: #{$color-error-light};
316
+ --color-error-500: var(--color-error-default);
317
+ --color-error-600: var(--color-error-default);
318
+ --color-error-700: var(--color-error-dark);
319
+ --color-error-800: #5a0707; // Darker shade for active state
320
+ --color-success-50: #{$color-success-light};
321
+ --color-success-100: #{$color-success-light};
322
+ --color-success-500: var(--color-success-default);
323
+ --color-success-600: var(--color-success-default);
324
+ --color-success-700: var(--color-success-dark);
325
+ --color-warning-50: #{$color-warning-light};
326
+ --color-warning-100: #{$color-warning-light};
327
+ --color-warning-500: var(--color-warning-default);
328
+ --color-warning-600: var(--color-warning-default);
329
+ --color-warning-700: var(--color-warning-dark);
330
+ --color-info-50: #{$color-info-light};
331
+ --color-info-100: #{$color-info-light};
332
+ --color-info-500: var(--color-info-default);
333
+ --color-info-600: var(--color-info-default);
334
+ --color-info-700: var(--color-info-dark);
335
+ }
336
+
337
+ // Default theme (light) on :root
338
+ :root,
339
+ :root.light {
340
+ @include -light-theme-colors;
341
+
342
+ // ============================================================================
343
+ // Spacing
344
+ // ============================================================================
345
+ --spacing-0: #{$spacing-0};
346
+ --spacing-0-5: #{$spacing-0-5};
347
+ --spacing-1: #{$spacing-1};
348
+ --spacing-1-5: #{$spacing-1-5};
349
+ --spacing-2: #{$spacing-2};
350
+ --spacing-2-5: #{$spacing-2-5};
351
+ --spacing-3: #{$spacing-3};
352
+ --spacing-3-5: #{$spacing-3-5};
353
+ --spacing-4: #{$spacing-4};
354
+ --spacing-5: #{$spacing-5};
355
+ --spacing-6: #{$spacing-6};
356
+ --spacing-7: #{$spacing-7};
357
+ --spacing-8: #{$spacing-8};
358
+ --spacing-9: #{$spacing-9};
359
+ --spacing-10: #{$spacing-10};
360
+ --spacing-11: #{$spacing-11};
361
+ --spacing-12: #{$spacing-12};
362
+ --spacing-14: #{$spacing-14};
363
+ --spacing-16: #{$spacing-16};
364
+
365
+ // ============================================================================
366
+ // Typography - Font Families
367
+ // ============================================================================
368
+ --typography-font-family-base: #{$typography-font-family-base};
369
+ --typography-font-family-mono: #{$typography-font-family-mono};
370
+
371
+ // ============================================================================
372
+ // Typography - Font Sizes
373
+ // ============================================================================
374
+ --typography-font-size-xs: #{$typography-font-size-xs};
375
+ --typography-font-size-sm: #{$typography-font-size-sm};
376
+ --typography-font-size-base: #{$typography-font-size-base};
377
+ --typography-font-size-lg: #{$typography-font-size-lg};
378
+ --typography-font-size-xl: #{$typography-font-size-xl};
379
+ --typography-font-size-2xl: #{$typography-font-size-2xl};
380
+ --typography-font-size-3xl: #{$typography-font-size-3xl};
381
+ --typography-font-size-4xl: #{$typography-font-size-4xl};
382
+ --typography-font-size-5xl: #{$typography-font-size-5xl};
383
+ --typography-font-size-6xl: #{$typography-font-size-6xl};
384
+ --typography-font-size-7xl: #{$typography-font-size-7xl};
385
+
386
+ // ============================================================================
387
+ // Typography - Font Weights
388
+ // ============================================================================
389
+ --typography-font-weight-normal: #{$typography-font-weight-normal};
390
+ --typography-font-weight-medium: #{$typography-font-weight-medium};
391
+ --typography-font-weight-semibold: #{$typography-font-weight-semibold};
392
+ --typography-font-weight-bold: #{$typography-font-weight-bold};
393
+
394
+ // ============================================================================
395
+ // Typography - Line Heights
396
+ // ============================================================================
397
+ --typography-line-height-tight: #{$typography-line-height-tight};
398
+ --typography-line-height-normal: #{$typography-line-height-normal};
399
+ --typography-line-height-relaxed: #{$typography-line-height-relaxed};
400
+
401
+ // ============================================================================
402
+ // Border Radius
403
+ // ============================================================================
404
+ --border-radius-none: #{$border-radius-none};
405
+ --border-radius-sm: #{$border-radius-sm};
406
+ --border-radius-md: #{$border-radius-md};
407
+ --border-radius-lg: #{$border-radius-lg};
408
+ --border-radius-xl: #{$border-radius-xl};
409
+ --border-radius-2xl: #{$border-radius-2xl};
410
+ --border-radius-full: #{$border-radius-full};
411
+
412
+ // ============================================================================
413
+ // Animation
414
+ // ============================================================================
415
+ --animation-duration-base: #{$animation-duration-fast};
416
+ --animation-easing-ease-in: #{$animation-easing-ease-in};
417
+ --animation-easing-ease-out: #{$animation-easing-ease-out};
418
+ --animation-easing-ease-in-out: #{$animation-easing-ease-in-out};
419
+
420
+ // ============================================================================
421
+ // Size - Interactive Elements
422
+ // ============================================================================
423
+ --size-interactive-xs-height: #{$size-interactive-xs-height};
424
+ --size-interactive-xs-padding: #{$size-interactive-xs-padding};
425
+ --size-interactive-xs-font-size: #{$size-interactive-xs-font-size};
426
+
427
+ --size-interactive-sm-height: #{$size-interactive-sm-height};
428
+ --size-interactive-sm-padding: #{$size-interactive-sm-padding};
429
+ --size-interactive-sm-font-size: #{$size-interactive-sm-font-size};
430
+
431
+ --size-interactive-md-height: #{$size-interactive-md-height};
432
+ --size-interactive-md-padding: #{$size-interactive-md-padding};
433
+ --size-interactive-md-font-size: #{$size-interactive-md-font-size};
434
+
435
+ --size-interactive-lg-height: #{$size-interactive-lg-height};
436
+ --size-interactive-lg-padding: #{$size-interactive-lg-padding};
437
+ --size-interactive-lg-font-size: #{$size-interactive-lg-font-size};
438
+
439
+ // ============================================================================
440
+ // Size - Minimum Touch Target
441
+ // ============================================================================
442
+ --size-min-touch-width: #{$size-min-touch-width};
443
+ --size-min-touch-height: #{$size-min-touch-height};
444
+
445
+ // ============================================================================
446
+ // Layout - Content Width
447
+ // ============================================================================
448
+ // Canonical cap for page content. `lc-container size="xxl"` reads this, so an
449
+ // app shell that centres its own content against the same custom property
450
+ // stays in lockstep with the container instead of hard-coding a width.
451
+ --lc-content-max-width: #{$size-content-max-width};
452
+
418
453
  // ============================================================================
419
454
  // Short Aliases for Common Usage (Component Convenience)
420
455
  // ============================================================================
@@ -441,28 +476,13 @@
441
476
  --line-height-normal: var(--typography-line-height-normal);
442
477
  --line-height-relaxed: var(--typography-line-height-relaxed);
443
478
  --animation-timing-ease: var(--animation-easing-ease-in-out);
444
-
445
- // Semantic color scale aliases — map the numeric scale some components use
446
- // onto the three canonical semantic shades so they always resolve.
447
- --color-error-50: #{$color-error-light};
448
- --color-error-100: #{$color-error-light};
449
- --color-error-500: var(--color-error-default);
450
- --color-error-600: var(--color-error-default);
451
- --color-error-700: var(--color-error-dark);
452
- --color-error-800: #5a0707; // Darker shade for active state
453
- --color-success-50: #{$color-success-light};
454
- --color-success-100: #{$color-success-light};
455
- --color-success-500: var(--color-success-default);
456
- --color-success-600: var(--color-success-default);
457
- --color-success-700: var(--color-success-dark);
458
- --color-warning-50: #{$color-warning-light};
459
- --color-warning-100: #{$color-warning-light};
460
- --color-warning-500: var(--color-warning-default);
461
- --color-warning-600: var(--color-warning-default);
462
- --color-warning-700: var(--color-warning-dark);
463
- --color-info-50: #{$color-info-light};
464
- --color-info-100: #{$color-info-light};
465
- --color-info-500: var(--color-info-default);
466
- --color-info-600: var(--color-info-default);
467
- --color-info-700: var(--color-info-dark);
479
+ }
480
+
481
+ // `<lc-header theme="light">` keeps the light palette inside a dark page
482
+ // (request 043, F-25): its slot buttons and primary inks measured 1.05:1
483
+ // (outline) and 1.59:1 (link) there; with the tokens re-declared they match a
484
+ // light page (17.12:1, 6.21:1). A root-level token override does not reach
485
+ // inside a themed header.
486
+ .lc-header--light {
487
+ @include -light-theme-colors;
468
488
  }
@@ -44,7 +44,9 @@ const rings: [string, string, string][] = [
44
44
  ['document-viewer/document-viewer.component.scss', '.doc-viewer__btn', '2px'],
45
45
  ['document-viewer/document-viewer.component.scss', '.doc-viewer__download-btn', '2px'],
46
46
  ['filter-bar/filter-bar.component.scss', '.lc-filter-bar__toggle-btn', '-2px'],
47
- ['select/select.component.scss', '.lc-select__clear', '2px'],
47
+ // 2px → 0 by review 043 r1 F3: the button grew from 20 to 24 px (2 px padding
48
+ // inside a −2 px margin), so offset 0 draws the ring where 2 px round 20 px did.
49
+ ['select/select.component.scss', '.lc-select__clear', '0'],
48
50
  ['gallery/gallery.component.scss', '.gallery__filter-btn', '2px'],
49
51
  ['log-viewer/log-viewer.component.scss', '.lc-log-viewer__level-pill', '2px'],
50
52
  ['callout/callout.component.scss', '.callout__dismiss', '2px'],
@@ -171,14 +173,18 @@ describe('Focus indicators (request 042)', () => {
171
173
 
172
174
  describe('D-6: focus wins over hover in every field with the pattern (F-19)', () => {
173
175
  // [sheet, hover selector after the fix, declarations it keeps]
176
+ // Request 043 (F-23, design D-5) changed the first seven rows on purpose:
177
+ // they also exclude the error class (an error field kept no error border
178
+ // under the pointer), and the textarea/datepicker outline hover moved from
179
+ // --color-primary-400 (1.89:1 light) to --color-text-secondary (7.55:1).
174
180
  const hovers: [string, string, Record<string, string>][] = [
175
- ['textarea/textarea.component.scss', '.lc-textarea--outline:hover:not(:disabled):not(:read-only):not(:focus)', { 'border-color': 'var(--color-primary-400)' }],
176
- ['textarea/textarea.component.scss', '.lc-textarea--filled:hover:not(:disabled):not(:read-only):not(:focus)', { 'background-color': 'var(--color-surface-hover)' }],
177
- ['datepicker/datepicker.component.scss', '.lc-datepicker:hover:not(:disabled):not([readonly]):not(:focus)', { 'border-color': 'var(--color-primary-400)' }],
178
- ['datepicker/datepicker.component.scss', '.lc-datepicker.lc-datepicker--filled:hover:not(:disabled):not([readonly]):not(:focus)', { 'background-color': 'var(--color-surface-hover)', 'border-color': 'var(--color-border)' }],
179
- ['input/input.component.scss', '.input-container:hover:not(.input-disabled):not(.input-readonly):not(:focus-within)', { 'border-color': 'var(--color-text-secondary)' }],
180
- ['select/select.component.scss', '.lc-select:hover:not(.lc-select--disabled):not(:focus)', { 'border-color': 'var(--color-text-secondary)' }],
181
- ['select/select.component.scss', '.lc-select.lc-select--filled:hover:not(.lc-select--disabled):not(:focus)', { 'background-color': 'var(--color-surface-hover)', 'border-color': 'var(--color-border)' }],
181
+ ['textarea/textarea.component.scss', '.lc-textarea--outline:hover:not(:disabled):not(:read-only):not(.lc-textarea--error):not(:focus)', { 'border-color': 'var(--color-text-secondary)' }],
182
+ ['textarea/textarea.component.scss', '.lc-textarea--filled:hover:not(:disabled):not(:read-only):not(.lc-textarea--error):not(:focus)', { 'background-color': 'var(--color-surface-hover)' }],
183
+ ['datepicker/datepicker.component.scss', '.lc-datepicker:hover:not(:disabled):not([readonly]):not(.lc-datepicker--error):not(:focus)', { 'border-color': 'var(--color-text-secondary)' }],
184
+ ['datepicker/datepicker.component.scss', '.lc-datepicker.lc-datepicker--filled:hover:not(:disabled):not([readonly]):not(.lc-datepicker--error):not(:focus)', { 'background-color': 'var(--color-surface-hover)', 'border-color': 'var(--color-border)' }],
185
+ ['input/input.component.scss', '.input-container:hover:not(.input-disabled):not(.input-readonly):not(.input-invalid):not(:focus-within)', { 'border-color': 'var(--color-text-secondary)' }],
186
+ ['select/select.component.scss', '.lc-select:hover:not(.lc-select--disabled):not(.lc-select--error):not(:focus)', { 'border-color': 'var(--color-text-secondary)' }],
187
+ ['select/select.component.scss', '.lc-select.lc-select--filled:hover:not(.lc-select--disabled):not(.lc-select--error):not(:focus)', { 'background-color': 'var(--color-surface-hover)', 'border-color': 'var(--color-border)' }],
182
188
  ['search-input/search-input.component.scss', '.search-input:hover:not(.search-input--disabled):not(:focus-within)', { 'border-color': 'var(--color-text-secondary)' }],
183
189
  ['tag-input/tag-input.component.scss', '.lc-tag-input__container:hover:not(.lc-tag-input__container--focused)', { 'border-color': 'var(--color-text-secondary)' }],
184
190
  ['date-range-picker/date-range-picker.component.scss', '.lc-drp__field:hover:not(.lc-drp__field--disabled):not(:focus-within)', { 'border-color': 'var(--color-text-secondary)' }],
@@ -981,9 +981,21 @@ describe('Component pairings of 3.22.4 (request 034)', () => {
981
981
  ['diff', '.lc-diff__num', { color: secondary }],
982
982
  // F-4: the lc-badge primary pair with a primary border.
983
983
  ['card', '.card__badge--primary', { 'background-color': 'var(--color-primary-subtle)', color: 'var(--color-on-primary-subtle)', border: '1px solid var(--color-primary-500)' }],
984
- // F-5: a 40 px hit area into half of each gap; the visible pill is unchanged.
984
+ // F-5: a hit area into half of each gap; the visible pill is unchanged.
985
+ // Request 043 (F-22) raised it from 40 to 44 px high (and at least 44 wide):
986
+ // the spacing exception is no longer relied on.
985
987
  ['log', '.lc-log-viewer__level-pill', { position: 'relative', padding: '0.125rem 0.5rem', 'font-size': '0.6875rem' }],
986
- ['log', '.lc-log-viewer__level-pill::before', { content: '""', position: 'absolute', 'inset-inline': '-0.125rem', top: 'calc(50% - 20px)', bottom: 'calc(50% - 20px)' }],
988
+ [
989
+ 'log',
990
+ '.lc-log-viewer__level-pill::before',
991
+ {
992
+ content: '""',
993
+ position: 'absolute',
994
+ 'inset-inline': 'min(-0.125rem, (100% - var(--size-min-touch-height, 2.75rem)) / 2)',
995
+ top: 'calc(50% - var(--size-min-touch-height, 2.75rem) / 2)',
996
+ bottom: 'calc(50% - var(--size-min-touch-height, 2.75rem) / 2)',
997
+ },
998
+ ],
987
999
  // F-7: three text steps instead of opacity, in the log and the terminal.
988
1000
  ['log', '.lc-log-viewer__line--debug', { color: secondary }],
989
1001
  ...meta.map((m): Row => ['log', `.lc-log-viewer__${m}`, { color: secondary }]),
@@ -58,3 +58,43 @@ describe('Theme modes', () => {
58
58
  expect(tokens['--app-background-image']).toContain('rgba(78, 63, 132, 0.14)');
59
59
  });
60
60
  });
61
+
62
+ /**
63
+ * Request 043 (F-25, design D-7): a header with `theme="light"` / `"dark"`
64
+ * re-declares every colour token of that theme, so its slot content (buttons,
65
+ * links, the theme toggle, the account menu) resolves the header's palette
66
+ * instead of the page's. Derived tokens resolve where they are declared, so
67
+ * the set must be complete.
68
+ */
69
+ describe('Theme scope of a themed header', () => {
70
+ const COLOUR = /^--(color-|gradient-|shadow-|elevation-|accent-line$|app-background-image$)/;
71
+ const colours = (tokens: Record<string, string>) =>
72
+ Object.fromEntries(Object.entries(tokens).filter(([name]) => COLOUR.test(name)));
73
+
74
+ it('AC-6: .lc-header--light declares exactly the colour tokens of the light root (172), with the same values', () => {
75
+ const root = tokensOf(light, ':root,');
76
+ const header = tokensOf(light, '\n.lc-header--light {');
77
+ expect(Object.keys(header)).toHaveLength(172);
78
+ expect(header).toEqual(colours(root));
79
+ });
80
+
81
+ it('AC-7: .lc-header--dark declares exactly the colour tokens of the dark root (172), with the same values', () => {
82
+ const root = tokensOf(dark, ':root.dark,');
83
+ const header = tokensOf(dark, '\n.lc-header--dark {');
84
+ expect(Object.keys(header)).toHaveLength(172);
85
+ expect(header).toEqual(colours(root));
86
+ });
87
+
88
+ it('AC-12: the root rules still declare the full token set (252 per theme), colours and the rest', () => {
89
+ expect(Object.keys(tokensOf(light, ':root,'))).toHaveLength(252);
90
+ expect(Object.keys(tokensOf(dark, ':root.dark,'))).toHaveLength(252);
91
+ expect(Object.keys(colours(tokensOf(light, ':root,')))).toHaveLength(172);
92
+ });
93
+
94
+ it('scopes only the header: each theme file emits the header rule once, after its root rules', () => {
95
+ expect(light.match(/\.lc-header--light \{/g)).toHaveLength(1);
96
+ expect(dark.match(/\.lc-header--dark \{/g)).toHaveLength(1);
97
+ expect(light.indexOf('.lc-header--light {')).toBeGreaterThan(light.indexOf(':root,'));
98
+ expect(dark.indexOf('.lc-header--dark {')).toBeGreaterThan(dark.indexOf(':root.system {'));
99
+ });
100
+ });