@lilydesignsystem/themes 0.2.0 → 0.3.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 (46) hide show
  1. package/dist/abyss.css +55 -7
  2. package/dist/acid.css +55 -7
  3. package/dist/adobe-spectrum.css +55 -7
  4. package/dist/aqua.css +55 -7
  5. package/dist/autumn.css +55 -7
  6. package/dist/black.css +55 -7
  7. package/dist/bumblebee.css +55 -7
  8. package/dist/business.css +55 -7
  9. package/dist/caramellatte.css +55 -7
  10. package/dist/cmyk.css +55 -7
  11. package/dist/coffee.css +55 -7
  12. package/dist/corporate.css +55 -7
  13. package/dist/cupcake.css +55 -7
  14. package/dist/cyberpunk.css +55 -7
  15. package/dist/dark.css +55 -7
  16. package/dist/dim.css +55 -7
  17. package/dist/dracula.css +55 -7
  18. package/dist/emerald.css +55 -7
  19. package/dist/fantasy.css +55 -7
  20. package/dist/forest.css +55 -7
  21. package/dist/garden.css +55 -7
  22. package/dist/halloween.css +55 -7
  23. package/dist/lemonade.css +55 -7
  24. package/dist/light.css +55 -7
  25. package/dist/lofi.css +55 -7
  26. package/dist/luxury.css +55 -7
  27. package/dist/mozilla-protocol.css +55 -7
  28. package/dist/night.css +55 -7
  29. package/dist/nord.css +55 -7
  30. package/dist/pastel.css +55 -7
  31. package/dist/retro.css +55 -7
  32. package/dist/silk.css +55 -7
  33. package/dist/sunset.css +55 -7
  34. package/dist/synthwave.css +55 -7
  35. package/dist/united-kingdom-government-digital-service.css +55 -7
  36. package/dist/united-kingdom-national-health-service-england-for-patients.css +55 -7
  37. package/dist/united-kingdom-national-health-service-england-for-practitioners.css +55 -7
  38. package/dist/united-kingdom-national-health-service-scotland-for-patients.css +55 -7
  39. package/dist/united-kingdom-national-health-service-scotland-for-practitioners.css +55 -7
  40. package/dist/united-kingdom-national-health-service-wales-for-patients.css +55 -7
  41. package/dist/united-kingdom-national-health-service-wales-for-practitioners.css +55 -7
  42. package/dist/united-states-web-design-system.css +55 -7
  43. package/dist/valentine.css +55 -7
  44. package/dist/winter.css +55 -7
  45. package/dist/wireframe.css +55 -7
  46. package/package.json +1 -1
package/dist/luxury.css CHANGED
@@ -155,6 +155,14 @@
155
155
  /* Primary body-copy colour. Maps to the theme's high-contrast
156
156
  reading colour. */
157
157
  --lily-text: var(--color-base-content);
158
+ /* Error text: the theme's error colour pulled toward the theme's own reading colour (`--color-base-content`, not `--lily-text`, which a host page may override) so it
159
+ keeps WCAG contrast as text on the page and on the error-tinted
160
+ callout surface (`--color-error` itself is a fill colour). */
161
+ --lily-error-text: color-mix(
162
+ in oklch,
163
+ var(--color-error) 22%,
164
+ var(--color-base-content)
165
+ );
158
166
  /* Muted / secondary text — mixed 70% with transparent to keep the
159
167
  hue but lower contrast for captions, helptext, placeholders. */
160
168
  --lily-text-muted: color-mix(
@@ -894,7 +902,7 @@
894
902
  }
895
903
  :where(.dont-list-item)::marker {
896
904
  content: "✗ ";
897
- color: var(--color-error);
905
+ color: var(--lily-error-text);
898
906
  }
899
907
 
900
908
  /* --- Tree --------------------------------------------------------------- */
@@ -976,7 +984,7 @@
976
984
  color: var(--color-success);
977
985
  }
978
986
  :where(.validation-list-item[data-status="failed"]) {
979
- color: var(--color-error);
987
+ color: var(--lily-error-text);
980
988
  }
