@ponchia/ui 0.2.0 → 0.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/css/fonts.css CHANGED
@@ -58,3 +58,14 @@
58
58
  font-display: swap;
59
59
  src: url('../fonts/doto-900.ttf') format('truetype');
60
60
  }
61
+
62
+ /* Data-saver: never *use* Doto, so the browser never fetches it. The
63
+ webfont is only requested when matched to rendered text, so pointing
64
+ --display / --dot-font at the system mono stack opts the whole
65
+ payload out under prefers-reduced-data (same lever as self-hosting). */
66
+ @media (prefers-reduced-data: reduce) {
67
+ :root {
68
+ --display: var(--mono);
69
+ --dot-font: var(--mono);
70
+ }
71
+ }
package/css/forms.css CHANGED
@@ -29,7 +29,7 @@
29
29
  transition:
30
30
  border-color var(--duration-fast) var(--ease-standard),
31
31
  background-color var(--duration-fast) var(--ease-standard);
32
- width: 100%;
32
+ inline-size: 100%;
33
33
  }
34
34
 
35
35
  .ui-input::placeholder,
@@ -38,7 +38,7 @@
38
38
  }
39
39
 
40
40
  .ui-textarea {
41
- min-height: 6rem;
41
+ min-block-size: 6rem;
42
42
  resize: vertical;
43
43
  }
44
44
 
@@ -48,7 +48,12 @@
48
48
  background-position: right 0.75rem center;
49
49
  background-repeat: no-repeat;
50
50
  background-size: 5px 5px;
51
- padding-right: 1.8rem;
51
+ padding-inline-end: 1.8rem;
52
+ }
53
+
54
+ /* background-position has no logical form — mirror the marker for RTL. */
55
+ [dir='rtl'] .ui-select {
56
+ background-position: left 0.75rem center;
52
57
  }
53
58
 
54
59
  .ui-input:focus,
@@ -103,8 +108,8 @@
103
108
  border-radius: 50%;
104
109
  content: '';
105
110
  flex: 0 0 auto;
106
- height: 0.42rem;
107
- width: 0.42rem;
111
+ block-size: 0.42rem;
112
+ inline-size: 0.42rem;
108
113
  }
109
114
 
110
115
  .ui-search:focus-within {
@@ -123,7 +128,7 @@
123
128
  font-size: var(--text-sm);
124
129
  outline: none;
125
130
  padding: 0.6rem 0;
126
- width: 100%;
131
+ inline-size: 100%;
127
132
  }
128
133
 
129
134
  /* Toggle switch — square Nothing-style track. */
@@ -145,22 +150,22 @@
145
150
  border: 1px solid var(--line-strong);
146
151
  border-radius: var(--radius-pill);
147
152
  display: inline-flex;
148
- height: 1.05rem;
153
+ block-size: 1.05rem;
149
154
  padding: 2px;
150
155
  transition:
151
156
  background-color var(--duration-fast) var(--ease-standard),
152
157
  border-color var(--duration-fast) var(--ease-standard);
153
- width: 1.95rem;
158
+ inline-size: 1.95rem;
154
159
  }
155
160
 
156
161
  .ui-switch__thumb {
157
162
  background: var(--text-dim);
158
163
  border-radius: 50%;
159
- height: 100%;
164
+ block-size: 100%;
160
165
  transition:
161
166
  transform var(--duration-fast) var(--ease-spring),
162
167
  background-color var(--duration-fast) var(--ease-standard);
163
- width: 0.78rem;
168
+ inline-size: 0.78rem;
164
169
  }
165
170
 
166
171
  .ui-switch input:checked + .ui-switch__track {
@@ -173,6 +178,10 @@
173
178
  transform: translateX(0.9rem);
174
179
  }
175
180
 
