lostcoords-ui 0.4.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 (93) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +21 -0
  3. data/README.md +352 -0
  4. data/app/assets/tailwind/lostcoords/ui/avatar.css +11 -0
  5. data/app/assets/tailwind/lostcoords/ui/card.css +26 -0
  6. data/app/assets/tailwind/lostcoords/ui/copy-button.css +33 -0
  7. data/app/assets/tailwind/lostcoords/ui/dialog.css +60 -0
  8. data/app/assets/tailwind/lostcoords/ui/disclosure.css +43 -0
  9. data/app/assets/tailwind/lostcoords/ui/emoji-picker.css +462 -0
  10. data/app/assets/tailwind/lostcoords/ui/field.css +6 -0
  11. data/app/assets/tailwind/lostcoords/ui/glass.css +37 -0
  12. data/app/assets/tailwind/lostcoords/ui/layout.css +5 -0
  13. data/app/assets/tailwind/lostcoords/ui/popover.css +75 -0
  14. data/app/assets/tailwind/lostcoords/ui/reading.css +60 -0
  15. data/app/assets/tailwind/lostcoords/ui/sheet.css +170 -0
  16. data/app/assets/tailwind/lostcoords/ui/squircle.css +32 -0
  17. data/app/assets/tailwind/lostcoords/ui/theme.css +255 -0
  18. data/app/assets/tailwind/lostcoords/ui/typography.css +81 -0
  19. data/app/assets/tailwind/lostcoords/ui/ui.css +21 -0
  20. data/app/assets/tailwind/lostcoords/ui/utilities.css +45 -0
  21. data/app/assets/tailwind/lostcoords_ui/engine.css +1 -0
  22. data/app/helpers/lostcoords/ui/badge_helper.rb +162 -0
  23. data/app/helpers/lostcoords/ui/button_helper.rb +70 -0
  24. data/app/helpers/lostcoords/ui/card_helper.rb +60 -0
  25. data/app/helpers/lostcoords/ui/copy_button_helper.rb +40 -0
  26. data/app/helpers/lostcoords/ui/dialog_helper.rb +33 -0
  27. data/app/helpers/lostcoords/ui/emoji_picker_helper.rb +245 -0
  28. data/app/helpers/lostcoords/ui/feedback_helper.rb +30 -0
  29. data/app/helpers/lostcoords/ui/form_helper.rb +93 -0
  30. data/app/helpers/lostcoords/ui/glass_helper.rb +25 -0
  31. data/app/helpers/lostcoords/ui/icon_helper.rb +15 -0
  32. data/app/helpers/lostcoords/ui/layout_helper.rb +60 -0
  33. data/app/helpers/lostcoords/ui/menu_helper.rb +41 -0
  34. data/app/helpers/lostcoords/ui/primitives_helper.rb +152 -0
  35. data/app/helpers/lostcoords/ui/reading_helper.rb +15 -0
  36. data/app/helpers/lostcoords/ui/render_attributes_helper.rb +46 -0
  37. data/app/helpers/lostcoords/ui/sheet_helper.rb +54 -0
  38. data/app/helpers/lostcoords/ui/structures_helper.rb +159 -0
  39. data/app/helpers/lostcoords/ui/tailwind_helper.rb +14 -0
  40. data/app/helpers/lostcoords/ui/translation_helper.rb +13 -0
  41. data/app/helpers/lostcoords/ui/typography_helper.rb +28 -0
  42. data/app/javascript/lostcoords/ui/controllers/confirm_dialog_controller.js +39 -0
  43. data/app/javascript/lostcoords/ui/controllers/disclosure_controller.js +163 -0
  44. data/app/javascript/lostcoords/ui/controllers/emoji_picker_controller.js +366 -0
  45. data/app/javascript/lostcoords/ui/controllers/modal_controller.js +27 -0
  46. data/app/javascript/lostcoords/ui/controllers/row_menu_controller.js +83 -0
  47. data/app/javascript/lostcoords/ui/controllers/sheet_controller.js +422 -0
  48. data/app/javascript/lostcoords/ui/controllers/toast_controller.js +69 -0
  49. data/app/javascript/lostcoords/ui/controllers/ui_copy_controller.js +56 -0
  50. data/app/javascript/lostcoords/ui/controllers/ui_popover_controller.js +17 -0
  51. data/app/javascript/lostcoords/ui/controllers/ui_selection_controller.js +69 -0
  52. data/app/javascript/lostcoords/ui/controllers/ui_toggle_controller.js +13 -0
  53. data/app/javascript/lostcoords/ui/helpers/catalog_picker.js +455 -0
  54. data/app/javascript/lostcoords/ui/helpers/context_dialog.js +29 -0
  55. data/app/javascript/lostcoords/ui/helpers/dialog.js +31 -0
  56. data/app/javascript/lostcoords/ui/helpers/dismiss_stack.js +155 -0
  57. data/app/javascript/lostcoords/ui/helpers/floating_panel.js +108 -0
  58. data/app/javascript/lostcoords/ui/helpers/menu_keys.js +27 -0
  59. data/app/javascript/lostcoords/ui/helpers/sheet_motion.js +13 -0
  60. data/app/javascript/lostcoords/ui/helpers/top_layer.js +102 -0
  61. data/app/javascript/lostcoords/ui/helpers/viewport.js +13 -0
  62. data/app/views/lostcoords/ui/components/_emoji_picker.html.erb +176 -0
  63. data/app/views/lostcoords/ui/components/_emoji_picker_grid.html.erb +29 -0
  64. data/app/views/lostcoords/ui/components/_form_alert.html.erb +4 -0
  65. data/app/views/lostcoords/ui/components/_lc_dialog.html.erb +13 -0
  66. data/app/views/lostcoords/ui/components/_lc_disclosure.html.erb +5 -0
  67. data/app/views/lostcoords/ui/components/_skeleton.html.erb +4 -0
  68. data/app/views/lostcoords/ui/components/_spinner.html.erb +10 -0
  69. data/app/views/lostcoords/ui/components/_ui_floating_panel.html.erb +8 -0
  70. data/config/emoji_search_aliases.yml +146 -0
  71. data/config/emoji_search_names.yml +1917 -0
  72. data/config/emoji_search_names_ja.yml +6902 -0
  73. data/config/helper_renames.json +113 -0
  74. data/config/importmap.rb +3 -0
  75. data/config/locales/en.yml +33 -0
  76. data/config/locales/es.yml +33 -0
  77. data/config/locales/ja.yml +33 -0
  78. data/lib/lostcoords/ui/action_view.rb +10 -0
  79. data/lib/lostcoords/ui/builders.rb +42 -0
  80. data/lib/lostcoords/ui/components.rb +13 -0
  81. data/lib/lostcoords/ui/engine.rb +22 -0
  82. data/lib/lostcoords/ui/helpers.rb +11 -0
  83. data/lib/lostcoords/ui/icons.rb +24 -0
  84. data/lib/lostcoords/ui/rails.rb +3 -0
  85. data/lib/lostcoords/ui/resources.rb +17 -0
  86. data/lib/lostcoords/ui/tokens.rb +14 -0
  87. data/lib/lostcoords/ui/version.rb +5 -0
  88. data/lib/lostcoords/ui.rb +2 -0
  89. data/lib/tasks/lostcoords_ui.rake +15 -0
  90. data/script/migrate_helpers.rb +136 -0
  91. data/vendor/heroicons/LICENSE +21 -0
  92. data/vendor/heroicons/icons.json +1303 -0
  93. metadata +203 -0
