@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/retro.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/silk.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/sunset.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);
@@ -160,6 +160,14 @@
160
160
  /* Primary body-copy colour. Maps to the theme's high-contrast
161
161
  reading colour. */
162
162
  --lily-text: var(--color-base-content);
163
+ /* 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
164
+ keeps WCAG contrast as text on the page and on the error-tinted
165
+ callout surface (`--color-error` itself is a fill colour). */
166
+ --lily-error-text: color-mix(
167
+ in oklch,
168
+ var(--color-error) 22%,
169
+ var(--color-base-content)
170
+ );
163
171
  /* Muted / secondary text — mixed 70% with transparent to keep the
164
172
  hue but lower contrast for captions, helptext, placeholders. */
165
173
  --lily-text-muted: color-mix(
@@ -899,7 +907,7 @@
899
907
  }
900
908
  :where(.dont-list-item)::marker {
901
909
  content: "✗ ";
902
- color: var(--color-error);
910
+ color: var(--lily-error-text);
903
911
  }
904
912
 
905
913
  /* --- Tree --------------------------------------------------------------- */
@@ -981,7 +989,7 @@
981
989
  color: var(--color-success);
982
990
  }
983
991
  :where(.validation-list-item[data-status="failed"]) {
984
- color: var(--color-error);
992
+ color: var(--lily-error-text);
985
993
  }
986
994
  :where(.validation-list-item[data-status="pending"]) {
987
995
  color: var(--lily-text-muted);
@@ -1339,7 +1347,7 @@
1339
1347
 
1340
1348
  /* Error message — inline form-validation message. */
1341
1349
  :where(.error-message) {
1342
- color: var(--color-error);
1350
+ color: var(--lily-error-text);
1343
1351
  font-weight: 600;
1344
1352
  }
1345
1353
  /* Error summary — heavyweight 4px border (GOV.UK pattern) so users
@@ -2553,6 +2561,7 @@
2553
2561
  .theme-picker-list,
2554
2562
  .locale-picker-list,
2555
2563
  .text-size-picker-list,
2564
+ .motion-picker-list,
2556
2565
  .share-picker-list,
2557
2566
  .search-picker-panel
2558
2567
  ) {
@@ -2578,17 +2587,56 @@
2578
2587
  .theme-picker-list,
2579
2588
  .locale-picker-list,
2580
2589
  .text-size-picker-list,
2590
+ .motion-picker-list,
2581
2591
  .share-picker-list,
2582
2592
  .search-picker-panel
2583
2593
  )[hidden] {
2584
2594
  display: none;
2585
2595
  }
2586
2596
 
2587
- :where(.theme-picker-list, .locale-picker-list, .text-size-picker-list)
2597
+ /* Popups open under their button, aligned to its start edge, and flip to
2598
+ its end edge (or above it) when they would run off the viewport. A header
2599
+ picker near the right edge otherwise overflows, and focusing the popup
2600
+ scrolls the whole page sideways. `position: fixed` makes the viewport the
2601
+ containing block that the flip fallbacks are checked against; browsers
2602
+ without anchor positioning keep the absolute placement above. */
2603
+ @supports (position-area: block-end) {
2604
+ :where(.theme-picker) { anchor-name: --lily-theme-picker; }
2605
+ :where(.locale-picker) { anchor-name: --lily-locale-picker; }
2606
+ :where(.text-size-picker) { anchor-name: --lily-text-size-picker; }
2607
+ :where(.motion-picker) { anchor-name: --lily-motion-picker; }
2608
+ :where(.share-picker) { anchor-name: --lily-share-picker; }
2609
+ :where(.search-picker) { anchor-name: --lily-search-picker; }
2610
+ :where(.theme-picker-list) { position-anchor: --lily-theme-picker; }
2611
+ :where(.locale-picker-list) { position-anchor: --lily-locale-picker; }
2612
+ :where(.text-size-picker-list) { position-anchor: --lily-text-size-picker; }
2613
+ :where(.motion-picker-list) { position-anchor: --lily-motion-picker; }
2614
+ :where(.share-picker-list) { position-anchor: --lily-share-picker; }
2615
+ :where(.search-picker-panel) { position-anchor: --lily-search-picker; }
2616
+ :where(
2617
+ .theme-picker-list,
2618
+ .locale-picker-list,
2619
+ .text-size-picker-list,
2620
+ .motion-picker-list,
2621
+ .share-picker-list,
2622
+ .search-picker-panel
2623
+ ) {
2624
+ position: fixed;
2625
+ inset: auto;
2626
+ position-area: block-end span-inline-end;
2627
+ position-try-fallbacks: flip-inline, flip-block, flip-block flip-inline;
2628
+ min-width: 0;
2629
+ width: max-content;
2630
+ max-width: calc(100vw - 1rem);
2631
+ }
2632
+ }
2633
+
2634
+ :where(.theme-picker-list, .locale-picker-list, .text-size-picker-list, .motion-picker-list)
2588
2635
  > :where(
2589
2636
  .theme-picker-option,
2590
2637
  .locale-picker-option,
2591
- .text-size-picker-option
2638
+ .text-size-picker-option,
2639
+ .motion-picker-option
2592
2640
  ) {
2593
2641
  padding: var(--lily-space-xs) var(--lily-space-sm);
2594
2642
  border-radius: var(--lily-radius-sm);
@@ -2597,7 +2645,7 @@
2597
2645
 
2598
2646
  /* data-active is the keyboard cursor (aria-activedescendant); focus
2599
2647
  stays on the listbox, so this is the only visible cue for it. */
2600
- :where(.theme-picker-list, .locale-picker-list, .text-size-picker-list)
2648
+ :where(.theme-picker-list, .locale-picker-list, .text-size-picker-list, .motion-picker-list)
2601
2649
  > :where([data-active]) {
2602
2650
  background-color: var(--lily-surface-alt);
2603
2651
  outline: var(--lily-focus-ring);
@@ -2606,7 +2654,7 @@
2606
2654
 
2607
2655
  /* aria-selected marks the applied theme/locale, which is not the
2608
2656
  same thing as the keyboard cursor. Both can be visible at once. */
2609
- :where(.theme-picker-list, .locale-picker-list, .text-size-picker-list)
2657
+ :where(.theme-picker-list, .locale-picker-list, .text-size-picker-list, .motion-picker-list)
2610
2658
  > :where([aria-selected="true"]) {
2611
2659
  font-weight: 600;
2612
2660
  background-color: var(--lily-surface-sunken);