@ponchia/ui 0.2.0

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/forms.css ADDED
@@ -0,0 +1,194 @@
1
+ /* ==========================================================================
2
+ forms — inputs and controls, monochrome with red focus
3
+ ========================================================================== */
4
+
5
+ .ui-field {
6
+ display: grid;
7
+ gap: 0.35rem;
8
+ }
9
+
10
+ .ui-label {
11
+ color: var(--text-dim);
12
+ font-family: var(--mono);
13
+ font-size: var(--text-2xs);
14
+ font-weight: 700;
15
+ letter-spacing: var(--tracking-wide);
16
+ text-transform: uppercase;
17
+ }
18
+
19
+ .ui-input,
20
+ .ui-select,
21
+ .ui-textarea {
22
+ background: var(--bg-elevated);
23
+ border: 1px solid var(--line-strong);
24
+ border-radius: var(--radius-md);
25
+ color: var(--text);
26
+ font-family: var(--mono);
27
+ font-size: var(--text-sm);
28
+ padding: 0.6rem 0.7rem;
29
+ transition:
30
+ border-color var(--duration-fast) var(--ease-standard),
31
+ background-color var(--duration-fast) var(--ease-standard);
32
+ width: 100%;
33
+ }
34
+
35
+ .ui-input::placeholder,
36
+ .ui-textarea::placeholder {
37
+ color: var(--text-dim);
38
+ }
39
+
40
+ .ui-textarea {
41
+ min-height: 6rem;
42
+ resize: vertical;
43
+ }
44
+
45
+ .ui-select {
46
+ appearance: none;
47
+ background-image: radial-gradient(var(--text-dim) 1.5px, transparent 1.5px);
48
+ background-position: right 0.75rem center;
49
+ background-repeat: no-repeat;
50
+ background-size: 5px 5px;
51
+ padding-right: 1.8rem;
52
+ }
53
+
54
+ .ui-input:focus,
55
+ .ui-select:focus,
56
+ .ui-textarea:focus {
57
+ border-color: var(--accent);
58
+ outline: none;
59
+ }
60
+
61
+ .ui-input:focus-visible,
62
+ .ui-select:focus-visible,
63
+ .ui-textarea:focus-visible {
64
+ outline: 2px solid var(--accent);
65
+ outline-offset: 1px;
66
+ }
67
+
68
+ .ui-input:disabled,
69
+ .ui-select:disabled,
70
+ .ui-textarea:disabled {
71
+ cursor: not-allowed;
72
+ opacity: 0.5;
73
+ }
74
+
75
+ .ui-input[aria-invalid='true'],
76
+ .ui-select[aria-invalid='true'],
77
+ .ui-textarea[aria-invalid='true'] {
78
+ border-color: var(--danger);
79
+ }
80
+
81
+ .ui-hint {
82
+ color: var(--text-dim);
83
+ font-size: var(--text-2xs);
84
+ }
85
+
86
+ .ui-hint--error {
87
+ color: var(--danger);
88
+ }
89
+
90
+ /* Search field with leading dot. */
91
+ .ui-search {
92
+ align-items: center;
93
+ background: var(--bg-elevated);
94
+ border: 1px solid var(--line-strong);
95
+ border-radius: var(--radius-md);
96
+ display: flex;
97
+ gap: 0.5rem;
98
+ padding: 0 0.7rem;
99
+ }
100
+
101
+ .ui-search::before {
102
+ background: var(--text-dim);
103
+ border-radius: 50%;
104
+ content: '';
105
+ flex: 0 0 auto;
106
+ height: 0.42rem;
107
+ width: 0.42rem;
108
+ }
109
+
110
+ .ui-search:focus-within {
111
+ border-color: var(--accent);
112
+ }
113
+
114
+ .ui-search:focus-within::before {
115
+ background: var(--accent);
116
+ }
117
+
118
+ .ui-search input {
119
+ background: transparent;
120
+ border: 0;
121
+ color: var(--text);
122
+ font-family: var(--mono);
123
+ font-size: var(--text-sm);
124
+ outline: none;
125
+ padding: 0.6rem 0;
126
+ width: 100%;
127
+ }
128
+
129
+ /* Toggle switch — square Nothing-style track. */
130
+ .ui-switch {
131
+ align-items: center;
132
+ cursor: pointer;
133
+ display: inline-flex;
134
+ gap: 0.6rem;
135
+ }
136
+
137
+ .ui-switch input {
138
+ position: absolute;
139
+ opacity: 0;
140
+ pointer-events: none;
141
+ }
142
+
143
+ .ui-switch__track {
144
+ background: var(--panel-soft);
145
+ border: 1px solid var(--line-strong);
146
+ border-radius: var(--radius-pill);
147
+ display: inline-flex;
148
+ height: 1.05rem;
149
+ padding: 2px;
150
+ transition:
151
+ background-color var(--duration-fast) var(--ease-standard),
152
+ border-color var(--duration-fast) var(--ease-standard);
153
+ width: 1.95rem;
154
+ }
155
+
156
+ .ui-switch__thumb {
157
+ background: var(--text-dim);
158
+ border-radius: 50%;
159
+ height: 100%;
160
+ transition:
161
+ transform var(--duration-fast) var(--ease-spring),
162
+ background-color var(--duration-fast) var(--ease-standard);
163
+ width: 0.78rem;
164
+ }
165
+
166
+ .ui-switch input:checked + .ui-switch__track {
167
+ background: var(--accent-soft);
168
+ border-color: var(--accent);
169
+ }
170
+
171
+ .ui-switch input:checked + .ui-switch__track .ui-switch__thumb {
172
+ background: var(--accent);
173
+ transform: translateX(0.9rem);
174
+ }
175
+
176
+ .ui-switch input:focus-visible + .ui-switch__track {
177
+ outline: 2px solid var(--accent);
178
+ outline-offset: 2px;
179
+ }
180
+
181
+ /* Checkbox / radio — square accent. */
182
+ .ui-check {
183
+ align-items: center;
184
+ cursor: pointer;
185
+ display: inline-flex;
186
+ gap: 0.5rem;
187
+ font-size: var(--text-sm);
188
+ }
189
+
190
+ .ui-check input {
191
+ accent-color: var(--accent);
192
+ height: 1rem;
193
+ width: 1rem;
194
+ }
package/css/index.css ADDED
@@ -0,0 +1,5 @@
1
+ /* @ponchia/ui — full bundle: core + responsive breakpoint overrides.
2
+ responsive.css joins the same `bronto` layer and, being imported last,
3
+ wins the within-layer cascade over the base rules it overrides. */
4
+ @import url('./core.css');
5
+ @import url('./responsive.css') layer(bronto);
package/css/layout.css ADDED
@@ -0,0 +1,219 @@
1
+ .site-background {
2
+ inset: 0;
3
+ overflow: hidden;
4
+ pointer-events: none;
5
+ position: fixed;
6
+ z-index: 0;
7
+ }
8
+
9
+ .site-background__grid {
10
+ position: absolute;
11
+ display: none;
12
+ }
13
+
14
+ .site-shell {
15
+ margin: 0 auto;
16
+ max-width: 1320px;
17
+ padding: 0.9rem;
18
+ position: relative;
19
+ z-index: 1;
20
+ }
21
+
22
+ .site-header,
23
+ .site-footer,
24
+ .hero,
25
+ .page-head,
26
+ .project-card,
27
+ .post-card,
28
+ .post-shell,
29
+ .focus-panel,
30
+ .surface-card,
31
+ .essay-card,
32
+ .metric-tile,
33
+ .principle-card,
34
+ .archive-note,
35
+ .signal-panel,
36
+ .problem-panel,
37
+ .callout,
38
+ .aside-block,
39
+ .quote-block,
40
+ .timeline,
41
+ .worklog-summary,
42
+ .project-teaser,
43
+ .misc-card {
44
+ background: var(--panel);
45
+ border: 1px solid var(--line);
46
+ box-shadow: var(--shadow);
47
+ }
48
+
49
+ .site-header {
50
+ align-items: center;
51
+ background: var(--panel);
52
+ border-radius: var(--radius-lg);
53
+ display: flex;
54
+ gap: 1rem;
55
+ justify-content: space-between;
56
+ margin: 0 auto 0.9rem;
57
+ padding: 0.55rem 0.65rem;
58
+ position: sticky;
59
+ top: 0.65rem;
60
+ z-index: 10;
61
+ }
62
+
63
+ .site-header__actions {
64
+ align-items: center;
65
+ display: flex;
66
+ gap: 0.7rem;
67
+ }
68
+
69
+ .site-mark {
70
+ align-items: center;
71
+ display: inline-flex;
72
+ font-family: var(--display);
73
+ font-size: 0.9rem;
74
+ gap: 0.35rem;
75
+ letter-spacing: 0;
76
+ text-transform: uppercase;
77
+ }
78
+
79
+ .site-mark__primary {
80
+ color: var(--text);
81
+ }
82
+
83
+ .site-main {
84
+ display: grid;
85
+ gap: 1.35rem;
86
+ grid-template-columns: minmax(0, 1fr);
87
+ }
88
+
89
+ .site-footer {
90
+ align-items: center;
91
+ border-radius: var(--radius-lg);
92
+ display: flex;
93
+ gap: 1rem;
94
+ justify-content: space-between;
95
+ margin-top: 1rem;
96
+ padding: 0.85rem 1rem;
97
+ }
98
+
99
+ .site-footer p {
100
+ font-size: 0.9rem;
101
+ margin: 0;
102
+ }
103
+
104
+ .site-footer__copy {
105
+ display: grid;
106
+ gap: 0.25rem;
107
+ }
108
+
109
+ .site-footer__links {
110
+ display: flex;
111
+ flex-wrap: wrap;
112
+ gap: 0.7rem;
113
+ justify-content: flex-end;
114
+ }
115
+
116
+ .site-footer__links a {
117
+ color: var(--text);
118
+ font-size: 0.86rem;
119
+ text-decoration: underline;
120
+ text-decoration-color: color-mix(in srgb, var(--accent) 42%, transparent);
121
+ text-underline-offset: 0.2rem;
122
+ transition:
123
+ color var(--duration-fast) var(--ease-standard),
124
+ text-decoration-color var(--duration-fast) var(--ease-standard);
125
+ }
126
+
127
+ .site-footer__links a:hover {
128
+ color: var(--accent-strong);
129
+ text-decoration-color: var(--accent-strong);
130
+ }
131
+
132
+ .hero,
133
+ .page-head,
134
+ .post-shell {
135
+ border-radius: var(--radius-xl);
136
+ max-width: 100%;
137
+ overflow: hidden;
138
+ padding: 1.35rem;
139
+ position: relative;
140
+ width: 100%;
141
+ }
142
+
143
+ .hero {
144
+ display: grid;
145
+ gap: 1.6rem;
146
+ grid-template-columns: minmax(0, 1.2fr) minmax(320px, 0.95fr);
147
+ }
148
+
149
+ .hero::before,
150
+ .page-head::before,
151
+ .post-shell::before {
152
+ display: none;
153
+ }
154
+
155
+ .hero > *,
156
+ .page-head > *,
157
+ .post-shell > * {
158
+ position: relative;
159
+ z-index: 1;
160
+ }
161
+
162
+ .hero__copy,
163
+ .hero__panel,
164
+ .panel-stack,
165
+ .card-stack,
166
+ .home-section,
167
+ .page-section {
168
+ display: grid;
169
+ gap: 1rem;
170
+ grid-template-columns: minmax(0, 1fr);
171
+ }
172
+
173
+ .hero__panel {
174
+ align-self: start;
175
+ }
176
+
177
+ .home-section,
178
+ .page-section {
179
+ padding-block: 0.2rem;
180
+ }
181
+
182
+ .profile-grid,
183
+ .project-teaser-grid,
184
+ .project-detail-grid,
185
+ .project-grid,
186
+ .home-grid,
187
+ .essay-grid,
188
+ .principle-grid,
189
+ .project-detail-layout,
190
+ .misc-grid {
191
+ display: grid;
192
+ gap: 1rem;
193
+ }
194
+
195
+ .profile-grid,
196
+ .project-detail-grid {
197
+ grid-template-columns: repeat(2, minmax(0, 1fr));
198
+ }
199
+
200
+ .project-detail-layout {
201
+ align-items: start;
202
+ gap: 1.6rem;
203
+ grid-template-columns: minmax(0, 1.35fr) minmax(300px, 0.65fr);
204
+ }
205
+
206
+ .project-grid,
207
+ .project-teaser-grid,
208
+ .home-grid,
209
+ .essay-grid {
210
+ grid-template-columns: repeat(2, minmax(0, 1fr));
211
+ }
212
+
213
+ .principle-grid {
214
+ grid-template-columns: repeat(3, minmax(0, 1fr));
215
+ }
216
+
217
+ .misc-grid {
218
+ grid-template-columns: repeat(3, minmax(0, 1fr));
219
+ }
package/css/motion.css ADDED
@@ -0,0 +1,268 @@
1
+ /* ==========================================================================
2
+ motion — keyframes + animation utilities
3
+ Restrained, dot-flavoured. Everything collapses under reduced-motion.
4
+ Keyframes from the legacy responsive layer live here so consumers that
5
+ import only core.css keep their existing animations.
6
+ ========================================================================== */
7
+
8
+ @keyframes pulseDot {
9
+ 0%,
10
+ 100% {
11
+ opacity: 0.35;
12
+ transform: scale(0.84);
13
+ }
14
+
15
+ 50% {
16
+ opacity: 1;
17
+ transform: scale(1);
18
+ }
19
+ }
20
+
21
+ @keyframes scan {
22
+ 0% {
23
+ transform: translateY(-120%);
24
+ }
25
+
26
+ 100% {
27
+ transform: translateY(320%);
28
+ }
29
+ }
30
+
31
+ @keyframes growBar {
32
+ to {
33
+ transform: scaleX(1);
34
+ }
35
+ }
36
+
37
+ @keyframes drawLine {
38
+ from {
39
+ opacity: 0;
40
+ stroke-dasharray: 0 999;
41
+ }
42
+
43
+ to {
44
+ opacity: 1;
45
+ stroke-dasharray: 999 0;
46
+ }
47
+ }
48
+
49
+ @keyframes pulseNode {
50
+ 0%,
51
+ 100% {
52
+ transform: scale(1);
53
+ }
54
+
55
+ 50% {
56
+ transform: scale(1.08);
57
+ }
58
+ }
59
+
60
+ @keyframes pulseRing {
61
+ 0% {
62
+ opacity: 0.7;
63
+ transform: scale(0.7);
64
+ }
65
+
66
+ 100% {
67
+ opacity: 0;
68
+ transform: scale(1.3);
69
+ }
70
+ }
71
+
72
+ /* --- Framework motifs --- */
73
+
74
+ @keyframes uiFadeIn {
75
+ from {
76
+ opacity: 0;
77
+ }
78
+
79
+ to {
80
+ opacity: 1;
81
+ }
82
+ }
83
+
84
+ @keyframes uiRise {
85
+ from {
86
+ opacity: 0;
87
+ transform: translateY(10px);
88
+ }
89
+
90
+ to {
91
+ opacity: 1;
92
+ transform: translateY(0);
93
+ }
94
+ }
95
+
96
+ @keyframes uiDotIn {
97
+ 0% {
98
+ opacity: 0;
99
+ transform: scale(0.2);
100
+ }
101
+
102
+ 60% {
103
+ opacity: 1;
104
+ transform: scale(1.15);
105
+ }
106
+
107
+ 100% {
108
+ opacity: 1;
109
+ transform: scale(1);
110
+ }
111
+ }
112
+
113
+ @keyframes uiSpin {
114
+ to {
115
+ transform: rotate(360deg);
116
+ }
117
+ }
118
+
119
+ @keyframes uiBlink {
120
+ 0%,
121
+ 45% {
122
+ opacity: 1;
123
+ }
124
+
125
+ 55%,
126
+ 100% {
127
+ opacity: 0.2;
128
+ }
129
+ }
130
+
131
+ @keyframes uiShimmer {
132
+ from {
133
+ background-position: 200% 0;
134
+ }
135
+
136
+ to {
137
+ background-position: -200% 0;
138
+ }
139
+ }
140
+
141
+ @keyframes uiMatrixReveal {
142
+ from {
143
+ clip-path: inset(0 100% 0 0);
144
+ }
145
+
146
+ to {
147
+ clip-path: inset(0 0 0 0);
148
+ }
149
+ }
150
+
151
+ /* --- Utilities --- */
152
+
153
+ .ui-animate-in {
154
+ animation: uiRise var(--duration-slow) var(--ease-spring) both;
155
+ }
156
+
157
+ .ui-animate-fade {
158
+ animation: uiFadeIn var(--duration-base) var(--ease-standard) both;
159
+ }
160
+
161
+ .ui-animate-dot {
162
+ animation: uiDotIn var(--duration-base) var(--ease-spring) both;
163
+ }
164
+
165
+ .ui-animate-matrix {
166
+ animation: uiMatrixReveal var(--duration-slow) var(--ease-out) both;
167
+ }
168
+
169
+ /* Stagger children: set --i on each child (or use nth-child cap). */
170
+ .ui-stagger > * {
171
+ animation: uiRise var(--duration-slow) var(--ease-spring) both;
172
+ animation-delay: calc(var(--i, 0) * 60ms);
173
+ }
174
+
175
+ .ui-stagger--auto > *:nth-child(1) {
176
+ animation-delay: 0ms;
177
+ }
178
+
179
+ .ui-stagger--auto > *:nth-child(2) {
180
+ animation-delay: 60ms;
181
+ }
182
+
183
+ .ui-stagger--auto > *:nth-child(3) {
184
+ animation-delay: 120ms;
185
+ }
186
+
187
+ .ui-stagger--auto > *:nth-child(4) {
188
+ animation-delay: 180ms;
189
+ }
190
+
191
+ .ui-stagger--auto > *:nth-child(5) {
192
+ animation-delay: 240ms;
193
+ }
194
+
195
+ .ui-stagger--auto > *:nth-child(6) {
196
+ animation-delay: 300ms;
197
+ }
198
+
199
+ .ui-stagger--auto > *:nth-child(n + 7) {
200
+ animation-delay: 360ms;
201
+ }
202
+
203
+ /* Reveal-on-scroll: add .ui-reveal, toggle .is-visible via IntersectionObserver.
204
+ Degrades to visible with no JS. */
205
+ @media (prefers-reduced-motion: no-preference) {
206
+ .ui-reveal {
207
+ opacity: 0;
208
+ transform: translateY(14px);
209
+ transition:
210
+ opacity var(--duration-slow) var(--ease-out),
211
+ transform var(--duration-slow) var(--ease-out);
212
+ }
213
+
214
+ .ui-reveal.is-visible {
215
+ opacity: 1;
216
+ transform: none;
217
+ }
218
+ }
219
+
220
+ .ui-skeleton {
221
+ background:
222
+ linear-gradient(
223
+ 90deg,
224
+ var(--panel-soft) 25%,
225
+ color-mix(in srgb, var(--panel-soft) 55%, var(--line-strong)) 50%,
226
+ var(--panel-soft) 75%
227
+ );
228
+ background-size: 200% 100%;
229
+ animation: uiShimmer 1.4s linear infinite;
230
+ border-radius: var(--radius-sm);
231
+ color: transparent;
232
+ min-height: 0.8em;
233
+ }
234
+
235
+ .ui-spinner {
236
+ animation: uiSpin 0.7s linear infinite;
237
+ border: 2px solid var(--line);
238
+ border-radius: 50%;
239
+ border-top-color: var(--accent);
240
+ display: inline-block;
241
+ height: 1.1rem;
242
+ width: 1.1rem;
243
+ }
244
+
245
+ .ui-caret::after {
246
+ animation: uiBlink 1.1s steps(1) infinite;
247
+ content: '▮';
248
+ margin-left: 0.1em;
249
+ }
250
+
251
+ @media (prefers-reduced-motion: reduce) {
252
+ html {
253
+ scroll-behavior: auto;
254
+ }
255
+
256
+ *,
257
+ *::before,
258
+ *::after {
259
+ animation-duration: 0.01ms !important;
260
+ animation-iteration-count: 1 !important;
261
+ transition-duration: 0.01ms !important;
262
+ }
263
+
264
+ .ui-reveal {
265
+ opacity: 1 !important;
266
+ transform: none !important;
267
+ }
268
+ }