181
+ [dir='rtl'] .ui-switch input:checked + .ui-switch__track .ui-switch__thumb {
182
+ transform: translateX(-0.9rem);
183
+ }
184
+
176
185
  .ui-switch input:focus-visible + .ui-switch__track {
177
186
  outline: 2px solid var(--accent);
178
187
  outline-offset: 2px;
@@ -189,6 +198,24 @@
189
198
 
190
199
  .ui-check input {
191
200
  accent-color: var(--accent);
192
- height: 1rem;
193
- width: 1rem;
201
+ block-size: 1rem;
202
+ inline-size: 1rem;
203
+ }
204
+
205
+ /* Touch: comfortable hit targets on coarse pointers. */
206
+ @media (pointer: coarse) {
207
+ .ui-input,
208
+ .ui-select,
209
+ .ui-textarea {
210
+ min-block-size: 2.9rem;
211
+ }
212
+
213
+ .ui-search {
214
+ min-block-size: 2.9rem;
215
+ }
216
+
217
+ .ui-check input {
218
+ block-size: 1.15rem;
219
+ inline-size: 1.15rem;
220
+ }
194
221
  }
package/css/layout.css CHANGED
@@ -13,7 +13,7 @@
13
13
 
14
14
  .site-shell {
15
15
  margin: 0 auto;
16
- max-width: 1320px;
16
+ max-inline-size: 1320px;
17
17
  padding: 0.9rem;
18
18
  position: relative;
19
19
  z-index: 1;
@@ -56,7 +56,7 @@
56
56
  margin: 0 auto 0.9rem;
57
57
  padding: 0.55rem 0.65rem;
58
58
  position: sticky;
59
- top: 0.65rem;
59
+ inset-block-start: 0.65rem;
60
60
  z-index: 10;
61
61
  }
62
62
 
@@ -92,7 +92,7 @@
92
92
  display: flex;
93
93
  gap: 1rem;
94
94
  justify-content: space-between;
95
- margin-top: 1rem;
95
+ margin-block-start: 1rem;
96
96
  padding: 0.85rem 1rem;
97
97
  }
98
98
 
@@ -133,11 +133,11 @@
133
133
  .page-head,
134
134
  .post-shell {
135
135
  border-radius: var(--radius-xl);
136
- max-width: 100%;
136
+ max-inline-size: 100%;
137
137
  overflow: hidden;
138
138
  padding: 1.35rem;
139
139
  position: relative;
140
- width: 100%;
140
+ inline-size: 100%;
141
141
  }
142
142
 
143
143
  .hero {
package/css/motion.css CHANGED
@@ -148,6 +148,30 @@
148
148
  }
149
149
  }
150
150
 
151
+ /* Indeterminate progress: a short segment sweeps the track. */
152
+ @keyframes uiTrack {
153
+ 0% {
154
+ inset-inline-start: -45%;
155
+ }
156
+
157
+ 100% {
158
+ inset-inline-start: 100%;
159
+ }
160
+ }
161
+
162
+ /* Toast / overlay entrance: rise + fade, spring-tipped. */
163
+ @keyframes uiToastIn {
164
+ from {
165
+ opacity: 0;
166
+ transform: translateY(12px) scale(0.98);
167
+ }
168
+
169
+ to {
170
+ opacity: 1;
171
+ transform: translateY(0) scale(1);
172
+ }
173
+ }
174
+
151
175
  /* --- Utilities --- */
152
176
 
153
177
  .ui-animate-in {
@@ -229,23 +253,23 @@
229
253
  animation: uiShimmer 1.4s linear infinite;
230
254
  border-radius: var(--radius-sm);
231
255
  color: transparent;
232
- min-height: 0.8em;
256
+ min-block-size: 0.8em;
233
257
  }
234
258
 
235
259
  .ui-spinner {
236
260
  animation: uiSpin 0.7s linear infinite;
237
261
  border: 2px solid var(--line);
238
262
  border-radius: 50%;
239
- border-top-color: var(--accent);
263
+ border-block-start-color: var(--accent);
240
264
  display: inline-block;
241
- height: 1.1rem;
242
- width: 1.1rem;
265
+ block-size: 1.1rem;
266
+ inline-size: 1.1rem;
243
267
  }
244
268
 
245
269
  .ui-caret::after {
246
270
  animation: uiBlink 1.1s steps(1) infinite;
247
271
  content: '▮';
248
- margin-left: 0.1em;
272
+ margin-inline-start: 0.1em;
249
273
  }
250
274
 