981
989
  :where(.validation-list-item[data-status="pending"]) {
982
990
  color: var(--lily-text-muted);
@@ -1334,7 +1342,7 @@
1334
1342
 
1335
1343
  /* Error message — inline form-validation message. */
1336
1344
  :where(.error-message) {
1337
- color: var(--color-error);
1345
+ color: var(--lily-error-text);
1338
1346
  font-weight: 600;
1339
1347
  }
1340
1348
  /* Error summary — heavyweight 4px border (GOV.UK pattern) so users
@@ -2548,6 +2556,7 @@
2548
2556
  .theme-picker-list,
2549
2557
  .locale-picker-list,
2550
2558
  .text-size-picker-list,
2559
+ .motion-picker-list,
2551
2560
  .share-picker-list,
2552
2561
  .search-picker-panel
2553
2562
  ) {
@@ -2573,17 +2582,56 @@
2573
2582
  .theme-picker-list,
2574
2583
  .locale-picker-list,
2575
2584
  .text-size-picker-list,
2585
+ .motion-picker-list,
2576
2586
  .share-picker-list,
2577
2587
  .search-picker-panel
2578
2588
  )[hidden] {
2579
2589
  display: none;
2580
2590
  }
2581
2591
 
2582
- :where(.theme-picker-list, .locale-picker-list, .text-size-picker-list)
2592
+ /* Popups open under their button, aligned to its start edge, and flip to
2593
+ its end edge (or above it) when they would run off the viewport. A header
2594
+ picker near the right edge otherwise overflows, and focusing the popup
2595
+ scrolls the whole page sideways. `position: fixed` makes the viewport the
2596
+ containing block that the flip fallbacks are checked against; browsers
2597
+ without anchor positioning keep the absolute placement above. */
2598
+ @supports (position-area: block-end) {
2599
+ :where(.theme-picker) { anchor-name: --lily-theme-picker; }
2600
+ :where(.locale-picker) { anchor-name: --lily-locale-picker; }
2601
+ :where(.text-size-picker) { anchor-name: --lily-text-size-picker; }
2602
+ :where(.motion-picker) { anchor-name: --lily-motion-picker; }
2603
+ :where(.share-picker) { anchor-name: --lily-share-picker; }
2604
+ :where(.search-picker) { anchor-name: --lily-search-picker; }
2605
+ :where(.theme-picker-list) { position-anchor: --lily-theme-picker; }
2606
+ :where(.locale-picker-list) { position-anchor: --lily-locale-picker; }
2607
+ :where(.text-size-picker-list) { position-anchor: --lily-text-size-picker; }
2608
+ :where(.motion-picker-list) { position-anchor: --lily-motion-picker; }
2609
+ :where(.share-picker-list) { position-anchor: --lily-share-picker; }
2610
+ :where(.search-picker-panel) { position-anchor: --lily-search-picker; }
2611
+ :where(
2612
+ .theme-picker-list,
2613
+ .locale-picker-list,
2614
+ .text-size-picker-list,
2615
+ .motion-picker-list,
2616
+ .share-picker-list,
2617
+ .search-picker-panel
2618
+ ) {
2619
+ position: fixed;
2620
+ inset: auto;
2621
+ position-area: block-end span-inline-end;
2622
+ position-try-fallbacks: flip-inline, flip-block, flip-block flip-inline;
2623
+ min-width: 0;
2624
+ width: max-content;
2625
+ max-width: calc(100vw - 1rem);
2626
+ }
2627
+ }
2628
+
2629
+ :where(.theme-picker-list, .locale-picker-list, .text-size-picker-list, .motion-picker-list)
2583
2630
  > :where(
2584
2631
  .theme-picker-option,
2585
2632
  .locale-picker-option,
2586
- .text-size-picker-option
2633
+ .text-size-picker-option,
2634
+ .motion-picker-option
2587
2635
  ) {
2588
2636
  padding: var(--lily-space-xs) var(--lily-space-sm);
2589
2637
  border-radius: var(--lily-radius-sm);
@@ -2592,7 +2640,7 @@
2592
2640
 
2593
2641
  /* data-active is the keyboard cursor (aria-activedescendant); focus
2594
2642
  stays on the listbox, so this is the only visible cue for it. */
2595
- :where(.theme-picker-list, .locale-picker-list, .text-size-picker-list)
2643
+ :where(.theme-picker-list, .locale-picker-list, .text-size-picker-list, .motion-picker-list)
2596
2644
  > :where([data-active]) {
2597
2645
  background-color: var(--lily-surface-alt);
2598
2646
  outline: var(--lily-focus-ring);
@@ -2601,7 +2649,7 @@
2601
2649
 
2602
2650
  /* aria-selected marks the applied theme/locale, which is not the
2603
2651
  same thing as the keyboard cursor. Both can be visible at once. */
2604
- :where(.theme-picker-list, .locale-picker-list, .text-size-picker-list)
2652
+ :where(.theme-picker-list, .locale-picker-list, .text-size-picker-list, .motion-picker-list)
2605
2653
  > :where([aria-selected="true"]) {
2606
2654
  font-weight: 600;
2607
2655
  background-color: var(--lily-surface-sunken);
@@ -155,6 +155,14 @@
155
155
  /* Primary body-copy colour. Maps to the theme's high-contrast
156
156
  reading colour. */
157
157
  --lily-text: var(--color-base-content);
158
+ /* Error text: the theme's error colour pulled toward the theme's own reading colour (`--color-base-content`, not `--lily-text`, which a host page may override) so it
159
+ keeps WCAG contrast as text on the page and on the error-tinted
160
+ callout surface (`--color-error` itself is a fill colour). */
161
+ --lily-error-text: color-mix(
162
+ in oklch,
163
+ var(--color-error) 22%,
164
+ var(--color-base-content)
165
+ );
158
166
  /* Muted / secondary text — mixed 70% with transparent to keep the
159
167
  hue but lower contrast for captions, helptext, placeholders. */
160
168
  --lily-text-muted: color-mix(
@@ -894,7 +902,7 @@
894
902
  }
895
903
  :where(.dont-list-item)::marker {
896
904
  content: "✗ ";
897
- color: var(--color-error);
905
+ color: var(--lily-error-text);
898
906
  }
899
907
 
900
908
  /* --- Tree --------------------------------------------------------------- */
@@ -976,7 +984,7 @@
976
984
  color: var(--color-success);
977
985
  }
978
986
  :where(.validation-list-item[data-status="failed"]) {
979
- color: var(--color-error);
987
+ color: var(--lily-error-text);
980
988
  }
981
989
  :where(.validation-list-item[data-status="pending"]) {
982
990
  color: var(--lily-text-muted);
@@ -1334,7 +1342,7 @@
1334
1342
 
1335
1343
  /* Error message — inline form-validation message. */
1336
1344
  :where(.error-message) {
1337
- color: var(--color-error);
1345
+ color: var(--lily-error-text);
1338
1346
  font-weight: 600;
1339
1347
  }
1340
1348
  /* Error summary — heavyweight 4px border (GOV.UK pattern) so users
@@ -2548,6 +2556,7 @@
2548
2556
  .theme-picker-list,
2549
2557
  .locale-picker-list,
2550
2558
  .text-size-picker-list,
2559
+ .motion-picker-list,
2551
2560
  .share-picker-list,
2552
2561
  .search-picker-panel
2553
2562
  ) {
@@ -2573,17 +2582,56 @@
2573
2582
  .theme-picker-list,
2574
2583
  .locale-picker-list,
2575
2584
  .text-size-picker-list,
2585
+ .motion-picker-list,
2576
2586
  .share-picker-list,
2577
2587
  .search-picker-panel
2578
2588
  )[hidden] {
2579
2589
  display: none;
2580
2590
  }
2581
2591
 
2582
- :where(.theme-picker-list, .locale-picker-list, .text-size-picker-list)
2592
+ /* Popups open under their button, aligned to its start edge, and flip to
2593
+ its end edge (or above it) when they would run off the viewport. A header
2594
+ picker near the right edge otherwise overflows, and focusing the popup
2595
+ scrolls the whole page sideways. `position: fixed` makes the viewport the
2596
+ containing block that the flip fallbacks are checked against; browsers
2597
+ without anchor positioning keep the absolute placement above. */
2598
+ @supports (position-area: block-end) {
2599
+ :where(.theme-picker) { anchor-name: --lily-theme-picker; }
2600
+ :where(.locale-picker) { anchor-name: --lily-locale-picker; }
2601
+ :where(.text-size-picker) { anchor-name: --lily-text-size-picker; }
2602
+ :where(.motion-picker) { anchor-name: --lily-motion-picker; }
2603
+ :where(.share-picker) { anchor-name: --lily-share-picker; }
2604
+ :where(.search-picker) { anchor-name: --lily-search-picker; }
2605
+ :where(.theme-picker-list) { position-anchor: --lily-theme-picker; }
2606
+ :where(.locale-picker-list) { position-anchor: --lily-locale-picker; }
2607
+ :where(.text-size-picker-list) { position-anchor: --lily-text-size-picker; }
2608
+ :where(.motion-picker-list) { position-anchor: --lily-motion-picker; }
2609
+ :where(.share-picker-list) { position-anchor: --lily-share-picker; }
2610
+ :where(.search-picker-panel) { position-anchor: --lily-search-picker; }
2611
+ :where(
2612
+ .theme-picker-list,
2613
+ .locale-picker-list,
2614
+ .text-size-picker-list,
2615
+ .motion-picker-list,
2616
+ .share-picker-list,
2617
+ .search-picker-panel
2618
+ ) {
2619
+ position: fixed;
2620
+ inset: auto;
2621
+ position-area: block-end span-inline-end;
2622
+ position-try-fallbacks: flip-inline, flip-block, flip-block flip-inline;
2623
+ min-width: 0;
2624
+ width: max-content;
2625
+ max-width: calc(100vw - 1rem);
2626
+ }
2627
+ }
2628
+
2629
+ :where(.theme-picker-list, .locale-picker-list, .text-size-picker-list, .motion-picker-list)
2583
2630
  > :where(
2584
2631
  .theme-picker-option,
2585
2632
  .locale-picker-option,
2586
- .text-size-picker-option
2633
+ .text-size-picker-option,
2634
+ .motion-picker-option
2587
2635
  ) {
2588
2636
  padding: var(--lily-space-xs) var(--lily-space-sm);
2589
2637
  border-radius: var(--lily-radius-sm);
@@ -2592,7 +2640,7 @@
2592
2640
 
2593
2641
  /* data-active is the keyboard cursor (aria-activedescendant); focus
2594
2642
  stays on the listbox, so this is the only visible cue for it. */
2595
- :where(.theme-picker-list, .locale-picker-list, .text-size-picker-list)
2643
+ :where(.theme-picker-list, .locale-picker-list, .text-size-picker-list, .motion-picker-list)
2596
2644
  > :where([data-active]) {
2597
2645
  background-color: var(--lily-surface-alt);
2598
2646
  outline: var(--lily-focus-ring);
@@ -2601,7 +2649,7 @@
2601
2649
 
2602
2650
  /* aria-selected marks the applied theme/locale, which is not the
2603
2651
  same thing as the keyboard cursor. Both can be visible at once. */
2604
- :where(.theme-picker-list, .locale-picker-list, .text-size-picker-list)
2652
+ :where(.theme-picker-list, .locale-picker-list, .text-size-picker-list, .motion-picker-list)
2605
2653
  > :where([aria-selected="true"]) {
2606
2654
  font-weight: 600;
2607
2655
  background-color: var(--lily-surface-sunken);
package/dist/night.css CHANGED
@@ -155,6 +155,14 @@
155
155
  /* Primary body-copy colour. Maps to the theme's high-contrast
156
156
  reading colour. */
157
157
  --lily-text: var(--color-base-content);
158
+ /* Error text: the theme's error colour pulled toward the theme's own reading colour (`--color-base-content`, not `--lily-text`, which a host page may override) so it
159
+ keeps WCAG contrast as text on the page and on the error-tinted
160
+ callout surface (`--color-error` itself is a fill colour). */
161
+ --lily-error-text: color-mix(
162
+ in oklch,
163
+ var(--color-error) 22%,
164
+ var(--color-base-content)
165
+ );
158
166
  /* Muted / secondary text — mixed 70% with transparent to keep the
159
167
  hue but lower contrast for captions, helptext, placeholders. */
160
168
  --lily-text-muted: color-mix(
@@ -894,7 +902,7 @@
894
902
  }
895
903
  :where(.dont-list-item)::marker {
896
904
  content: "✗ ";
897
- color: var(--color-error);
905
+ color: var(--lily-error-text);
898
906
  }
899
907
 
900
908
  /* --- Tree --------------------------------------------------------------- */
@@ -976,7 +984,7 @@
976
984
  color: var(--color-success);
977
985
  }
978
986
  :where(.validation-list-item[data-status="failed"]) {
979
- color: var(--color-error);
987
+ color: var(--lily-error-text);
980
988
  }
981
989
  :where(.validation-list-item[data-status="pending"]) {
982
990
  color: var(--lily-text-muted);
@@ -1334,7 +1342,7 @@
1334
1342
 
1335
1343
  /* Error message — inline form-validation message. */
1336
1344
  :where(.error-message) {
1337
- color: var(--color-error);
1345
+ color: var(--lily-error-text);
1338
1346
  font-weight: 600;
1339
1347
  }
1340
1348
  /* Error summary — heavyweight 4px border (GOV.UK pattern) so users
@@ -2548,6 +2556,7 @@
2548
2556
  .theme-picker-list,
2549
2557
  .locale-picker-list,
2550
2558
  .text-size-picker-list,
2559
+ .motion-picker-list,
2551
2560
  .share-picker-list,
2552
2561
  .search-picker-panel
2553
2562
  ) {
@@ -2573,17 +2582,56 @@
2573
2582
  .theme-picker-list,
2574
2583
  .locale-picker-list,
2575
2584
  .text-size-picker-list,
2585
+ .motion-picker-list,
2576
2586
  .share-picker-list,
2577
2587
  .search-picker-panel
2578
2588
  )[hidden] {
2579
2589
  display: none;
2580
2590
  }
2581
2591
 
2582
- :where(.theme-picker-list, .locale-picker-list, .text-size-picker-list)
2592
+ /* Popups open under their button, aligned to its start edge, and flip to
2593
+ its end edge (or above it) when they would run off the viewport. A header
2594
+ picker near the right edge otherwise overflows, and focusing the popup
2595
+ scrolls the whole page sideways. `position: fixed` makes the viewport the
2596
+ containing block that the flip fallbacks are checked against; browsers
2597
+ without anchor positioning keep the absolute placement above. */
2598
+ @supports (position-area: block-end) {
2599
+ :where(.theme-picker) { anchor-name: --lily-theme-picker; }
2600
+ :where(.locale-picker) { anchor-name: --lily-locale-picker; }
2601
+ :where(.text-size-picker) { anchor-name: --lily-text-size-picker; }
2602
+ :where(.motion-picker) { anchor-name: --lily-motion-picker; }
2603
+ :where(.share-picker) { anchor-name: --lily-share-picker; }
2604
+ :where(.search-picker) { anchor-name: --lily-search-picker; }
2605
+ :where(.theme-picker-list) { position-anchor: --lily-theme-picker; }
2606
+ :where(.locale-picker-list) { position-anchor: --lily-locale-picker; }
2607
+ :where(.text-size-picker-list) { position-anchor: --lily-text-size-picker; }
2608
+ :where(.motion-picker-list) { position-anchor: --lily-motion-picker; }
2609
+ :where(.share-picker-list) { position-anchor: --lily-share-picker; }
2610
+ :where(.search-picker-panel) { position-anchor: --lily-search-picker; }
2611
+ :where(
2612
+ .theme-picker-list,
2613
+ .locale-picker-list,
2614
+ .text-size-picker-list,
2615
+ .motion-picker-list,
2616
+ .share-picker-list,
2617
+ .search-picker-panel
2618
+ ) {
2619
+ position: fixed;
2620
+ inset: auto;
2621
+ position-area: block-end span-inline-end;
2622
+ position-try-fallbacks: flip-inline, flip-block, flip-block flip-inline;
2623
+ min-width: 0;
2624
+ width: max-content;
2625
+ max-width: calc(100vw - 1rem);
2626
+ }
2627
+ }
2628
+
2629
+ :where(.theme-picker-list, .locale-picker-list, .text-size-picker-list, .motion-picker-list)
2583
2630
  > :where(
2584
2631
  .theme-picker-option,
2585
2632
  .locale-picker-option,
2586
- .text-size-picker-option
2633
+ .text-size-picker-option,
2634
+ .motion-picker-option
2587
2635
  ) {
2588
2636
  padding: var(--lily-space-xs) var(--lily-space-sm);
2589
2637
  border-radius: var(--lily-radius-sm);
@@ -2592,7 +2640,7 @@
2592
2640
 
2593
2641
  /* data-active is the keyboard cursor (aria-activedescendant); focus
2594
2642
  stays on the listbox, so this is the only visible cue for it. */
2595
- :where(.theme-picker-list, .locale-picker-list, .text-size-picker-list)
2643
+ :where(.theme-picker-list, .locale-picker-list, .text-size-picker-list, .motion-picker-list)
2596
2644
  > :where([data-active]) {
2597
2645
  background-color: var(--lily-surface-alt);
2598
2646
  outline: var(--lily-focus-ring);
@@ -2601,7 +2649,7 @@
2601
2649
 
2602
2650
  /* aria-selected marks the applied theme/locale, which is not the
2603
2651
  same thing as the keyboard cursor. Both can be visible at once. */
2604
- :where(.theme-picker-list, .locale-picker-list, .text-size-picker-list)
2652
+ :where(.theme-picker-list, .locale-picker-list, .text-size-picker-list, .motion-picker-list)
2605
2653
  > :where([aria-selected="true"]) {
2606
2654
  font-weight: 600;
2607
2655
  background-color: var(--lily-surface-sunken);
package/dist/nord.css CHANGED
@@ -155,6 +155,14 @@
155
155
  /* Primary body-copy colour. Maps to the theme's high-contrast
156
156
  reading colour. */
157
157
  --lily-text: var(--color-base-content);
158
+ /* Error text: the theme's error colour pulled toward the theme's own reading colour (`--color-base-content`, not `--lily-text`, which a host page may override) so it
159
+ keeps WCAG contrast as text on the page and on the error-tinted
160
+ callout surface (`--color-error` itself is a fill colour). */
161
+ --lily-error-text: color-mix(
162
+ in oklch,
163
+ var(--color-error) 22%,
164
+ var(--color-base-content)
165
+ );
158
166
  /* Muted / secondary text — mixed 70% with transparent to keep the
159
167
  hue but lower contrast for captions, helptext, placeholders. */
160
168
  --lily-text-muted: color-mix(
@@ -894,7 +902,7 @@
894
902
  }
895
903
  :where(.dont-list-item)::marker {
896
904
  content: "✗ ";
897
- color: var(--color-error);
905
+ color: var(--lily-error-text);
898
906
  }
899
907
 
900
908
  /* --- Tree --------------------------------------------------------------- */
@@ -976,7 +984,7 @@
976
984
  color: var(--color-success);
977
985
  }
978
986
  :where(.validation-list-item[data-status="failed"]) {
979
- color: var(--color-error);
987
+ color: var(--lily-error-text);
980
988
  }
981
989
  :where(.validation-list-item[data-status="pending"]) {
982
990
  color: var(--lily-text-muted);
@@ -1334,7 +1342,7 @@
1334
1342
 
1335
1343
  /* Error message — inline form-validation message. */
1336
1344
  :where(.error-message) {
1337
- color: var(--color-error);
1345
+ color: var(--lily-error-text);
1338
1346
  font-weight: 600;
1339
1347
  }
1340
1348
  /* Error summary — heavyweight 4px border (GOV.UK pattern) so users
@@ -2548,6 +2556,7 @@
2548
2556
  .theme-picker-list,
2549
2557
  .locale-picker-list,
2550
2558
  .text-size-picker-list,
2559
+ .motion-picker-list,
2551
2560
  .share-picker-list,
2552
2561
  .search-picker-panel
2553
2562
  ) {
@@ -2573,17 +2582,56 @@
2573
2582
  .theme-picker-list,
2574
2583
  .locale-picker-list,
2575
2584
  .text-size-picker-list,
2585
+ .motion-picker-list,
2576
2586
  .share-picker-list,
2577
2587
  .search-picker-panel
2578
2588
  )[hidden] {
2579
2589
  display: none;
2580
2590
  }
2581
2591
 
2582
- :where(.theme-picker-list, .locale-picker-list, .text-size-picker-list)
2592
+ /* Popups open under their button, aligned to its start edge, and flip to
2593
+ its end edge (or above it) when they would run off the viewport. A header
2594
+ picker near the right edge otherwise overflows, and focusing the popup
2595
+ scrolls the whole page sideways. `position: fixed` makes the viewport the
2596
+ containing block that the flip fallbacks are checked against; browsers
2597
+ without anchor positioning keep the absolute placement above. */
2598
+ @supports (position-area: block-end) {
2599
+ :where(.theme-picker) { anchor-name: --lily-theme-picker; }
2600
+ :where(.locale-picker) { anchor-name: --lily-locale-picker; }
2601
+ :where(.text-size-picker) { anchor-name: --lily-text-size-picker; }
2602
+ :where(.motion-picker) { anchor-name: --lily-motion-picker; }
2603
+ :where(.share-picker) { anchor-name: --lily-share-picker; }
2604
+ :where(.search-picker) { anchor-name: --lily-search-picker; }
2605
+ :where(.theme-picker-list) { position-anchor: --lily-theme-picker; }
2606
+ :where(.locale-picker-list) { position-anchor: --lily-locale-picker; }
2607
+ :where(.text-size-picker-list) { position-anchor: --lily-text-size-picker; }
2608
+ :where(.motion-picker-list) { position-anchor: --lily-motion-picker; }
2609
+ :where(.share-picker-list) { position-anchor: --lily-share-picker; }
2610
+ :where(.search-picker-panel) { position-anchor: --lily-search-picker; }
2611
+ :where(
2612
+ .theme-picker-list,
2613
+ .locale-picker-list,
2614
+ .text-size-picker-list,
2615
+ .motion-picker-list,
2616
+ .share-picker-list,
2617
+ .search-picker-panel
2618
+ ) {
2619
+ position: fixed;
2620
+ inset: auto;
2621
+ position-area: block-end span-inline-end;
2622
+ position-try-fallbacks: flip-inline, flip-block, flip-block flip-inline;
2623
+ min-width: 0;
2624
+ width: max-content;
2625
+ max-width: calc(100vw - 1rem);
2626
+ }
2627
+ }
2628
+
2629
+ :where(.theme-picker-list, .locale-picker-list, .text-size-picker-list, .motion-picker-list)
2583
2630
  > :where(
2584
2631
  .theme-picker-option,
2585
2632
  .locale-picker-option,
2586
- .text-size-picker-option
2633
+ .text-size-picker-option,
2634
+ .motion-picker-option
2587
2635
  ) {
2588
2636
  padding: var(--lily-space-xs) var(--lily-space-sm);
2589
2637
  border-radius: var(--lily-radius-sm);
@@ -2592,7 +2640,7 @@
2592
2640
 
2593
2641
  /* data-active is the keyboard cursor (aria-activedescendant); focus
2594
2642
  stays on the listbox, so this is the only visible cue for it. */
2595
- :where(.theme-picker-list, .locale-picker-list, .text-size-picker-list)
2643
+ :where(.theme-picker-list, .locale-picker-list, .text-size-picker-list, .motion-picker-list)
2596
2644
  > :where([data-active]) {
2597
2645
  background-color: var(--lily-surface-alt);
2598
2646
  outline: var(--lily-focus-ring);
@@ -2601,7 +2649,7 @@
2601
2649
 
2602
2650
  /* aria-selected marks the applied theme/locale, which is not the
2603
2651
  same thing as the keyboard cursor. Both can be visible at once. */
2604
- :where(.theme-picker-list, .locale-picker-list, .text-size-picker-list)
2652
+ :where(.theme-picker-list, .locale-picker-list, .text-size-picker-list, .motion-picker-list)
2605
2653
  > :where([aria-selected="true"]) {
2606
2654
  font-weight: 600;
2607
2655
  background-color: var(--lily-surface-sunken);
package/dist/pastel.css CHANGED
@@ -155,6 +155,14 @@
155
155
  /* Primary body-copy colour. Maps to the theme's high-contrast
156
156
  reading colour. */
157
157
  --lily-text: var(--color-base-content);
158
+ /* Error text: the theme's error colour pulled toward the theme's own reading colour (`--color-base-content`, not `--lily-text`, which a host page may override) so it
159
+ keeps WCAG contrast as text on the page and on the error-tinted
160
+ callout surface (`--color-error` itself is a fill colour). */
161
+ --lily-error-text: color-mix(
162
+ in oklch,
163
+ var(--color-error) 22%,
164
+ var(--color-base-content)
165
+ );
158
166
  /* Muted / secondary text — mixed 70% with transparent to keep the
159
167
  hue but lower contrast for captions, helptext, placeholders. */
160
168
  --lily-text-muted: color-mix(
@@ -894,7 +902,7 @@
894
902
  }
895
903
  :where(.dont-list-item)::marker {
896
904
  content: "✗ ";
897
- color: var(--color-error);
905
+ color: var(--lily-error-text);
898
906
  }
899
907
 
900
908
  /* --- Tree --------------------------------------------------------------- */
@@ -976,7 +984,7 @@
976
984
  color: var(--color-success);
977
985
  }
978
986
  :where(.validation-list-item[data-status="failed"]) {
979
- color: var(--color-error);
987
+ color: var(--lily-error-text);
980
988
  }
981
989
  :where(.validation-list-item[data-status="pending"]) {
982
990
  color: var(--lily-text-muted);
@@ -1334,7 +1342,7 @@
1334
1342
 
1335
1343
  /* Error message — inline form-validation message. */
1336
1344
  :where(.error-message) {
1337
- color: var(--color-error);
1345
+ color: var(--lily-error-text);
1338
1346
  font-weight: 600;
1339
1347
  }
1340
1348
  /* Error summary — heavyweight 4px border (GOV.UK pattern) so users
@@ -2548,6 +2556,7 @@
2548
2556
  .theme-picker-list,
2549
2557
  .locale-picker-list,
2550
2558
  .text-size-picker-list,
2559
+ .motion-picker-list,
2551
2560
  .share-picker-list,
2552
2561
  .search-picker-panel
2553
2562
  ) {
@@ -2573,17 +2582,56 @@
2573
2582
  .theme-picker-list,
2574
2583
  .locale-picker-list,
2575
2584
  .text-size-picker-list,
2585
+ .motion-picker-list,
2576
2586
  .share-picker-list,
2577
2587
  .search-picker-panel
2578
2588
  )[hidden] {
2579
2589
  display: none;
2580
2590
  }
2581
2591
 
2582
- :where(.theme-picker-list, .locale-picker-list, .text-size-picker-list)
2592
+ /* Popups open under their button, aligned to its start edge, and flip to
2593
+ its end edge (or above it) when they would run off the viewport. A header
2594
+ picker near the right edge otherwise overflows, and focusing the popup
2595
+ scrolls the whole page sideways. `position: fixed` makes the viewport the
2596
+ containing block that the flip fallbacks are checked against; browsers
2597
+ without anchor positioning keep the absolute placement above. */
2598
+ @supports (position-area: block-end) {
2599
+ :where(.theme-picker) { anchor-name: --lily-theme-picker; }
2600
+ :where(.locale-picker) { anchor-name: --lily-locale-picker; }
2601
+ :where(.text-size-picker) { anchor-name: --lily-text-size-picker; }
2602
+ :where(.motion-picker) { anchor-name: --lily-motion-picker; }
2603
+ :where(.share-picker) { anchor-name: --lily-share-picker; }
2604
+ :where(.search-picker) { anchor-name: --lily-search-picker; }
2605
+ :where(.theme-picker-list) { position-anchor: --lily-theme-picker; }
2606
+ :where(.locale-picker-list) { position-anchor: --lily-locale-picker; }
2607
+ :where(.text-size-picker-list) { position-anchor: --lily-text-size-picker; }
2608
+ :where(.motion-picker-list) { position-anchor: --lily-motion-picker; }
2609
+ :where(.share-picker-list) { position-anchor: --lily-share-picker; }
2610
+ :where(.search-picker-panel) { position-anchor: --lily-search-picker; }
2611
+ :where(
2612
+ .theme-picker-list,
2613
+ .locale-picker-list,
2614
+ .text-size-picker-list,
2615
+ .motion-picker-list,
2616
+ .share-picker-list,
2617
+ .search-picker-panel
2618
+ ) {
2619
+ position: fixed;
2620
+ inset: auto;
2621
+ position-area: block-end span-inline-end;
2622
+ position-try-fallbacks: flip-inline, flip-block, flip-block flip-inline;
2623
+ min-width: 0;
2624
+ width: max-content;
2625
+ max-width: calc(100vw - 1rem);
2626
+ }
2627
+ }
2628
+
2629
+ :where(.theme-picker-list, .locale-picker-list, .text-size-picker-list, .motion-picker-list)
2583
2630
  > :where(
2584
2631
  .theme-picker-option,
2585
2632
  .locale-picker-option,
2586
- .text-size-picker-option
2633
+ .text-size-picker-option,
2634
+ .motion-picker-option
2587
2635
  ) {
2588
2636
  padding: var(--lily-space-xs) var(--lily-space-sm);
2589
2637
  border-radius: var(--lily-radius-sm);
@@ -2592,7 +2640,7 @@
2592
2640
 
2593
2641
  /* data-active is the keyboard cursor (aria-activedescendant); focus
2594
2642
  stays on the listbox, so this is the only visible cue for it. */
2595
- :where(.theme-picker-list, .locale-picker-list, .text-size-picker-list)
2643
+ :where(.theme-picker-list, .locale-picker-list, .text-size-picker-list, .motion-picker-list)
2596
2644
  > :where([data-active]) {
2597
2645
  background-color: var(--lily-surface-alt);
2598
2646
  outline: var(--lily-focus-ring);
@@ -2601,7 +2649,7 @@
2601
2649
 
2602
2650
  /* aria-selected marks the applied theme/locale, which is not the
2603
2651
  same thing as the keyboard cursor. Both can be visible at once. */
2604
- :where(.theme-picker-list, .locale-picker-list, .text-size-picker-list)
2652
+ :where(.theme-picker-list, .locale-picker-list, .text-size-picker-list, .motion-picker-list)
2605
2653
  > :where([aria-selected="true"]) {
2606
2654
  font-weight: 600;
2607
2655
  background-color: var(--lily-surface-sunken);