@@ -0,0 +1,170 @@
1
+ @layer components {
2
+ @media (width < 40rem) {
3
+ .sheet {
4
+ position: fixed;
5
+
6
+ /* Anchored from the top edge at the screen height it opened at
7
+ (sheet_controller), then lifted by its own height. In-app browsers
8
+ (Brave, Chrome) resize the page under the keyboard; anything hung
9
+ from the bottom edge jumps a frame as they do, but the top holds. */
10
+ inset: var(--sheet-floor, 100dvh) 0 auto;
11
+ translate: 0 -100%;
12
+ margin: 0;
13
+ z-index: var(--z-index-prompt);
14
+ inline-size: 100%;
15
+ max-block-size: calc(var(--sheet-floor, 100dvh) * 0.9);
16
+ overflow-y: auto;
17
+ overscroll-behavior: contain;
18
+ padding-block-end: max(env(safe-area-inset-bottom), 1rem);
19
+ border: 1px solid var(--glass-edge);
20
+ border-start-start-radius: var(--radius-3xl);
21
+ border-start-end-radius: var(--radius-3xl);
22
+
23
+ /* Published as a variable, not just applied, because the sticky chrome
24
+ that rides on top of the sheet — the grabber bar, the pinned action
25
+ row — has to paint the *same* surface or it reads as a seam. In dark
26
+ mode the sheet is a lightened paper-2/paper-3 mix while --paper is
27
+ 0.045 lightness darker, which is exactly the band you could see. */
28
+ --sheet-bg: var(--paper);
29
+ @supports (background: light-dark(white, black)) {
30
+ --sheet-bg: light-dark(var(--paper), color-mix(in oklab, var(--paper-2) 92%, var(--paper-3)));
31
+ }
32
+ background: var(--sheet-bg);
33
+ color: var(--ink);
34
+ box-shadow: 0 -12px 40px -12px color-mix(in oklab, var(--ink) 45%, transparent);
35
+ transform: translateY(var(--sheet-offscreen));
36
+ transition:
37
+ transform var(--sheet-duration) var(--ease-sheet),
38
+ display var(--sheet-duration) allow-discrete,
39
+ overlay var(--sheet-duration) allow-discrete;
40
+ }
41
+
42
+ /* Popover-API reveal (currency): top layer drives display, so showPopover()/
43
+ hidePopover() animate the slide both ways, with a native ::backdrop. */
44
+ .sheet[popover] { display: none; flex-direction: column; max-block-size: min(calc(var(--sheet-floor, 100svh) * 0.72), 34rem); }
45
+ .sheet[popover]:popover-open {
46
+ display: flex;
47
+ transform: translateY(0);
48
+
49
+ @starting-style { transform: translateY(var(--sheet-offscreen)); }
50
+ }
51
+ .sheet[popover]::backdrop {
52
+ background: var(--scrim);
53
+ backdrop-filter: blur(2px);
54
+ opacity: 0;
55
+ transition:
56
+ opacity var(--sheet-duration) var(--ease-sheet),
57
+ display var(--sheet-duration) allow-discrete,
58
+ overlay var(--sheet-duration) allow-discrete;
59
+
60
+ @media (prefers-reduced-motion: reduce) { transition: none; }
61
+ }
62
+ .sheet[popover]:popover-open::backdrop { opacity: 1; @starting-style { opacity: 0; } }
63
+
64
+ /* UIKit's 36×5 grabber. */
65
+ :is([data-sheet-target~="handle"], dialog[data-controller~="sheet"])::before {
66
+ content: "";
67
+ display: block;
68
+ inline-size: 2.25rem;
69
+ block-size: 0.3125rem;
70
+ border-radius: 9999px;
71
+ background: color-mix(in oklab, var(--ink-3) 45%, transparent);
72
+ }
73
+ }
74
+ }
75
+
76
+ @layer modules {
77
+ /* Phones: every modal dialog is an iOS sheet (sheet_controller). It floats
78
+ inset with all corners round while it is short, and docks to the screen
79
+ edges as it reaches the large detent: --sheet-p runs 0 → 1 between them.
80
+ Lives in this layer so it out-ranks a dialog's own frame. */
81
+ @media (width < 40rem) {
82
+ dialog[data-controller~="sheet"] {
83
+ --sheet-p: 0;
84
+ --sheet-inset: 0.5rem;
85
+ --sheet-radius: 2.25rem;
86
+ --sheet-bg: var(--paper);
87
+ --sheet-gap: calc(var(--sheet-inset) * (1 - var(--sheet-p)));
88
+
89
+ position: fixed;
90
+
91
+ /* Anchored from the top edge, like .sheet: the keyboard covers it and
92
+ nothing moves. */
93
+ inset: calc(var(--sheet-floor, 100dvh) - var(--sheet-gap)) 0 auto;
94
+ translate: 0 -100%;
95
+ margin: 0 var(--sheet-gap);
96
+ inline-size: auto;
97
+ max-inline-size: none;
98
+ block-size: auto;
99
+ max-block-size: calc(var(--sheet-floor, 100dvh) - max(env(safe-area-inset-top), 0.75rem) - 0.625rem);
100
+ padding: 0 0 max(0px, calc(env(safe-area-inset-bottom) - var(--sheet-gap)));
101
+ overflow: hidden auto;
102
+ overscroll-behavior: contain;
103
+ scrollbar-width: none;
104
+ border: 1px solid var(--glass-edge);
105
+ border-radius:
106
+ var(--sheet-radius) var(--sheet-radius)
107
+ calc(var(--sheet-radius) * (1 - var(--sheet-p))) calc(var(--sheet-radius) * (1 - var(--sheet-p)));
108
+ background: var(--sheet-bg);
109
+ box-shadow: var(--glass-rim), 0 -8px 40px -12px rgb(0 0 0 / 0.28);
110
+ opacity: 1;
111
+ transform: translateY(var(--sheet-offscreen));
112
+ transform-origin: bottom center;
113
+ transition:
114
+ transform var(--sheet-duration) var(--ease-sheet),
115
+ display var(--sheet-duration) allow-discrete,
116
+ overlay var(--sheet-duration) allow-discrete;
117
+
118
+ &[open] {
119
+ transform: none;
120
+
121
+ @starting-style { transform: translateY(var(--sheet-offscreen)); }
122
+ }
123
+
124
+ &::before {
125
+ position: absolute;
126
+ z-index: calc(var(--z-index-art) + 1);
127
+ inset: 0.3125rem auto auto 50%;
128
+ translate: -50% 0;
129
+ pointer-events: none;
130
+ }
131
+
132
+ &::backdrop {
133
+ background: var(--scrim-sheet);
134
+ backdrop-filter: none;
135
+ opacity: 0;
136
+ transition:
137
+ opacity var(--sheet-duration) var(--ease-sheet),
138
+ display var(--sheet-duration) allow-discrete,
139
+ overlay var(--sheet-duration) allow-discrete;
140
+ }
141
+
142
+ &[open]::backdrop {
143
+ opacity: 1;
144
+
145
+ @starting-style { opacity: 0; }
146
+ }
147
+
148
+ @media (prefers-reduced-motion: reduce) {
149
+ &::backdrop { transition: none; }
150
+ }
151
+ }
152
+
153
+ /* Behind a large sheet the page shrinks back and rounds off, over black,
154
+ as UIKit's page sheet does; sheet_controller drives the variables. */
155
+ html[data-sheet-page] {
156
+ background: #000;
157
+
158
+ > body {
159
+ transform-origin: 50% var(--sheet-page-origin, 0);
160
+ transform:
161
+ translateY(calc(var(--sheet-page-p, 0) * (max(env(safe-area-inset-top), 0.75rem) - 0.25rem)))
162
+ scale(var(--sheet-page-scale, 1));
163
+ clip-path: inset(var(--sheet-page-origin, 0) 0 0 round calc(var(--sheet-page-p, 0) * 0.75rem));
164
+ transition:
165
+ transform var(--sheet-page-transition, 0s),
166
+ clip-path var(--sheet-page-transition, 0s);
167
+ }
168
+ }
169
+ }
170
+ }
@@ -0,0 +1,32 @@
1
+ /* WebKit ignores corner-shape and keeps plain rounded corners. A squircle reads
2
+ tighter than a circular arc of the same radius, so the 12/16/24 tiers grow. */
3
+ @layer theme {
4
+ @supports (corner-shape: squircle) {
5
+ body {
6
+ --radius-xl: 1.125rem;
7
+ --radius-2xl: 1.5rem;
8
+ --radius-3xl: 2rem;
9
+
10
+ & :is(
11
+ [class*="rounded-xl"], [class*="rounded-2xl"], [class*="rounded-3xl"],
12
+ [class*="rounded-t-"], [class*="rounded-b-"],
13
+ [class*="rounded-ss-"], [class*="rounded-se-"],
14
+ [class*="rounded-es-"], [class*="rounded-ee-"],
15
+ [class*="[&_button]:rounded-xl"] button,
16
+ [class*="before:rounded-xl"]::before
17
+ ):not([class*="rounded-full"]) {
18
+ corner-shape: squircle;
19
+ }
20
+ }
21
+ }
22
+ }
23
+
24
+ /* For surfaces whose radius comes from a variable or a stylesheet, which the class
25
+ match above can't see. The card, dialog, menu, badge and picker builders carry it. */
26
+ @utility squircle {
27
+ @supports (corner-shape: squircle) {
28
+ &:not([class*="rounded-full"]) {
29
+ corner-shape: squircle;
30
+ }
31
+ }
32
+ }
@@ -0,0 +1,255 @@
1
+ @theme inline {
2
+ --color-paper: var(--paper);
3
+ --color-paper-2: var(--paper-2);
4
+ --color-paper-3: var(--paper-3);
5
+ --color-ink: var(--ink);
6
+ --color-ink-2: var(--ink-2);
7
+ --color-ink-3: var(--ink-3);
8
+ --color-ink-on-accent: var(--ink-on-accent);
9
+ --color-hairline: var(--hairline);
10
+
11
+ --color-sky: var(--sky);
12
+ --color-sky-deep: var(--sky-deep);
13
+ --color-sky-soft: var(--sky-soft);
14
+ --color-accent: var(--accent);
15
+ --color-leaf: var(--leaf);
16
+ --color-leaf-soft: var(--leaf-soft);
17
+ --color-gold: var(--gold);
18
+ --color-gold-soft: var(--gold-soft);
19
+ --color-berry: var(--berry);
20
+ --color-berry-soft: var(--berry-soft);
21
+ --color-danger: var(--danger);
22
+ --color-danger-soft: var(--danger-soft);
23
+
24
+ --font-display: var(--f-display);
25
+ --font-body: var(--f-body);
26
+ --font-mono: var(--f-mono);
27
+ }
28
+
29
+ @theme {
30
+ --text-xs--line-height: initial;
31
+ --text-sm--line-height: initial;
32
+ --text-base--line-height: initial;
33
+ --text-lg--line-height: initial;
34
+ --text-xl--line-height: initial;
35
+ --text-2xl--line-height: initial;
36
+
37
+ --z-index-above: 1;
38
+ --z-index-raised: 2;
39
+ --z-index-art: 3;
40
+
41
+ --z-index-sticky-action: 10;
42
+ --z-index-float: 10;
43
+
44
+ --z-index-nav: 20;
45
+ --z-index-nav-popover: 30;
46
+ --z-index-popover: 30;
47
+ --z-index-mobile-nav: 40;
48
+ --z-index-mobile-action: 50;
49
+ --z-index-prompt: 51;
50
+
51
+ --z-index-overlay: 60;
52
+ --z-index-overlay-panel: 61;
53
+ --z-index-toast: 70;
54
+
55
+ --ease-out: cubic-bezier(0.3, 0, 0, 1);
56
+ --ease-out-long: cubic-bezier(0.2, 0.7, 0, 1);
57
+ --ease-out-expo: cubic-bezier(0.16, 1, 0.3, 1);
58
+ --ease-sheet: cubic-bezier(0.32, 0.72, 0, 1);
59
+
60
+ --sheet-duration: 500ms;
61
+
62
+ --sheet-offscreen: calc(100% + 2rem);
63
+ --ease-out-overshoot-subtle: cubic-bezier(0.25, 1.25, 0.5, 1);
64
+ --ease-spring: cubic-bezier(0.34, 1.45, 0.64, 1);
65
+ --color-scrim-dock: rgb(10 14 24 / 0.22);
66
+ }
67
+
68
+ @custom-variant dark (&:where(html[data-theme="dark"], html[data-theme="dark"] *));
69
+
70
+ @theme {
71
+ --animate-alert-in: alert-in 360ms var(--ease-out-expo) both;
72
+
73
+ @keyframes alert-in {
74
+ from { opacity: 0; transform: translateY(-0.25rem); }
75
+ }
76
+ }
77
+
78
+ @layer theme {
79
+ :root {
80
+ --ui-motion-quick: 140ms;
81
+ --ui-motion-control: 180ms;
82
+ --ui-motion-feedback: 160ms;
83
+ --ui-press-scale: 0.96;
84
+
85
+ --lch-sky: 55.6% 0.176 256.6;
86
+ --lch-sky-deep: 51.5% 0.169 259.2;
87
+ --lch-leaf: 58.6% 0.089 144.3;
88
+ --lch-gold: 73.8% 0.130 86;
89
+ --lch-berry: 63.5% 0.151 41.4;
90
+
91
+ --paper: oklch(100% 0 0deg);
92
+ --paper-2: oklch(97.6% 0.003 264.5deg);
93
+ --paper-3: oklch(95.2% 0.006 264.5deg);
94
+ --ink: oklch(23.1% 0.010 268.2deg);
95
+ --ink-2: oklch(39.4% 0.012 267deg);
96
+ --ink-3: oklch(52.0% 0.014 267deg);
97
+ --ink-on-accent: #fff;
98
+ --hairline: oklch(93.1% 0.006 264.5deg);
99
+
100
+ --scrim: color-mix(in oklab, var(--ink) 55%, transparent);
101
+ --scrim-soft: color-mix(in oklab, var(--ink) 12%, transparent);
102
+
103
+ --scrim-sheet: rgb(0 0 0 / 0.28);
104
+
105
+ --sky: oklch(var(--lch-sky));
106
+ --sky-deep: oklch(var(--lch-sky-deep));
107
+ --sky-soft: oklch(95.2% 0.023 258.4deg);
108
+ --accent: var(--sky-deep);
109
+
110
+ --leaf: oklch(var(--lch-leaf));
111
+ --leaf-soft: oklch(95.0% 0.015 136deg);
112
+ --gold: oklch(var(--lch-gold));
113
+ --gold-soft: oklch(95.5% 0.040 88deg);
114
+ --berry: oklch(var(--lch-berry));
115
+ --berry-soft: oklch(95.4% 0.020 58deg);
116
+ --danger: var(--berry);
117
+ --danger-soft: var(--berry-soft);
118
+
119
+ --f-display: ui-sans-serif, system-ui, sans-serif;
120
+ --f-body: ui-sans-serif, system-ui, sans-serif;
121
+ --f-japanese: "Hiragino Sans", "Yu Gothic", "YuGothic", "Meiryo", ui-sans-serif, system-ui, sans-serif;
122
+ --f-mono: ui-monospace, "SFMono-Regular", "SF Mono", menlo, consolas, monospace;
123
+
124
+ --shadow-sm: 0 1px 2px rgb(16 24 40 / 0.05);
125
+ --shadow:
126
+ 0 1px 3px rgb(16 24 40 / 0.05),
127
+ 0 8px 24px -8px rgb(16 24 40 / 0.09);
128
+ --shadow-lg:
129
+ 0 1px 3px rgb(16 24 40 / 0.06),
130
+ 0 24px 48px -12px rgb(16 24 40 / 0.18);
131
+
132
+ --glass-fill: color-mix(in oklab, var(--paper) 74%, transparent);
133
+ --glass-edge: rgb(255 255 255 / 0.4);
134
+ --glass-bar-edge: var(--glass-edge);
135
+ --glass-rim:
136
+ inset 0 1px 0 rgb(255 255 255 / 0.6),
137
+ inset 0 0 0 1px rgb(255 255 255 / 0.22);
138
+ --glass-shadow: var(--glass-rim), var(--shadow);
139
+
140
+ --glass-hud-fill:
141
+ linear-gradient(rgb(255 255 255 / 0.6), rgb(255 255 255 / 0) 60%),
142
+ color-mix(in oklab, var(--paper) 82%, transparent);
143
+ --glass-hud-ink: var(--ink);
144
+ --glass-hud-solid: var(--paper);
145
+ --glass-hud-shadow:
146
+ inset 0 0 0 1px rgb(16 24 40 / 0.08),
147
+ 0 1px 2px rgb(16 24 40 / 0.06),
148
+ 0 6px 16px -6px rgb(16 24 40 / 0.16);
149
+
150
+ --pill-rim: linear-gradient(135deg, #fff 0%, #dcdce0 30%, #f7f7f8 55%, #c9c9ce 100%);
151
+ --pill-surface: linear-gradient(#fff, #f1f1f4);
152
+ --pill-light: inset 0 1px 0 #fff, inset 0 -1px 1px rgb(0 0 0 / 0.06);
153
+ --pill-depth: 0 1px 1px rgb(0 0 0 / 0.08), 0 8px 18px -6px rgb(0 0 0 / 0.18);
154
+
155
+ --focus-halo-color: color-mix(in oklab, var(--sky) 50%, transparent);
156
+ --focus-halo: 0 0 0 calc(var(--spacing) * 0.5) var(--focus-halo-color);
157
+
158
+ color-scheme: light;
159
+
160
+ }
161
+
162
+ html:lang(ja) {
163
+ --f-display: var(--f-japanese);
164
+ --f-body: var(--f-japanese);
165
+ }
166
+
167
+ html[data-theme="dark"] {
168
+ color-scheme: dark;
169
+
170
+ --paper: oklch(20.5% 0.002 75deg);
171
+ --paper-2: oklch(24.2% 0.003 75deg);
172
+ --paper-3: oklch(28.4% 0.004 75deg);
173
+ --ink: oklch(91.5% 0.006 85deg);
174
+ --ink-2: color-mix(in oklab, var(--ink) 76%, var(--paper));
175
+ --ink-3: color-mix(in oklab, var(--ink) 68%, var(--paper));
176
+ --hairline: color-mix(in oklab, var(--ink) 16%, transparent);
177
+
178
+ --scrim: rgb(0 0 0 / 0.6);
179
+ --scrim-soft: rgb(0 0 0 / 0.32);
180
+
181
+ --ink-on-accent: var(--paper);
182
+ --sky: oklch(65.5% 0.150 255deg);
183
+ --sky-deep: oklch(61.5% 0.155 257deg);
184
+ --sky-soft: color-mix(in oklab, var(--sky) 18%, var(--paper));
185
+ --accent: var(--sky);
186
+
187
+ --leaf-soft: color-mix(in oklab, var(--leaf) 16%, var(--paper));
188
+ --gold-soft: color-mix(in oklab, var(--gold) 16%, var(--paper));
189
+ --berry-soft: color-mix(in oklab, var(--berry) 16%, var(--paper));
190
+
191
+ --shadow-sm: 0 1px 2px rgb(0 0 0 / 0.2);
192
+ --shadow:
193
+ 0 1px 2px rgb(0 0 0 / 0.16),
194
+ 0 8px 24px -8px rgb(0 0 0 / 0.32);
195
+ --shadow-lg:
196
+ 0 1px 3px rgb(0 0 0 / 0.2),
197
+ 0 24px 48px -12px rgb(0 0 0 / 0.55);
198
+
199
+ --glass-fill: color-mix(in oklab, var(--paper) 80%, transparent);
200
+ --glass-edge: transparent;
201
+ --glass-rim: 0 0 #0000;
202
+ --glass-bar-edge: rgb(255 255 255 / 0.06);
203
+ --glass-shadow: 0 1px 3px rgb(0 0 0 / 0.04), 0 4px 12px rgb(0 0 0 / 0.03);
204
+ --glass-hud-fill:
205
+ linear-gradient(rgb(255 255 255 / 0.06), rgb(255 255 255 / 0) 60%),
206
+ color-mix(in oklab, var(--paper-3) 90%, transparent);
207
+ --glass-hud-solid: var(--paper-3);
208
+ --glass-hud-shadow:
209
+ inset 0 1px 0 rgb(255 255 255 / 0.1),
210
+ inset 0 0 0 1px rgb(255 255 255 / 0.1),
211
+ 0 8px 20px -8px rgb(0 0 0 / 0.6);
212
+
213
+ --pill-rim: linear-gradient(135deg, rgb(255 255 255 / 0.22) 0%, rgb(255 255 255 / 0.06) 30%, rgb(255 255 255 / 0.12) 55%, rgb(0 0 0 / 0.3) 100%);
214
+ --pill-surface: linear-gradient(var(--paper-3), var(--paper-2));
215
+ --pill-light: inset 0 1px 0 rgb(255 255 255 / 0.08), inset 0 -1px 1px rgb(0 0 0 / 0.2);
216
+ --pill-depth: 0 1px 1px rgb(0 0 0 / 0.3), 0 8px 18px -6px rgb(0 0 0 / 0.5);
217
+ }
218
+ }
219
+
220
+ @layer base {
221
+ body {
222
+ background-color: var(--paper);
223
+ color: var(--ink);
224
+ font-family: var(--f-body);
225
+ line-height: 1.5;
226
+ }
227
+
228
+ :is(h1, h2, h3, h4, h5) {
229
+ font-family: var(--f-display);
230
+ line-height: 1.2;
231
+ color: var(--ink);
232
+ }
233
+
234
+ button { cursor: pointer; background: none; }
235
+
236
+ dialog { background: transparent; color: inherit; }
237
+
238
+ :where([popover]) { color: inherit; }
239
+
240
+ :is(a, button, input, textarea, select, summary, [tabindex]):focus-visible,
241
+ label:has(input.sr-only:focus-visible) {
242
+ outline: calc(var(--spacing) * 0.5) solid var(--focus-halo-color);
243
+ outline-offset: 0;
244
+ }
245
+
246
+ dialog:focus-visible { outline: none; }
247
+
248
+ @media (prefers-reduced-motion: reduce) {
249
+ *, *::before, *::after {
250
+ animation-duration: 0.01ms !important;
251
+ animation-iteration-count: 1 !important;
252
+ transition-duration: 0.01ms !important;
253
+ }
254
+ }
255
+ }
@@ -0,0 +1,81 @@
1
+ @layer components {
2
+ :where(.ui-heading) {
3
+ font-family: var(--font-display, var(--font-body, inherit));
4
+ font-weight: var(--ui-heading-weight, 700);
5
+ letter-spacing: var(--ui-heading-tracking, -0.025em);
6
+ overflow-wrap: anywhere;
7
+ text-wrap: balance;
8
+ }
9
+
10
+ :where(.ui-heading-page) {
11
+ font-size: var(--ui-heading-page-size, 1.875rem);
12
+ line-height: var(--ui-heading-page-line-height, 2.25rem);
13
+ }
14
+
15
+ :where(.ui-heading-section) {
16
+ font-size: var(--ui-heading-section-size, 1.25rem);
17
+ line-height: var(--ui-heading-section-line-height, 1.5rem);
18
+ }
19
+
20
+ :where(.ui-heading-card) {
21
+ font-size: var(--ui-heading-card-size, 1.125rem);
22
+ line-height: var(--ui-heading-card-line-height, 1.5rem);
23
+ }
24
+
25
+ :where(.ui-heading:lang(ja)) {
26
+ letter-spacing: var(--ui-heading-ja-tracking, 0);
27
+ line-break: strict;
28
+ }
29
+
30
+ :where(.ui-text) {
31
+ font-family: var(--font-body, inherit);
32
+ font-weight: var(--ui-text-weight, 400);
33
+ letter-spacing: var(--ui-text-tracking, normal);
34
+ overflow-wrap: anywhere;
35
+ }
36
+
37
+ :where(.ui-text-body) {
38
+ font-size: var(--ui-text-body-size, 1rem);
39
+ line-height: var(--ui-text-body-line-height, 1.5rem);
40
+ }
41
+
42
+ :where(.ui-text-small) {
43
+ font-size: var(--ui-text-small-size, 0.875rem);
44
+ line-height: var(--ui-text-small-line-height, 1.25rem);
45
+ }
46
+
47
+ :where(.ui-text-caption) {
48
+ font-size: var(--ui-text-caption-size, 0.75rem);
49
+ line-height: var(--ui-text-caption-line-height, 1rem);
50
+ }
51
+
52
+ :where(.ui-text:lang(ja)) {
53
+ line-break: strict;
54
+ }
55
+
56
+ @supports (word-break: auto-phrase) {
57
+ :where(.ui-heading:lang(ja)) {
58
+ word-break: auto-phrase;
59
+ }
60
+ }
61
+ }
62
+
63
+ @layer utilities {
64
+ :where(code):not(:where(pre code)),
65
+ .ui-prose :where(code):not(:where(pre code)) {
66
+ font-family: var(--f-mono);
67
+ font-size: 0.875em;
68
+ font-weight: inherit;
69
+ line-height: inherit;
70
+ color: var(--ink);
71
+ background-color: var(--paper-3);
72
+ border-radius: var(--radius-sm);
73
+ padding: 0.125em 0.375em;
74
+ overflow-wrap: anywhere;
75
+
76
+ &::before,
77
+ &::after {
78
+ content: none;
79
+ }
80
+ }
81
+ }
@@ -0,0 +1,21 @@
1
+ @import "./theme.css";
2
+ @source "../../../../helpers/**/*.rb";
3
+ @source "../../../../javascript/**/*.js";
4
+ @source "../../../../views/**/*.erb";
5
+ @source not "../../../../../lib";
6
+
7
+ @import "./glass.css";
8
+ @import "./copy-button.css";
9
+ @import "./disclosure.css";
10
+ @import "./emoji-picker.css";
11
+ @import "./popover.css";
12
+ @import "./sheet.css";
13
+ @import "./card.css";
14
+ @import "./dialog.css";
15
+ @import "./avatar.css";
16
+ @import "./squircle.css";
17
+ @import "./utilities.css";
18
+ @import "./typography.css";
19
+ @import "./layout.css";
20
+ @import "./reading.css";
21
+ @import "./field.css";
@@ -0,0 +1,45 @@
1
+ /* The rim is the border box painted with --pill-rim under the surface, so
2
+ one element carries both layers. */
3
+ @utility pill-3d {
4
+ border: calc(var(--spacing) * 0.375) solid transparent;
5
+ background: var(--pill-surface) padding-box, var(--pill-rim) border-box;
6
+ box-shadow: var(--pill-light), var(--pill-depth);
7
+ }
8
+
9
+ /* A control gives a little as it is pressed, unless it is disabled. */
10
+ @utility press {
11
+ @media (prefers-reduced-motion: no-preference) {
12
+ &:not([disabled], :disabled, [aria-disabled="true"]):active {
13
+ transform: scale(var(--press-scale, var(--ui-press-scale)));
14
+ }
15
+ }
16
+ }
17
+
18
+ @layer components {
19
+ /* A data-URI image cannot read CSS variables, so the chevron's ink is baked in. */
20
+ select.select-control {
21
+ appearance: none;
22
+ background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20' fill='none' stroke='%237b808a' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 8 4 4 4-4'/%3E%3C/svg%3E");
23
+ background-size: calc(var(--spacing) * 5) calc(var(--spacing) * 5);
24
+ background-repeat: no-repeat;
25
+ background-position: right calc(var(--spacing) * 4) center;
26
+ }
27
+ }
28
+
29
+ @property --scroll-fade-start { syntax: "<length>"; inherits: false; initial-value: 0; }
30
+ @property --scroll-fade-end { syntax: "<length>"; inherits: false; initial-value: 0; }
31
+
32
+ @keyframes scroll-fade-x {
33
+ 0% { --scroll-fade-start: 0; --scroll-fade-end: 2rem; }
34
+ 15% { --scroll-fade-start: 2rem; }
35
+ 85% { --scroll-fade-end: 2rem; }
36
+ 100% { --scroll-fade-start: 2rem; --scroll-fade-end: 0; }
37
+ }
38
+
39
+ @supports (animation-timeline: scroll(self inline)) {
40
+ .scroll-fade-x {
41
+ mask-image: linear-gradient(to right, transparent, black var(--scroll-fade-start), black calc(100% - var(--scroll-fade-end)), transparent);
42
+ animation: scroll-fade-x linear both;
43
+ animation-timeline: scroll(self inline);
44
+ }
45
+ }
@@ -0,0 +1 @@
1
+ @import "../lostcoords/ui/ui.css";