251
275
  @media (prefers-reduced-motion: reduce) {
@@ -1,6 +1,6 @@
1
1
  /* ==========================================================================
2
2
  navigation — site nav, menu, theme toggle (Nothing flat, dot indicator)
3
- Class names preserved for personal-site compatibility.
3
+ Class names kept stable for site-nav compatibility.
4
4
  ========================================================================== */
5
5
 
6
6
  .site-menu {
@@ -23,7 +23,7 @@
23
23
  gap: 0.4rem;
24
24
  letter-spacing: var(--tracking-wide);
25
25
  list-style: none;
26
- min-height: 2rem;
26
+ min-block-size: 2rem;
27
27
  padding: 0.42rem 0.66rem;
28
28
  text-transform: uppercase;
29
29
  transition:
@@ -35,7 +35,7 @@
35
35
 
36
36
  .theme-toggle__button {
37
37
  justify-content: center;
38
- min-width: 7rem;
38
+ min-inline-size: 7rem;
39
39
  }
40
40
 
41
41
  .site-menu__toggle::-webkit-details-marker {
@@ -63,21 +63,21 @@
63
63
  border: 1px solid var(--line-strong);
64
64
  border-radius: var(--radius-pill);
65
65
  display: inline-flex;
66
- height: 0.8rem;
66
+ block-size: 0.8rem;
67
67
  padding: 0.12rem;
68
- width: 1.5rem;
68
+ inline-size: 1.5rem;
69
69
  }
70
70
 
71
71
  .theme-toggle__thumb {
72
72
  background: var(--text-dim);
73
73
  border-radius: 50%;
74
74
  display: block;
75
- height: 100%;
75
+ block-size: 100%;
76
76
  transform: translateX(0);
77
77
  transition:
78
78
  background-color var(--duration-fast) var(--ease-standard),
79
79
  transform var(--duration-fast) var(--ease-spring);
80
- width: 0.56rem;
80
+ inline-size: 0.56rem;
81
81
  }
82
82
 
83
83
  [data-theme='dark'] .theme-toggle__thumb {
@@ -85,6 +85,11 @@
85
85
  transform: translateX(0.6rem);
86
86
  }
87
87
 
88
+ [dir='rtl'][data-theme='dark'] .theme-toggle__thumb,
89
+ [dir='rtl'] [data-theme='dark'] .theme-toggle__thumb {
90
+ transform: translateX(-0.6rem);
91
+ }
92
+
88
93
  .site-nav {
89
94
  display: inline-flex;
90
95
  gap: 0.15rem;
@@ -114,13 +119,13 @@
114
119
  background: currentColor;
115
120
  border-radius: 50%;
116
121
  content: '';
117
- height: 0.32rem;
122
+ block-size: 0.32rem;
118
123
  opacity: 0;
119
124
  transform: scale(0.5);
120
125
  transition:
121
126
  opacity var(--duration-fast) var(--ease-standard),
122
127
  transform var(--duration-fast) var(--ease-spring);
123
- width: 0.32rem;
128
+ inline-size: 0.32rem;
124
129
  }
125
130
 
126
131
  .site-nav a:hover,
@@ -0,0 +1,198 @@
1
+ /* ==========================================================================
2
+ overlay — modal / drawer / dropdown menu
3
+ Built on native <dialog> and <details> so the framework stays
4
+ CSS-first; the optional initDialog behavior only adds open/close glue.
5
+ ========================================================================== */
6
+
7
+ /* --- Modal — style the native <dialog> --- */
8
+
9
+ .ui-modal {
10
+ background: var(--panel-strong);
11
+ border: 1px solid var(--line-strong);
12
+ border-radius: var(--radius-lg);
13
+ box-shadow: var(--shadow-raised);
14
+ color: var(--text);
15
+ margin: auto;
16
+ max-block-size: min(85vh, 44rem);
17
+ max-inline-size: min(32rem, calc(100vw - 2rem));
18
+ overflow: hidden;
19
+ padding: 0;
20
+ inline-size: 100%;
21
+ }
22
+
23
+ .ui-modal::backdrop {
24
+ backdrop-filter: blur(2px);
25
+ background: color-mix(in srgb, var(--bg) 70%, transparent);
26
+ }
27
+
28
+ .ui-modal[open] {
29
+ animation: uiToastIn var(--duration-base) var(--ease-spring) both;
30
+ display: grid;
31
+ grid-template-rows: auto 1fr auto;
32
+ }
33
+
34
+ .ui-modal__head {
35
+ align-items: flex-start;
36
+ border-block-end: 1px solid var(--line);
37
+ display: flex;
38
+ gap: var(--space-sm);
39
+ justify-content: space-between;
40
+ padding: var(--space-md);
41
+ }
42
+
43
+ .ui-modal__title {
44
+ color: var(--text);
45
+ font-family: var(--display);
46
+ font-size: var(--text-lg);
47
+ letter-spacing: var(--tracking-wide);
48
+ margin: 0;
49
+ text-transform: uppercase;
50
+ }
51
+
52
+ .ui-modal__body {
53
+ overflow-y: auto;
54
+ padding: var(--space-md);
55
+ }
56
+
57
+ .ui-modal__foot {
58
+ border-block-start: 1px solid var(--line);
59
+ display: flex;
60
+ flex-wrap: wrap;
61
+ gap: var(--space-xs);
62
+ justify-content: flex-end;
63
+ padding: var(--space-md);
64
+ }
65
+
66
+ .ui-modal__close {
67
+ background: transparent;
68
+ border: 1px solid var(--line-strong);
69
+ border-radius: var(--radius-md);
70
+ color: var(--text);
71
+ cursor: pointer;
72
+ flex: 0 0 auto;
73
+ font-family: var(--mono);
74
+ line-height: 1;
75
+ padding: 0.34rem 0.5rem;
76
+ }
77
+
78
+ /* Drawer — full-height panel slid in from the inline-end edge
79
+ (right in LTR, left in RTL). */
80
+ .ui-modal--drawer {
81
+ block-size: 100vh;
82
+ margin: 0;
83
+ margin-inline-start: auto;
84
+ max-block-size: 100vh;
85
+ max-inline-size: min(26rem, 100vw);
86
+ border-radius: 0;
87
+ border-width: 0;
88
+ border-inline-start-width: 1px;
89
+ }
90
+
91
+ @media (hover: hover) {
92
+ .ui-modal__close:hover {
93
+ border-color: var(--accent);
94
+ color: var(--accent);
95
+ }
96
+ }
97
+
98
+ /* --- Dropdown menu — pairs with native <details> --- */
99
+
100
+ .ui-menu {
101
+ background: var(--panel-strong);
102
+ border: 1px solid var(--line-strong);
103
+ border-radius: var(--radius-md);
104
+ box-shadow: var(--shadow-raised);
105
+ display: grid;
106
+ gap: 1px;
107
+ min-inline-size: 11rem;
108
+ padding: 0.3rem;
109
+ position: absolute;
110
+ inset-inline-end: 0;
111
+ inset-block-start: calc(100% + 0.4rem);
112
+ z-index: 30;
113
+ }
114
+
115
+ .ui-menu__label {
116
+ color: var(--text-dim);
117
+ font-family: var(--mono);
118
+ font-size: var(--text-2xs);
119
+ letter-spacing: var(--tracking-wide);
120
+ padding: 0.45rem 0.55rem 0.2rem;
121
+ text-transform: uppercase;
122
+ }
123
+
124
+ .ui-menu__item {
125
+ align-items: center;
126
+ background: transparent;
127
+ border: 0;
128
+ border-radius: var(--radius-sm);
129
+ color: var(--text-soft);
130
+ cursor: pointer;
131
+ display: flex;
132
+ font-family: var(--mono);
133
+ font-size: var(--text-sm);
134
+ gap: 0.5rem;
135
+ padding: 0.5rem 0.55rem;
136
+ text-align: start;
137
+ inline-size: 100%;
138
+ }
139
+
140
+ .ui-menu__item::before {
141
+ background: currentColor;
142
+ border-radius: 50%;
143
+ content: '';
144
+ block-size: 0.3rem;
145
+ opacity: 0.4;
146
+ inline-size: 0.3rem;
147
+ }
148
+
149
+ .ui-menu__sep {
150
+ background: var(--line);
151
+ border: 0;
152
+ block-size: 1px;
153
+ margin: 0.2rem 0;
154
+ }
155
+
156
+ @media (hover: hover) {
157
+ .ui-menu__item:hover {
158
+ background: var(--bg-accent);
159
+ color: var(--text);
160
+ }
161
+
162
+ .ui-menu__item:hover::before {
163
+ opacity: 1;
164
+ }
165
+ }
166
+
167
+ /* --- Mobile: modal becomes a bottom sheet, drawer goes full-width --- */
168
+
169
+ @media (max-width: 560px) {
170
+ .ui-modal {
171
+ border-radius: var(--radius-lg) var(--radius-lg) 0 0;
172
+ margin: auto auto 0;
173
+ max-block-size: 88vh;
174
+ max-inline-size: 100vw;
175
+ inline-size: 100vw;
176
+ }
177
+
178
+ .ui-modal--drawer {
179
+ border-radius: 0;
180
+ border-width: 1px 0 0;
181
+ block-size: 88vh;
182
+ margin: auto 0 0;
183
+ max-block-size: 88vh;
184
+ max-inline-size: 100vw;
185
+ inline-size: 100vw;
186
+ }
187
+
188
+ .ui-menu {
189
+ inset-inline: 0;
190
+ min-inline-size: 0;
191
+ }
192
+ }
193
+
194
+ @media (prefers-reduced-motion: reduce) {
195
+ .ui-modal[open] {
196
+ animation: none;
197
+ }
198
+ }
@@ -69,14 +69,16 @@
69
69
 
70
70
  .ui-divider {
71
71
  border: 0;
72
- border-top: 1px solid var(--line);
72
+ border-block-start: 1px solid var(--line);
73
73
  margin: 0;
74
74
  }
75
75
 
76
76
  /* --- Eyebrow / section label — dot-matrix face --- */
77
77
 
78
78
  .ui-eyebrow {
79
- color: var(--accent);
79
+ /* accent-strong, not accent: this is small bold text and must clear
80
+ WCAG AA 4.5:1 on the soft/tinted surfaces eyebrows sit on too. */
81
+ color: var(--accent-strong);
80
82
  font-family: var(--display);
81
83
  font-size: var(--text-xs);
82
84
  font-weight: 700;
@@ -106,8 +108,8 @@
106
108
  justify-content: center;
107
109
  letter-spacing: var(--tracking-wide);
108
110
  line-height: 1;
109
- min-height: 2.4rem;
110
- min-width: 2.4rem;
111
+ min-block-size: 2.4rem;
112
+ min-inline-size: 2.4rem;
111
113
  padding: 0.66rem 1rem;
112
114
  text-transform: uppercase;
113
115
  transition:
@@ -137,7 +139,7 @@
137
139
 
138
140
  .ui-button--icon {
139
141
  aspect-ratio: 1;
140
- min-width: 2.4rem;
142
+ min-inline-size: 2.4rem;
141
143
  padding: 0;
142
144
  }
143
145
 
@@ -172,13 +174,13 @@
172
174
  }
173
175
 
174
176
  .ui-link--arrow::after {
175
- border-right: 1px solid currentColor;
176
- border-top: 1px solid currentColor;
177
+ border-inline-end: 1px solid currentColor;
178
+ border-block-start: 1px solid currentColor;
177
179
  content: '';
178
- height: 0.42rem;
180
+ block-size: 0.42rem;
179
181
  transform: rotate(45deg);
180
182
  transition: transform var(--duration-fast) var(--ease-standard);
181
- width: 0.42rem;
183
+ inline-size: 0.42rem;
182
184
  }
183
185
 
184
186
  /* --- Chip / tag --- */
@@ -195,7 +197,7 @@
195
197
  gap: 0.36rem;
196
198
  letter-spacing: var(--tracking-wide);
197
199
  line-height: 1;
198
- min-height: 1.7rem;
200
+ min-block-size: 1.7rem;
199
201
  padding: 0.32rem 0.55rem;
200
202
  text-transform: uppercase;
201
203
  }
@@ -224,28 +226,26 @@
224
226
  text-transform: uppercase;
225
227
  }
