@press2ai/theme-specialist-glossy 0.3.0 → 0.4.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@press2ai/theme-specialist-glossy",
3
- "version": "0.3.0",
3
+ "version": "0.4.0",
4
4
  "description": "Classless, AI-first theme inspired by Stripe. Framework-agnostic templates (Hono, Astro, raw HTML). Semantic HTML, Schema.org microdata, JSON-LD — built for LLM crawlers.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -30,6 +30,7 @@
30
30
  "exports": {
31
31
  ".": "./src/index.ts",
32
32
  "./templates": "./src/templates/index.ts",
33
+ "./catalog": "./src/templates/catalog.ts",
33
34
  "./Layout.astro": "./src/components/Layout.astro",
34
35
  "./ProfileArticle.astro": "./src/components/ProfileArticle.astro",
35
36
  "./ProfileCard.astro": "./src/components/ProfileCard.astro",
@@ -1,498 +1,271 @@
1
- /* ============================================================
2
- Otwarty Trener — theme: "stripe"
3
- Classless. Stylowanie po tagach semantycznych.
4
- Inspiracja: Stripe / Revolut — clean, bold, dużo whitespace.
5
- ============================================================ */
6
-
7
1
  @import url('https://rsms.me/inter/inter.css');
8
2
 
9
3
  :root {
10
- --font-sans: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
11
- --font-display: 'Inter', sans-serif;
12
-
13
- --color-bg: #ffffff;
14
- --color-bg-soft: #f6f9fc;
15
- --color-text: #0a2540;
16
- --color-text-soft: #425466;
17
- --color-text-muted: #8898aa;
18
- --color-border: #e3e8ee;
19
- --color-border-strong: #cfd7df;
20
-
21
- --color-accent: #635bff;
22
- --color-accent-hover: #4f46e5;
23
- --color-accent-soft: #f0f0ff;
24
-
25
- --gradient-hero: linear-gradient(150deg, #f6f9fc 0%, #eef2ff 40%, #ffffff 100%);
26
- --gradient-accent: linear-gradient(135deg, #635bff 0%, #00d4ff 100%);
27
-
28
- --radius: 12px;
29
- --radius-lg: 20px;
30
- --shadow-sm: 0 1px 3px rgba(10, 37, 64, 0.05), 0 1px 2px rgba(10, 37, 64, 0.03);
31
- --shadow-md: 0 4px 12px rgba(10, 37, 64, 0.06), 0 2px 4px rgba(10, 37, 64, 0.04);
32
- --shadow-lg: 0 12px 32px rgba(10, 37, 64, 0.08), 0 4px 12px rgba(10, 37, 64, 0.04);
33
-
34
- --container: 1100px;
35
- --container-prose: 760px;
36
- --transition: 180ms cubic-bezier(0.4, 0, 0.2, 1);
37
- }
38
-
39
- * { box-sizing: border-box; }
40
-
41
- html {
42
- font-size: 16px;
43
- -webkit-font-smoothing: antialiased;
44
- -moz-osx-font-smoothing: grayscale;
45
- scroll-behavior: smooth;
46
- overflow-x: hidden;
47
- }
4
+ --font: 'Inter', system-ui, sans-serif;
5
+ --g1: 0.5rem; --g2: 0.8125rem; --g3: 1.3125rem; --g4: 2.125rem; --g5: 3.4375rem; --g6: 5.5625rem; --g7: 9rem;
6
+ --t-xs: 0.8rem; --t-sm: 1rem; --t-md: 1.25rem; --t-lg: 1.563rem; --t-xl: 1.953rem; --t-2xl: 2.441rem;
7
+ --container: 1080px; --pad: var(--g4);
8
+ --w-6: 495px; --w-8: 667px; --w-10: 839px; --measure: 38rem;
9
+ --white: #ffffff; --bg: #fafbfc; --card: #ffffff;
10
+ --ink: #1a1a2e; --ink-2: #4a4a68; --ink-3: #8b8ba3;
11
+ --line: #e8e8ef; --line-h: #d0d0de;
12
+ --violet: #7c5cfc; --violet-s: #f3f0ff;
13
+ --teal: #0d9488; --teal-s: #ecfdf5;
14
+ --rose: #e11d63; --rose-s: #fff1f5;
15
+ --amber: #d97706; --amber-s: #fffbeb;
16
+ --sky: #0284c7; --sky-s: #f0f9ff;
17
+ --r: 12px; --r-lg: 16px; --pill: 999px;
18
+ --shadow: 0 1px 3px rgba(0,0,0,.04);
19
+ --shadow-up: 0 2px 8px rgba(0,0,0,.06), 0 0 0 1px rgba(0,0,0,.02);
20
+ --ease: 180ms ease;
21
+ }
22
+
23
+ *, *::before, *::after { box-sizing: border-box; margin: 0; }
24
+ html { font-size: 16px; -webkit-font-smoothing: antialiased; scroll-behavior: smooth; }
48
25
 
49
26
  body {
50
- margin: 0;
27
+ font-family: var(--font);
28
+ font-feature-settings: 'cv11', 'ss01';
29
+ color: var(--ink);
30
+ background: var(--bg);
31
+ line-height: 1.5;
51
32
  overflow-x: clip;
52
- font-family: var(--font-sans);
53
- font-feature-settings: 'cv11', 'ss01', 'ss03';
54
- color: var(--color-text);
55
- background: var(--color-bg);
56
- line-height: 1.6;
57
33
  }
58
34
 
59
- /* ---------- LAYOUT ---------- */
35
+ h1, h2, h3 { color: var(--ink); letter-spacing: -0.02em; }
36
+ h1 { font-size: clamp(var(--t-xl), 4.5vw, var(--t-2xl)); font-weight: 800; line-height: 1.15; letter-spacing: -0.035em; margin-bottom: var(--g4); }
37
+ h2 { font-size: var(--t-lg); font-weight: 700; line-height: 1.25; margin-bottom: var(--g3); }
38
+ h3 { font-size: var(--t-md); font-weight: 600; line-height: 1.35; margin-bottom: var(--g2); }
39
+ p { font-size: var(--t-sm); line-height: 1.6; color: var(--ink-2); margin-bottom: var(--g3); max-width: var(--measure); }
40
+ a { color: var(--violet); text-decoration: none; transition: color var(--ease); }
41
+ a:hover { color: var(--ink); }
42
+ small { font-size: var(--t-xs); color: var(--ink-3); }
43
+ strong { color: var(--ink); font-weight: 600; }
60
44
 
45
+ /* Header */
61
46
  body > header {
62
- position: sticky;
63
- top: 0;
64
- z-index: 50;
65
- background: rgba(255, 255, 255, 0.85);
66
- backdrop-filter: saturate(180%) blur(12px);
67
- -webkit-backdrop-filter: saturate(180%) blur(12px);
68
- border-bottom: 1px solid var(--color-border);
47
+ position: sticky; top: 0; z-index: 50;
48
+ background: rgba(255,255,255,.88);
49
+ backdrop-filter: blur(12px); -webkit-backdrop-filter: blur(12px);
50
+ border-bottom: 1px solid var(--line);
69
51
  }
70
-
71
52
  body > header nav {
72
- max-width: var(--container);
73
- margin: 0 auto;
74
- padding: 1rem 1.5rem;
75
- display: flex;
76
- align-items: center;
77
- justify-content: space-between;
78
- gap: 2rem;
79
- }
80
-
81
- body > header nav a {
82
- color: var(--color-text);
83
- text-decoration: none;
84
- font-weight: 500;
85
- font-size: 0.95rem;
86
- transition: color var(--transition);
87
- }
88
-
89
- body > header nav a:hover {
90
- color: var(--color-accent);
91
- }
92
-
93
- body > header nav a strong {
94
- font-size: 1.1rem;
95
- font-weight: 700;
96
- background: var(--gradient-accent);
97
- -webkit-background-clip: text;
98
- background-clip: text;
99
- color: transparent;
53
+ max-width: var(--container); margin-inline: auto; padding-inline: var(--pad);
54
+ height: var(--g5); display: flex; align-items: center; justify-content: space-between;
100
55
  }
56
+ body > header nav a { color: var(--ink-2); text-decoration: none; font-size: var(--t-sm); font-weight: 500; }
57
+ body > header nav a strong { font-size: var(--t-md); font-weight: 700; color: var(--ink); }
101
58
 
59
+ /* Main */
102
60
  main {
103
- max-width: var(--container);
104
- margin: 0 auto;
105
- padding: 3rem 1.5rem 5rem;
106
- }
107
-
108
- body > footer {
109
- border-top: 1px solid var(--color-border);
110
- background: var(--color-bg-soft);
111
- padding: 2.5rem 1.5rem;
112
- text-align: center;
113
- }
114
-
115
- body > footer small {
116
- color: var(--color-text-muted);
117
- font-size: 0.875rem;
118
- }
119
-
120
- body > footer a {
121
- color: var(--color-accent);
122
- text-decoration: none;
123
- }
124
-
125
- /* ---------- TYPOGRAPHY ---------- */
126
-
127
- h1, h2, h3, h4 {
128
- font-family: var(--font-display);
129
- color: var(--color-text);
130
- letter-spacing: -0.02em;
131
- line-height: 1.2;
132
- margin: 0 0 1rem;
133
- }
134
-
135
- h1 {
136
- font-size: clamp(2.25rem, 5vw, 3.5rem);
137
- font-weight: 800;
138
- letter-spacing: -0.035em;
139
- }
140
-
141
- h2 {
142
- font-size: 1.75rem;
143
- font-weight: 700;
144
- margin-top: 2.5rem;
145
- }
146
-
147
- h3 {
148
- font-size: 1.25rem;
149
- font-weight: 600;
150
- }
151
-
152
- p {
153
- color: var(--color-text-soft);
154
- margin: 0 0 1rem;
155
- }
156
-
157
- a {
158
- color: var(--color-accent);
159
- text-decoration: none;
160
- transition: color var(--transition);
161
- }
162
-
163
- a:hover {
164
- color: var(--color-accent-hover);
165
- }
166
-
167
- small {
168
- color: var(--color-text-muted);
169
- font-size: 0.875rem;
170
- }
171
-
172
- strong {
173
- color: var(--color-text);
174
- font-weight: 600;
61
+ max-width: var(--container); margin-inline: auto;
62
+ padding-inline: var(--pad); padding-top: 0; padding-bottom: var(--g6);
175
63
  }
64
+ main > h1:first-child, main > article:first-child { margin-top: var(--g6); }
65
+ main > section { margin-bottom: var(--g6); }
176
66
 
177
- /* ---------- HERO (hgroup) — Stripe-style mesh gradient ---------- */
67
+ /* Footer */
68
+ body > footer { border-top: 1px solid var(--line); padding: var(--g5) 0; text-align: center; }
69
+ body > footer small { display: block; max-width: var(--container); margin-inline: auto; padding-inline: var(--pad); color: var(--ink-3); }
70
+ body > footer a { color: var(--violet); }
178
71
 
72
+ /* Hero */
179
73
  hgroup {
180
- position: relative;
181
- padding-top: 7rem;
182
- padding-bottom: 9rem;
183
- padding-left: max(1.5rem, calc((100vw - var(--container)) / 2));
184
- padding-right: max(1.5rem, calc((100vw - var(--container)) / 2));
185
- margin: -3rem calc(50% - 50vw) 4rem;
186
- text-align: left;
187
- overflow: hidden;
188
- isolation: isolate;
189
- background:
190
- radial-gradient(ellipse 80% 60% at 15% 20%, rgba(99, 91, 255, 0.18) 0%, transparent 60%),
191
- radial-gradient(ellipse 60% 80% at 85% 30%, rgba(0, 212, 255, 0.15) 0%, transparent 55%),
192
- radial-gradient(ellipse 70% 50% at 50% 100%, rgba(255, 87, 209, 0.12) 0%, transparent 60%),
193
- linear-gradient(180deg, #f6f9fc 0%, #ffffff 100%);
194
- }
195
-
196
- hgroup::before {
197
- content: '';
198
- position: absolute;
199
- inset: 0;
200
- background-image:
201
- linear-gradient(rgba(10, 37, 64, 0.04) 1px, transparent 1px),
202
- linear-gradient(90deg, rgba(10, 37, 64, 0.04) 1px, transparent 1px);
203
- background-size: 56px 56px;
204
- mask-image: radial-gradient(ellipse 70% 60% at 50% 40%, black 0%, transparent 75%);
205
- -webkit-mask-image: radial-gradient(ellipse 70% 60% at 50% 40%, black 0%, transparent 75%);
206
- z-index: -1;
207
- pointer-events: none;
208
- }
209
-
210
- hgroup::after {
211
- content: '';
212
- position: absolute;
213
- left: 0;
214
- right: 0;
215
- bottom: -1px;
216
- height: 80px;
217
- background: linear-gradient(180deg, transparent 0%, #ffffff 100%);
218
- pointer-events: none;
219
- z-index: -1;
74
+ position: relative; text-align: center; background: var(--white);
75
+ padding: var(--g6) var(--pad);
76
+ margin: 0 calc(50% - 50vw) var(--g6);
77
+ border-bottom: 1px solid var(--line);
220
78
  }
221
-
222
- hgroup > * {
223
- position: relative;
224
- }
225
-
226
- hgroup > p:first-child {
227
- display: inline-flex;
228
- margin-bottom: 2rem;
229
- padding: 0;
230
- }
231
-
79
+ hgroup > * { position: relative; }
80
+ hgroup > p:first-child { display: inline-flex; margin-bottom: var(--g4); padding: 0; }
232
81
  hgroup > p:first-child small {
233
- display: inline-flex;
234
- align-items: center;
235
- gap: 0.5rem;
236
- background: rgba(255, 255, 255, 0.8);
237
- backdrop-filter: blur(8px);
238
- border: 1px solid var(--color-border);
239
- padding: 0.4rem 0.9rem;
240
- border-radius: 999px;
241
- color: var(--color-text-soft);
242
- font-size: 0.8rem;
243
- font-weight: 500;
244
- box-shadow: var(--shadow-sm);
245
- }
246
-
247
- hgroup > p:first-child small::before {
248
- content: '';
249
- width: 6px;
250
- height: 6px;
251
- border-radius: 50%;
252
- background: #00d24a;
253
- box-shadow: 0 0 0 3px rgba(0, 210, 74, 0.2);
254
- }
255
-
256
- hgroup h1 {
257
- font-size: clamp(2.5rem, 6.5vw, 5rem);
258
- font-weight: 800;
259
- letter-spacing: -0.04em;
260
- line-height: 1.05;
261
- margin: 0 0 1.5rem;
262
- max-width: 900px;
263
- background: linear-gradient(135deg, #0a2540 0%, #1a1a4e 40%, #635bff 100%);
264
- -webkit-background-clip: text;
265
- background-clip: text;
266
- color: transparent;
82
+ display: inline-flex; align-items: center; gap: var(--g1);
83
+ background: var(--teal-s); padding: var(--g1) var(--g2);
84
+ border-radius: var(--pill); font-size: var(--t-xs); font-weight: 600; color: var(--teal);
267
85
  }
268
-
269
- hgroup h1 br { display: block; }
270
-
271
- hgroup p {
272
- font-size: 1.2rem;
273
- line-height: 1.55;
274
- color: var(--color-text-soft);
275
- max-width: 640px;
276
- margin: 0 0 2rem;
277
- }
278
-
86
+ hgroup > p:first-child small::before { content: ''; width: 6px; height: 6px; border-radius: 50%; background: var(--teal); }
87
+ hgroup h1 { max-width: 16ch; margin: 0 auto var(--g4); color: var(--ink); }
88
+ hgroup p { font-size: var(--t-md); line-height: 1.5; color: var(--ink-2); max-width: var(--measure); margin: 0 auto 0; }
279
89
  hgroup > p:last-child {
280
- display: flex;
281
- gap: 0.75rem;
282
- flex-wrap: wrap;
283
- margin-top: 2.5rem;
284
- margin-bottom: 0;
90
+ display: flex; gap: var(--g2); flex-wrap: wrap; justify-content: center;
91
+ margin-top: var(--g5); margin-bottom: 0;
285
92
  }
286
-
287
93
  hgroup > p:last-child a {
288
- display: inline-flex;
289
- align-items: center;
290
- padding: 0.85rem 1.5rem;
291
- border-radius: 999px;
292
- font-weight: 600;
293
- font-size: 0.95rem;
294
- text-decoration: none;
295
- transition: all var(--transition);
296
- }
297
-
298
- hgroup > p:last-child a:first-child {
299
- background: var(--color-text);
300
- color: white;
301
- box-shadow: 0 4px 14px rgba(10, 37, 64, 0.25);
302
- }
303
-
304
- hgroup > p:last-child a:first-child:hover {
305
- background: var(--color-accent);
306
- transform: translateY(-1px);
307
- box-shadow: 0 6px 20px rgba(99, 91, 255, 0.35);
308
- }
309
-
310
- hgroup > p:last-child a:last-child {
311
- background: rgba(255, 255, 255, 0.7);
312
- backdrop-filter: blur(8px);
313
- color: var(--color-text);
314
- border: 1px solid var(--color-border);
315
- }
316
-
317
- hgroup > p:last-child a:last-child:hover {
318
- background: white;
319
- border-color: var(--color-border-strong);
320
- }
321
-
322
- @media (max-width: 640px) {
323
- hgroup { padding: 4rem 1.25rem 5rem; }
324
- hgroup h1 br { display: none; }
325
- }
326
-
327
- /* ---------- SECTIONS ---------- */
328
-
329
- main > section {
330
- margin-bottom: 3rem;
331
- }
332
-
333
- main > section > p:first-of-type {
334
- font-size: 1.05rem;
335
- max-width: var(--container-prose);
336
- }
337
-
338
- /* ---------- TRAINER CARDS (article in section) ---------- */
339
-
340
- main > section > article {
341
- background: var(--color-bg);
342
- border: 1px solid var(--color-border);
343
- border-radius: var(--radius);
344
- padding: 1.75rem 2rem;
345
- margin: 1rem 0;
346
- box-shadow: var(--shadow-sm);
347
- transition: all var(--transition);
348
- }
349
-
350
- main > section > article:hover {
351
- border-color: var(--color-border-strong);
352
- box-shadow: var(--shadow-md);
353
- transform: translateY(-2px);
354
- }
355
-
356
- main > section > article header {
357
- margin-bottom: 0.75rem;
358
- }
359
-
360
- main > section > article h2 {
361
- margin: 0 0 0.25rem;
362
- font-size: 1.35rem;
363
- font-weight: 700;
364
- }
365
-
366
- main > section > article h2 a {
367
- color: var(--color-text);
368
- }
369
-
370
- main > section > article h2 a:hover {
371
- color: var(--color-accent);
372
- }
373
-
374
- main > section > article header p {
375
- margin: 0;
376
- font-size: 0.9rem;
377
- color: var(--color-text-muted);
378
- }
379
-
380
- main > section > article > p {
381
- margin: 0.75rem 0 0.5rem;
382
- color: var(--color-text-soft);
383
- }
384
-
385
- main > section > article small {
386
- display: inline-block;
387
- background: var(--color-accent-soft);
388
- color: var(--color-accent-hover);
389
- padding: 0.25rem 0.75rem;
390
- border-radius: 999px;
391
- font-size: 0.8rem;
392
- font-weight: 500;
393
- }
394
-
395
- /* ---------- TRAINER ARTICLE (single page) ---------- */
396
-
94
+ display: inline-flex; align-items: center; height: var(--g5); padding: 0 var(--g4);
95
+ border-radius: var(--pill); font-weight: 600; font-size: var(--t-sm); transition: all var(--ease);
96
+ }
97
+ hgroup > p:last-child a:first-child { background: var(--violet); color: var(--white); }
98
+ hgroup > p:last-child a:first-child:hover { background: var(--ink); }
99
+ hgroup > p:last-child a:last-child { background: var(--white); color: var(--ink); border: 1px solid var(--line); }
100
+ hgroup > p:last-child a:last-child:hover { border-color: var(--line-h); background: var(--bg); }
101
+
102
+ /* Search */
103
+ form[role="search"] {
104
+ display: flex; max-width: var(--w-6); height: var(--g5);
105
+ margin: var(--g5) auto 0; background: var(--white);
106
+ border: 1px solid var(--line); border-radius: var(--pill);
107
+ overflow: hidden; box-shadow: var(--shadow-up); transition: border-color var(--ease);
108
+ }
109
+ form[role="search"]:focus-within { border-color: var(--violet); }
110
+ form[role="search"] input {
111
+ flex: 1; min-width: 0; border: none; background: transparent; color: var(--ink);
112
+ padding: 0 var(--g3); font-size: var(--t-sm); font-family: var(--font); outline: none;
113
+ }
114
+ form[role="search"] input::placeholder { color: var(--ink-3); }
115
+ form[role="search"] button {
116
+ flex-shrink: 0; border: none; background: var(--violet); color: var(--white);
117
+ padding: 0 var(--g4); font-size: var(--t-sm); font-weight: 600;
118
+ font-family: var(--font); cursor: pointer; transition: background var(--ease);
119
+ }
120
+ form[role="search"] button:hover { background: var(--ink); }
121
+
122
+ /* Stats */
123
+ section:has(> dl) { margin-bottom: 0; }
124
+ section > dl {
125
+ display: grid; grid-template-columns: repeat(auto-fit, minmax(100px, 1fr)); gap: var(--g3);
126
+ padding: var(--g5) var(--g4); margin: 0 auto var(--g6); max-width: var(--w-6);
127
+ background: var(--white); border: 1px solid var(--line); border-radius: var(--r-lg);
128
+ }
129
+ section > dl div { text-align: center; }
130
+ section > dl dt { font-size: var(--t-xl); font-weight: 800; line-height: 1.2; color: var(--violet); }
131
+ section > dl dd { margin: 0; font-size: var(--t-xs); line-height: 1.5; color: var(--ink-3); font-weight: 500; text-transform: uppercase; letter-spacing: 0.06em; }
132
+
133
+ /* Category pills */
134
+ nav[aria-label] { display: flex; flex-wrap: wrap; justify-content: center; gap: var(--g2); margin-bottom: var(--g6); }
135
+ nav[aria-label] a {
136
+ display: inline-flex; align-items: center; height: var(--g4); padding: 0 var(--g2);
137
+ border-radius: var(--pill); font-size: var(--t-xs); font-weight: 500;
138
+ background: var(--white); border: 1px solid var(--line); color: var(--ink-2); transition: all var(--ease);
139
+ }
140
+ nav[aria-label] a:nth-child(5n+1):hover { border-color: var(--violet); color: var(--violet); background: var(--violet-s); }
141
+ nav[aria-label] a:nth-child(5n+2):hover { border-color: var(--teal); color: var(--teal); background: var(--teal-s); }
142
+ nav[aria-label] a:nth-child(5n+3):hover { border-color: var(--rose); color: var(--rose); background: var(--rose-s); }
143
+ nav[aria-label] a:nth-child(5n+4):hover { border-color: var(--amber); color: var(--amber); background: var(--amber-s); }
144
+ nav[aria-label] a:nth-child(5n+5):hover { border-color: var(--sky); color: var(--sky); background: var(--sky-s); }
145
+
146
+ /* Steps */
147
+ section:has(> ol) > h2 { text-align: center; }
148
+ section > ol {
149
+ list-style: none; padding: 0; display: grid;
150
+ grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); gap: var(--g3); margin: 0; counter-reset: steps;
151
+ }
152
+ section > ol li {
153
+ counter-increment: steps; background: var(--white); border: 1px solid var(--line);
154
+ border-radius: var(--r-lg); padding: var(--g5) var(--g3); text-align: center;
155
+ }
156
+ section > ol li::before {
157
+ content: counter(steps); display: flex; align-items: center; justify-content: center;
158
+ width: var(--g5); height: var(--g5); margin: 0 auto var(--g3);
159
+ border-radius: 50%; font-size: var(--t-md); font-weight: 700;
160
+ }
161
+ section > ol li:nth-child(5n+1)::before { background: var(--violet-s); color: var(--violet); }
162
+ section > ol li:nth-child(5n+2)::before { background: var(--teal-s); color: var(--teal); }
163
+ section > ol li:nth-child(5n+3)::before { background: var(--amber-s); color: var(--amber); }
164
+ section > ol li:nth-child(5n+4)::before { background: var(--rose-s); color: var(--rose); }
165
+ section > ol li:nth-child(5n+5)::before { background: var(--sky-s); color: var(--sky); }
166
+ section > ol li strong { display: block; font-size: var(--t-sm); line-height: 1.5; margin-bottom: var(--g1); color: var(--ink); }
167
+ section > ol li span { font-size: var(--t-xs); line-height: 1.5; color: var(--ink-3); }
168
+
169
+ /* Trainer cards */
170
+ section:has(> article[itemscope]) {
171
+ display: grid; grid-template-columns: repeat(auto-fill, minmax(var(--w-6), 1fr)); gap: var(--g3);
172
+ }
173
+ section:has(> article[itemscope]) > h2 { grid-column: 1 / -1; margin-bottom: var(--g4); }
174
+ article[itemscope] {
175
+ background: var(--card); border: 1px solid var(--line); border-left: 3px solid var(--line);
176
+ border-radius: var(--r-lg); padding: var(--g4) var(--g3);
177
+ transition: border-color var(--ease), box-shadow var(--ease);
178
+ }
179
+ article[itemscope]:hover { border-color: var(--line-h); box-shadow: var(--shadow-up); }
180
+ article[itemscope]:nth-child(5n+2) { border-left-color: var(--violet); }
181
+ article[itemscope]:nth-child(5n+3) { border-left-color: var(--teal); }
182
+ article[itemscope]:nth-child(5n+4) { border-left-color: var(--rose); }
183
+ article[itemscope]:nth-child(5n+5) { border-left-color: var(--amber); }
184
+ article[itemscope]:nth-child(5n+6) { border-left-color: var(--sky); }
185
+ article[itemscope] header { margin-bottom: var(--g2); }
186
+ article[itemscope] h2 { font-size: var(--t-md); line-height: 1.35; margin: 0 0 var(--g1); }
187
+ article[itemscope] h2 a { color: var(--ink); }
188
+ article[itemscope] h2 a:hover { color: var(--violet); }
189
+ article[itemscope] header p { font-size: var(--t-xs); line-height: 1.5; color: var(--ink-3); margin: 0; }
190
+ article[itemscope] [itemprop="description"] { font-size: var(--t-xs); line-height: 1.5; margin: var(--g1) 0 0; color: var(--ink-2); }
191
+ article[itemscope] [itemprop="jobTitle"],
192
+ article[itemscope] [itemprop="addressLocality"] { color: var(--ink-3); }
193
+ article[itemscope] > p:last-child small {
194
+ display: inline-block; margin-top: var(--g2); background: var(--violet-s); color: var(--violet);
195
+ padding: calc(var(--g1) / 2) var(--g1); border-radius: var(--pill); font-size: var(--t-xs); font-weight: 500;
196
+ }
197
+
198
+ /* Single trainer */
397
199
  main > article {
398
- max-width: var(--container-prose);
399
- margin: 0 auto;
400
- background: var(--color-bg);
401
- border: 1px solid var(--color-border);
402
- border-radius: var(--radius-lg);
403
- padding: 3rem;
404
- box-shadow: var(--shadow-md);
405
- }
406
-
407
- main > article > header {
408
- border-bottom: 1px solid var(--color-border);
409
- padding-bottom: 1.5rem;
410
- margin-bottom: 2rem;
200
+ max-width: var(--w-8); margin: 0 auto; background: var(--card);
201
+ border: 1px solid var(--line); border-radius: var(--r-lg); padding: var(--g5);
411
202
  }
412
-
413
- main > article > header h1 {
414
- margin-bottom: 0.5rem;
415
- }
416
-
417
- main > article > header p {
418
- font-size: 1.1rem;
419
- color: var(--color-text-muted);
420
- margin: 0;
421
- }
422
-
203
+ main > article > header { border-bottom: 1px solid var(--line); padding-bottom: var(--g3); margin-bottom: var(--g4); }
204
+ main > article > header h1 { margin-bottom: var(--g2); }
205
+ main > article > header p { font-size: var(--t-md); color: var(--ink-3); margin: 0; }
423
206
  main > article address {
424
- font-style: normal;
425
- display: inline-block;
426
- background: var(--color-bg-soft);
427
- padding: 0.75rem 1.25rem;
428
- border-radius: var(--radius);
429
- margin-bottom: 2rem;
430
- color: var(--color-text-soft);
431
- border: 1px solid var(--color-border);
432
- }
433
-
434
- main > article section {
435
- margin: 2rem 0;
436
- }
437
-
438
- main > article section h2 {
439
- font-size: 1.1rem;
440
- font-weight: 600;
441
- text-transform: uppercase;
442
- letter-spacing: 0.05em;
443
- color: var(--color-text-muted);
444
- margin-top: 0;
445
- margin-bottom: 1rem;
446
- }
447
-
448
- main > article ul {
449
- list-style: none;
450
- padding: 0;
451
- display: flex;
452
- flex-wrap: wrap;
453
- gap: 0.5rem;
207
+ font-style: normal; display: inline-block; background: var(--bg);
208
+ padding: var(--g1) var(--g2); border-radius: var(--r); margin-bottom: var(--g3);
209
+ color: var(--ink-2); border: 1px solid var(--line); font-size: var(--t-sm);
454
210
  }
455
-
211
+ main > article section { margin: var(--g5) 0; }
212
+ main > article section h2 { font-size: var(--t-xs); font-weight: 600; text-transform: uppercase; letter-spacing: 0.06em; color: var(--ink-3); margin: 0 0 var(--g2); }
213
+ main > article ul { list-style: none; padding: 0; display: flex; flex-wrap: wrap; gap: var(--g1); }
456
214
  main > article ul li {
457
- background: var(--color-accent-soft);
458
- color: var(--color-accent-hover);
459
- padding: 0.4rem 0.9rem;
460
- border-radius: 999px;
461
- font-size: 0.875rem;
462
- font-weight: 500;
463
- }
464
-
465
- main > article dl {
466
- display: grid;
467
- grid-template-columns: max-content 1fr;
468
- gap: 0.75rem 1.5rem;
469
- margin: 0;
470
- }
471
-
472
- main > article dt {
473
- color: var(--color-text-muted);
474
- font-size: 0.875rem;
475
- font-weight: 500;
476
- }
477
-
478
- main > article dd {
479
- margin: 0;
480
- color: var(--color-text);
481
- }
482
-
483
- main > article > footer {
484
- margin-top: 2.5rem;
485
- padding-top: 1.5rem;
486
- border-top: 1px solid var(--color-border);
487
- text-align: center;
488
- }
489
-
490
- /* ---------- RESPONSIVE ---------- */
491
-
215
+ background: var(--violet-s); color: var(--violet);
216
+ padding: calc(var(--g1) / 2) var(--g2); border-radius: var(--pill); font-size: var(--t-xs); font-weight: 500;
217
+ }
218
+ main > article dl { display: grid; grid-template-columns: max-content 1fr; gap: var(--g1) var(--g3); }
219
+ main > article dt { font-size: var(--t-xs); color: var(--ink-3); font-weight: 500; }
220
+ main > article dd { margin: 0; font-size: var(--t-sm); }
221
+ main > article > footer { margin-top: var(--g5); padding-top: var(--g3); border-top: 1px solid var(--line); text-align: center; }
222
+
223
+ /* Pagination */
224
+ main > nav p { display: flex; align-items: center; justify-content: center; gap: var(--g3); padding: var(--g4) 0; font-size: var(--t-sm); color: var(--ink-3); }
225
+ main > nav a {
226
+ height: var(--g4); display: inline-flex; align-items: center; padding: 0 var(--g2);
227
+ border-radius: var(--pill); background: var(--white); border: 1px solid var(--line);
228
+ font-size: var(--t-xs); font-weight: 500; transition: all var(--ease);
229
+ }
230
+ main > nav a:hover { border-color: var(--violet); color: var(--violet); }
231
+
232
+ /* Trust */
233
+ blockquote {
234
+ margin: var(--g5) auto var(--g6); padding: var(--g5) var(--g4); max-width: var(--w-8);
235
+ background: var(--teal-s); border: 1px solid rgba(13,148,136,.12);
236
+ border-radius: var(--r-lg); text-align: center; border-left: none;
237
+ }
238
+ blockquote strong { display: block; font-size: var(--t-md); line-height: 1.35; margin-bottom: var(--g2); color: var(--teal); }
239
+ blockquote p { color: var(--ink-2); margin: 0 auto; font-size: var(--t-sm); }
240
+
241
+ /* Forms */
242
+ label { display: block; font-size: var(--t-sm); color: var(--ink-2); font-weight: 500; margin-bottom: var(--g1); }
243
+ input[type="text"] {
244
+ display: block; width: 100%; margin-top: var(--g1); height: var(--g5);
245
+ padding: 0 var(--g2); background: var(--white); border: 1px solid var(--line);
246
+ border-radius: var(--r); color: var(--ink); font-size: var(--t-sm); font-family: var(--font);
247
+ transition: border-color var(--ease);
248
+ }
249
+ input[type="text"]:focus { outline: none; border-color: var(--violet); box-shadow: 0 0 0 3px rgba(124,92,252,.08); }
250
+ button[type="submit"] {
251
+ margin-top: var(--g3); height: var(--g5); padding: 0 var(--g4);
252
+ border: none; border-radius: var(--pill); background: var(--violet); color: var(--white);
253
+ font-size: var(--t-sm); font-weight: 600; font-family: var(--font); cursor: pointer;
254
+ transition: background var(--ease);
255
+ }
256
+ button[type="submit"]:hover { background: var(--ink); }
257
+
258
+ /* Responsive */
492
259
  @media (max-width: 640px) {
493
- main { padding: 2rem 1rem 3rem; }
494
- hgroup { padding: 2.5rem 1rem 3rem; margin: -2rem -1rem 2rem; }
495
- main > article { padding: 1.5rem; }
496
- main > article dl { grid-template-columns: 1fr; gap: 0.25rem 0; }
497
- main > article dt { margin-top: 0.75rem; }
260
+ :root { --pad: var(--g3); }
261
+ main { padding: 0 var(--pad) var(--g5); }
262
+ hgroup { padding: var(--g5) var(--pad); }
263
+ section:has(> article[itemscope]) { grid-template-columns: 1fr; }
264
+ section > ol { grid-template-columns: 1fr; }
265
+ section > dl { grid-template-columns: 1fr; max-width: var(--w-6); padding: var(--g4); }
266
+ main > article { padding: var(--g4); }
267
+ main > article dl { grid-template-columns: 1fr; gap: calc(var(--g1) / 2) 0; }
268
+ main > article dt { margin-top: var(--g2); }
269
+ form[role="search"] { height: var(--g4); }
270
+ form[role="search"] input { font-size: var(--t-xs); }
498
271
  }
@@ -0,0 +1,63 @@
1
+ import { esc } from './helpers.ts';
2
+
3
+ export interface CatalogHeroProps {
4
+ badge?: string;
5
+ title: string;
6
+ subtitle?: string;
7
+ searchAction?: string;
8
+ searchPlaceholder?: string;
9
+ searchValue?: string;
10
+ }
11
+
12
+ export function catalogHero(p: CatalogHeroProps): string {
13
+ const badge = p.badge ? `<p><small>${esc(p.badge)}</small></p>` : '';
14
+ const subtitle = p.subtitle ? `<p>${esc(p.subtitle)}</p>` : '';
15
+ const search = p.searchAction !== undefined ? `<form role="search" action="${esc(p.searchAction ?? '/')}" method="get">
16
+ <input type="text" name="q" placeholder="${esc(p.searchPlaceholder ?? 'Szukaj...')}" value="${esc(p.searchValue ?? '')}" />
17
+ <button type="submit">Szukaj</button>
18
+ </form>` : '';
19
+ return `<hgroup>
20
+ ${badge}
21
+ <h1>${esc(p.title)}</h1>
22
+ ${subtitle}
23
+ ${search}
24
+ </hgroup>`;
25
+ }
26
+
27
+ export function statBar(items: { value: string; label: string }[]): string {
28
+ const divs = items.map(i => `<div><dt>${esc(i.value)}</dt><dd>${esc(i.label)}</dd></div>`).join('\n');
29
+ return `<section><dl>\n${divs}\n</dl></section>`;
30
+ }
31
+
32
+ export function categoryNav(items: { href: string; label: string }[], ariaLabel = 'Kategorie'): string {
33
+ if (!items.length) return '';
34
+ const links = items.map(i => `<a href="${esc(i.href)}">${esc(i.label)}</a>`).join('');
35
+ return `<nav aria-label="${esc(ariaLabel)}">${links}</nav>`;
36
+ }
37
+
38
+ export function steps(title: string, items: { title: string; description: string }[]): string {
39
+ const lis = items.map(i => `<li><strong>${esc(i.title)}</strong><span>${esc(i.description)}</span></li>`).join('\n');
40
+ return `<section>\n<h2>${esc(title)}</h2>\n<ol>\n${lis}\n</ol>\n</section>`;
41
+ }
42
+
43
+ export function trustBlock(title: string, body: string): string {
44
+ return `<blockquote>\n<strong>${esc(title)}</strong>\n<p>${esc(body)}</p>\n</blockquote>`;
45
+ }
46
+
47
+ export interface PaginationProps {
48
+ current: number;
49
+ total: number;
50
+ baseHref?: string;
51
+ extraParams?: string;
52
+ prevLabel?: string;
53
+ nextLabel?: string;
54
+ }
55
+
56
+ export function pagination(p: PaginationProps): string {
57
+ if (p.total <= 1) return '';
58
+ const base = p.baseHref ?? '/';
59
+ const extra = p.extraParams ?? '';
60
+ const prev = p.current > 1 ? `<a href="${esc(base)}?p=${p.current - 1}${extra}">${esc(p.prevLabel ?? '\u2190 Poprzednia')}</a>` : '';
61
+ const next = p.current < p.total ? `<a href="${esc(base)}?p=${p.current + 1}${extra}">${esc(p.nextLabel ?? 'Nastepna \u2192')}</a>` : '';
62
+ return `<nav><p>${prev} Strona ${p.current} z ${p.total} ${next}</p></nav>`;
63
+ }
@@ -2,4 +2,5 @@ export { layout, type LayoutProps } from './layout.ts';
2
2
  export { hero } from './hero.ts';
3
3
  export { profileCard } from './profile-card.ts';
4
4
  export { profileArticle } from './profile-article.ts';
5
+ export { catalogHero, statBar, categoryNav, steps, trustBlock, pagination, type CatalogHeroProps, type PaginationProps } from './catalog.ts';
5
6
  export { esc, fullName } from './helpers.ts';
@@ -12,7 +12,7 @@ export interface LayoutProps {
12
12
  footerContent?: string;
13
13
  }
14
14
 
15
- const THEME_VERSION = '0.3.0';
15
+ const THEME_VERSION = '0.4.0';
16
16
 
17
17
  export function layout(props: LayoutProps, body: string): string {
18
18
  const {