226
228
 
229
+ /* Tone rides the border + tint; text stays the high-contrast neutral
230
+ (the soft tint can't carry 4.5:1 small-bold tone-on-tone — WCAG). */
227
231
  .ui-badge--accent {
228
232
  background: var(--accent-soft);
229
233
  border-color: color-mix(in srgb, var(--accent) 45%, var(--line));
230
- color: var(--accent);
231
234
  }
232
235
 
233
236
  .ui-badge--success {
234
237
  background: var(--success-soft);
235
238
  border-color: color-mix(in srgb, var(--success) 40%, var(--line));
236
- color: var(--success);
237
239
  }
238
240
 
239
241
  .ui-badge--warning {
240
242
  background: var(--warning-soft);
241
243
  border-color: color-mix(in srgb, var(--warning) 40%, var(--line));
242
- color: var(--warning);
243
244
  }
244
245
 
245
246
  .ui-badge--danger {
246
247
  background: var(--danger-soft);
247
248
  border-color: color-mix(in srgb, var(--danger) 40%, var(--line));
248
- color: var(--danger);
249
249
  }
250
250
 
251
251
  /* --- Key/value list --- */
@@ -257,10 +257,10 @@
257
257
  }
258
258
 
259
259
  .ui-key-value div {
260
- border-top: 1px solid var(--line);
260
+ border-block-start: 1px solid var(--line);
261
261
  display: grid;
262
262
  gap: 0.16rem;
263
- padding-top: 0.6rem;
263
+ padding-block-start: 0.6rem;
264
264
  }
265
265
 
266
266
  .ui-key-value dt {
@@ -315,7 +315,24 @@
315
315
  transform: translateX(0.14rem) rotate(45deg);
316
316
  }
317
317
 
318
+ [dir='rtl'] .ui-link--arrow:hover::after {
319
+ transform: translateX(-0.14rem) rotate(45deg);
320
+ }
321
+
318
322
  .ui-chip--accent:hover {
319
323
  background: var(--accent-soft);
320
324
  }
321
325
  }
326
+
327
+ /* --- Touch: comfortable hit targets on coarse pointers --- */
328
+
329
+ @media (pointer: coarse) {
330
+ .ui-button {
331
+ min-block-size: 2.9rem;
332
+ min-inline-size: 2.9rem;
333
+ }
334
+
335
+ .ui-button--icon {
336
+ min-inline-size: 2.9rem;
337
+ }
338
+ }
@@ -55,7 +55,7 @@
55
55
 
56
56
  .site-header__actions {
57
57
  align-items: center;
58
- margin-left: auto;
58
+ margin-inline-start: auto;
59
59
  }
60
60
 
61
61
  .site-menu {
@@ -63,7 +63,7 @@
63
63
  }
64
64
 
65
65
  .site-menu[open] {
66
- min-width: 0;
66
+ min-inline-size: 0;
67
67
  }
68
68
 
69
69
  .site-menu[open] .site-nav--mobile {
@@ -77,22 +77,22 @@
77
77
  box-shadow: var(--shadow-raised);
78
78
  display: none;
79
79
  gap: 0.35rem;
80
- margin-top: 0;
80
+ margin-block-start: 0;
81
81
  padding: 0.6rem;
82
82
  position: absolute;
83
- right: 0;
84
- top: calc(100% + 0.7rem);
85
- width: min(12rem, calc(100vw - 1.8rem));
83
+ inset-inline-end: 0;
84
+ inset-block-start: calc(100% + 0.7rem);
85
+ inline-size: min(12rem, calc(100vw - 1.8rem));
86
86
  z-index: 20;
87
87
  }
88
88
 
89
89
  .site-nav--mobile a {
90
- width: 100%;
90
+ inline-size: 100%;
91
91
  }
92
92
 
93
93
  .hero--home .problem-panel {
94
- border-left: 0;
95
- border-top: 1px solid var(--line);
94
+ border-inline-start: 0;
95
+ border-block-start: 1px solid var(--line);
96
96
  padding: 1rem 0 0;
97
97
  }
98
98
 
@@ -114,10 +114,10 @@
114
114
  }
115
115
 
116
116
  .notes-strip__latest {
117
- border-left: 0;
118
- border-top: 1px solid var(--line);
119
- padding-left: 0;
120
- padding-top: 1rem;
117
+ border-inline-start: 0;
118
+ border-block-start: 1px solid var(--line);
119
+ padding-inline-start: 0;
120
+ padding-block-start: 1rem;
121
121
  }
122
122
 
123
123
  .hero--home .hero__panel {
@@ -152,6 +152,6 @@
152
152
  }
153
153
 
154
154
  .theme-toggle__button {
155
- min-width: 4.2rem;
155
+ min-inline-size: 4.2rem;
156
156
  }
157
157
  }