@press2ai/theme-specialist-glossy 0.4.3 → 0.5.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.4.3",
3
+ "version": "0.5.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",
@@ -6,18 +6,19 @@
6
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
7
  --container: 1080px; --pad: var(--g4);
8
8
  --w-6: 495px; --w-8: 667px; --w-10: 839px; --measure: 38rem;
9
- --white: #ffffff; --bg: #fafbfc; --card: #ffffff;
9
+ --white: #ffffff; --bg: #f8f9fb; --card: #ffffff;
10
10
  --ink: #1a1a2e; --ink-2: #4a4a68; --ink-3: #8b8ba3;
11
11
  --line: #e8e8ef; --line-h: #d0d0de;
12
- --violet: #7c5cfc; --violet-s: #f3f0ff;
12
+ --violet: #7c5cfc; --violet-s: #f3f0ff; --violet-glow: rgba(124,92,252,.18);
13
13
  --teal: #0d9488; --teal-s: #ecfdf5;
14
14
  --rose: #e11d63; --rose-s: #fff1f5;
15
15
  --amber: #d97706; --amber-s: #fffbeb;
16
16
  --sky: #0284c7; --sky-s: #f0f9ff;
17
- --r: 12px; --r-lg: 16px; --pill: 999px;
17
+ --r: 16px; --r-lg: 20px; --pill: 999px;
18
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;
19
+ --shadow-md: 0 4px 16px rgba(0,0,0,.06), 0 1px 3px rgba(0,0,0,.04);
20
+ --shadow-up: 0 8px 24px rgba(0,0,0,.08), 0 2px 6px rgba(0,0,0,.03);
21
+ --ease: 200ms cubic-bezier(.4,0,.2,1);
21
22
  }
22
23
 
23
24
  *, *::before, *::after { box-sizing: border-box; margin: 0; }
@@ -28,12 +29,12 @@ body {
28
29
  font-feature-settings: 'cv11', 'ss01';
29
30
  color: var(--ink);
30
31
  background: var(--bg);
31
- line-height: 1.5;
32
+ line-height: 1.6;
32
33
  overflow-x: clip;
33
34
  }
34
35
 
35
36
  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
+ h1 { font-size: clamp(var(--t-xl), 5vw, var(--t-2xl)); font-weight: 800; line-height: 1.1; letter-spacing: -0.035em; margin-bottom: var(--g4); }
37
38
  h2 { font-size: var(--t-lg); font-weight: 700; line-height: 1.25; margin-bottom: var(--g3); }
38
39
  h3 { font-size: var(--t-md); font-weight: 600; line-height: 1.35; margin-bottom: var(--g2); }
39
40
  p { font-size: var(--t-sm); line-height: 1.6; color: var(--ink-2); margin-bottom: var(--g3); max-width: var(--measure); }
@@ -45,13 +46,13 @@ strong { color: var(--ink); font-weight: 600; }
45
46
  /* Header */
46
47
  body > header {
47
48
  position: sticky; top: 0; z-index: 50;
48
- background: rgba(255,255,255,.88);
49
- backdrop-filter: blur(12px); -webkit-backdrop-filter: blur(12px);
49
+ background: rgba(255,255,255,.82);
50
+ backdrop-filter: saturate(180%) blur(16px); -webkit-backdrop-filter: saturate(180%) blur(16px);
50
51
  border-bottom: 1px solid var(--line);
51
52
  }
52
53
  body > header nav {
53
54
  max-width: var(--container); margin-inline: auto; padding-inline: var(--pad);
54
- height: var(--g5); display: flex; align-items: center; justify-content: space-between;
55
+ height: 56px; display: flex; align-items: center; justify-content: space-between;
55
56
  }
56
57
  body > header nav a { color: var(--ink-2); text-decoration: none; font-size: var(--t-sm); font-weight: 500; }
57
58
  body > header nav a strong { font-size: var(--t-md); font-weight: 700; color: var(--ink); }
@@ -59,10 +60,10 @@ body > header nav a strong { font-size: var(--t-md); font-weight: 700; color: va
59
60
  /* Main */
60
61
  main {
61
62
  max-width: var(--container); margin-inline: auto;
62
- padding-inline: var(--pad); padding-top: 0; padding-bottom: var(--g6);
63
+ padding-inline: var(--pad); padding-top: 0; padding-bottom: var(--g7);
63
64
  }
64
65
  main > h1:first-child, main > article:first-child { margin-top: var(--g6); }
65
- main > section { margin-bottom: var(--g6); }
66
+ main > section { margin-bottom: var(--g7); }
66
67
 
67
68
  /* Footer */
68
69
  body > footer { border-top: 1px solid var(--line); padding: var(--g5) 0; text-align: center; }
@@ -71,42 +72,64 @@ body > footer a { color: var(--violet); }
71
72
 
72
73
  /* Hero */
73
74
  hgroup {
74
- position: relative; text-align: center; background: var(--white);
75
- padding: var(--g6) var(--pad);
76
- margin: 0 calc(50% - 50vw) var(--g6) calc(50% - 50vw);
75
+ position: relative; text-align: center; isolation: isolate; overflow: hidden;
76
+ padding: var(--g7) var(--pad) var(--g6);
77
+ margin: 0 calc(50% - 50vw) var(--g7) calc(50% - 50vw);
78
+ background:
79
+ radial-gradient(ellipse 70% 50% at 20% 30%, var(--violet-glow) 0%, transparent 60%),
80
+ radial-gradient(ellipse 50% 60% at 80% 20%, rgba(13,148,136,.12) 0%, transparent 55%),
81
+ radial-gradient(ellipse 60% 40% at 50% 100%, rgba(225,29,99,.08) 0%, transparent 50%),
82
+ linear-gradient(180deg, #fff 0%, var(--bg) 100%);
77
83
  border-bottom: 1px solid var(--line);
78
84
  }
85
+ hgroup::before {
86
+ content: ''; position: absolute; inset: 0;
87
+ background-image:
88
+ linear-gradient(rgba(124,92,252,.04) 1px, transparent 1px),
89
+ linear-gradient(90deg, rgba(124,92,252,.04) 1px, transparent 1px);
90
+ background-size: 48px 48px;
91
+ mask-image: radial-gradient(ellipse 60% 50% at 50% 40%, black 0%, transparent 70%);
92
+ -webkit-mask-image: radial-gradient(ellipse 60% 50% at 50% 40%, black 0%, transparent 70%);
93
+ z-index: -1;
94
+ }
79
95
  hgroup > * { position: relative; }
80
96
  hgroup > p:first-child { display: inline-flex; margin-bottom: var(--g4); padding: 0; }
81
97
  hgroup > p:first-child small {
82
98
  display: inline-flex; align-items: center; gap: var(--g1);
83
- background: var(--teal-s); padding: var(--g1) var(--g2);
99
+ background: rgba(255,255,255,.7); backdrop-filter: blur(8px);
100
+ padding: var(--g1) var(--g2); border: 1px solid var(--line);
84
101
  border-radius: var(--pill); font-size: var(--t-xs); font-weight: 600; color: var(--teal);
102
+ box-shadow: var(--shadow);
85
103
  }
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; }
89
- hgroup > p:last-child {
104
+ hgroup > p:first-child small::before { content: ''; width: 6px; height: 6px; border-radius: 50%; background: #00d24a; box-shadow: 0 0 0 3px rgba(0,210,74,.2); }
105
+ hgroup h1 { max-width: 18ch; margin: 0 auto var(--g4); color: var(--ink); }
106
+ hgroup p { font-size: var(--t-md); line-height: 1.55; color: var(--ink-2); max-width: var(--measure); margin: 0 auto 0; }
107
+
108
+ /* Hero CTAs */
109
+ .hero-ctas {
90
110
  display: flex; gap: var(--g2); flex-wrap: wrap; justify-content: center;
91
111
  margin-top: var(--g5); margin-bottom: 0;
92
112
  }
93
- hgroup > p:last-child a {
94
- display: inline-flex; align-items: center; height: var(--g5); padding: 0 var(--g4);
113
+ .cta-primary, .cta-secondary {
114
+ display: inline-flex; align-items: center; height: 48px; padding: 0 var(--g4);
95
115
  border-radius: var(--pill); font-weight: 600; font-size: var(--t-sm); transition: all var(--ease);
96
116
  }
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); }
117
+ .cta-primary {
118
+ background: var(--violet); color: var(--white);
119
+ box-shadow: 0 4px 14px var(--violet-glow);
120
+ }
121
+ .cta-primary:hover { background: var(--ink); color: var(--white); transform: translateY(-1px); box-shadow: 0 6px 20px rgba(26,26,46,.2); }
122
+ .cta-secondary { background: var(--white); color: var(--ink); border: 1px solid var(--line); }
123
+ .cta-secondary:hover { border-color: var(--line-h); background: var(--bg); }
101
124
 
102
125
  /* Search */
103
126
  form[role="search"] {
104
- display: flex; max-width: var(--w-6); height: var(--g5);
127
+ display: flex; max-width: var(--w-6); height: 52px;
105
128
  margin: var(--g5) auto 0; background: var(--white);
106
129
  border: 1px solid var(--line); border-radius: var(--pill);
107
- overflow: hidden; box-shadow: var(--shadow-up); transition: border-color var(--ease);
130
+ overflow: hidden; box-shadow: var(--shadow-md); transition: all var(--ease);
108
131
  }
109
- form[role="search"]:focus-within { border-color: var(--violet); }
132
+ form[role="search"]:focus-within { border-color: var(--violet); box-shadow: 0 4px 16px var(--violet-glow); }
110
133
  form[role="search"] input {
111
134
  flex: 1; min-width: 0; border: none; background: transparent; color: var(--ink);
112
135
  padding: 0 var(--g3); font-size: var(--t-sm); font-family: var(--font); outline: none;
@@ -114,29 +137,34 @@ form[role="search"] input {
114
137
  }
115
138
  form[role="search"] input::placeholder { color: var(--ink-3); }
116
139
  form[role="search"] button {
117
- flex-shrink: 0; border: none; background: var(--violet); color: var(--white);
140
+ flex-shrink: 0; height: 100%; border: none; background: var(--violet); color: var(--white);
118
141
  padding: 0 var(--g4); font-size: var(--t-sm); font-weight: 600;
119
142
  font-family: var(--font); cursor: pointer; transition: background var(--ease);
120
143
  }
121
144
  form[role="search"] button:hover { background: var(--ink); }
122
145
 
123
146
  /* Stats */
147
+ section[aria-label] > p { text-align: center; font-size: var(--t-sm); color: var(--ink-2); margin: 0 auto var(--g4); max-width: var(--measure); }
124
148
  section:has(> dl) { margin-bottom: 0; }
125
149
  section > dl {
126
- display: grid; grid-template-columns: repeat(auto-fit, minmax(100px, 1fr)); gap: var(--g3);
127
- padding: var(--g5) var(--g4); margin: 0 auto var(--g6); max-width: var(--w-6);
150
+ display: grid; grid-template-columns: repeat(auto-fit, minmax(140px, 1fr)); gap: var(--g4);
151
+ padding: var(--g5); margin: 0 auto var(--g7); max-width: var(--w-8);
128
152
  background: var(--white); border: 1px solid var(--line); border-radius: var(--r-lg);
153
+ box-shadow: var(--shadow-md);
129
154
  }
130
155
  section > dl div { text-align: center; }
156
+ .stat-icon { display: flex; align-items: center; justify-content: center; width: 40px; height: 40px; margin: 0 auto var(--g2); background: var(--violet-s); border-radius: 50%; color: var(--violet); }
157
+ .stat-icon svg { width: 20px; height: 20px; }
131
158
  section > dl dt { font-size: var(--t-xl); font-weight: 800; line-height: 1.2; color: var(--violet); }
132
- 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; }
159
+ section > dl dd { margin: var(--g1) 0 0; font-size: var(--t-xs); line-height: 1.5; color: var(--ink-3); font-weight: 500; text-transform: uppercase; letter-spacing: 0.06em; }
133
160
 
134
161
  /* Category pills */
135
- nav[aria-label] { display: flex; flex-wrap: wrap; justify-content: center; gap: var(--g2); margin-bottom: var(--g6); }
162
+ nav[aria-label] { display: flex; flex-wrap: wrap; justify-content: center; gap: var(--g2); margin-bottom: var(--g7); }
136
163
  nav[aria-label] a {
137
- display: inline-flex; align-items: center; height: var(--g4); padding: 0 var(--g2);
164
+ display: inline-flex; align-items: center; height: 36px; padding: 0 var(--g3);
138
165
  border-radius: var(--pill); font-size: var(--t-xs); font-weight: 500;
139
- background: var(--white); border: 1px solid var(--line); color: var(--ink-2); transition: all var(--ease);
166
+ background: var(--white); border: 1px solid var(--line); color: var(--ink-2);
167
+ transition: all var(--ease); box-shadow: var(--shadow);
140
168
  }
141
169
  nav[aria-label] a:nth-child(5n+1):hover { border-color: var(--violet); color: var(--violet); background: var(--violet-s); }
142
170
  nav[aria-label] a:nth-child(5n+2):hover { border-color: var(--teal); color: var(--teal); background: var(--teal-s); }
@@ -145,18 +173,20 @@ nav[aria-label] a:nth-child(5n+4):hover { border-color: var(--amber); color: var
145
173
  nav[aria-label] a:nth-child(5n+5):hover { border-color: var(--sky); color: var(--sky); background: var(--sky-s); }
146
174
 
147
175
  /* Steps */
148
- section:has(> ol) > h2 { text-align: center; }
176
+ section:has(> ol) > h2 { text-align: center; margin-bottom: var(--g5); }
149
177
  section > ol {
150
178
  list-style: none; padding: 0; display: grid;
151
- grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); gap: var(--g3); margin: 0; counter-reset: steps;
179
+ grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: var(--g4); margin: 0; counter-reset: steps;
152
180
  }
153
181
  section > ol li {
154
182
  counter-increment: steps; background: var(--white); border: 1px solid var(--line);
155
- border-radius: var(--r-lg); padding: var(--g5) var(--g3); text-align: center;
183
+ border-radius: var(--r-lg); padding: var(--g5) var(--g4); text-align: center;
184
+ box-shadow: var(--shadow); transition: all var(--ease);
156
185
  }
186
+ section > ol li:hover { transform: translateY(-2px); box-shadow: var(--shadow-md); }
157
187
  section > ol li::before {
158
188
  content: counter(steps); display: flex; align-items: center; justify-content: center;
159
- width: var(--g5); height: var(--g5); margin: 0 auto var(--g3);
189
+ width: 48px; height: 48px; margin: 0 auto var(--g3);
160
190
  border-radius: 50%; font-size: var(--t-md); font-weight: 700;
161
191
  }
162
192
  section > ol li:nth-child(5n+1)::before { background: var(--violet-s); color: var(--violet); }
@@ -164,42 +194,64 @@ section > ol li:nth-child(5n+2)::before { background: var(--teal-s); color: var(
164
194
  section > ol li:nth-child(5n+3)::before { background: var(--amber-s); color: var(--amber); }
165
195
  section > ol li:nth-child(5n+4)::before { background: var(--rose-s); color: var(--rose); }
166
196
  section > ol li:nth-child(5n+5)::before { background: var(--sky-s); color: var(--sky); }
167
- section > ol li strong { display: block; font-size: var(--t-sm); line-height: 1.5; margin-bottom: var(--g1); color: var(--ink); }
168
- section > ol li span { font-size: var(--t-xs); line-height: 1.5; color: var(--ink-3); }
197
+ section > ol li strong { display: block; font-size: var(--t-md); line-height: 1.4; margin-bottom: var(--g1); color: var(--ink); }
198
+ section > ol li span { font-size: var(--t-sm); line-height: 1.5; color: var(--ink-3); }
169
199
 
170
200
  /* Trainer cards */
171
201
  section:has(> article[itemscope]) {
172
- display: grid; grid-template-columns: repeat(auto-fill, minmax(var(--w-6), 1fr)); gap: var(--g3);
202
+ display: grid; grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); gap: var(--g4);
173
203
  }
174
204
  section:has(> article[itemscope]) > h2 { grid-column: 1 / -1; margin-bottom: var(--g4); }
175
205
  article[itemscope] {
176
- background: var(--card); border: 1px solid var(--line); border-left: 3px solid var(--line);
177
- border-radius: var(--r-lg); padding: var(--g4) var(--g3);
178
- transition: border-color var(--ease), box-shadow var(--ease);
179
- }
180
- article[itemscope]:hover { border-color: var(--line-h); box-shadow: var(--shadow-up); }
181
- article[itemscope]:nth-child(5n+2) { border-left-color: var(--violet); }
182
- article[itemscope]:nth-child(5n+3) { border-left-color: var(--teal); }
183
- article[itemscope]:nth-child(5n+4) { border-left-color: var(--rose); }
184
- article[itemscope]:nth-child(5n+5) { border-left-color: var(--amber); }
185
- article[itemscope]:nth-child(5n+6) { border-left-color: var(--sky); }
206
+ position: relative; background: var(--card); border: 1px solid var(--line);
207
+ border-radius: var(--r-lg); padding: var(--g4);
208
+ display: flex; flex-direction: column;
209
+ box-shadow: var(--shadow); transition: all var(--ease);
210
+ }
211
+ article[itemscope]:hover { transform: translateY(-3px); box-shadow: var(--shadow-up); border-color: var(--line-h); }
212
+
213
+ /* Card avatar */
214
+ .card-avatar {
215
+ width: 48px; height: 48px; border-radius: 50%;
216
+ display: flex; align-items: center; justify-content: center;
217
+ font-size: var(--t-sm); font-weight: 700; color: var(--white);
218
+ margin-bottom: var(--g3); flex-shrink: 0;
219
+ }
220
+ article[itemscope]:nth-child(5n+2) .card-avatar { background: var(--violet); }
221
+ article[itemscope]:nth-child(5n+3) .card-avatar { background: var(--teal); }
222
+ article[itemscope]:nth-child(5n+4) .card-avatar { background: var(--rose); }
223
+ article[itemscope]:nth-child(5n+5) .card-avatar { background: var(--amber); }
224
+ article[itemscope]:nth-child(5n+6) .card-avatar { background: var(--sky); }
225
+ article[itemscope]:nth-child(5n+1) .card-avatar,
226
+ article[itemscope]:first-child .card-avatar { background: var(--violet); }
227
+
186
228
  article[itemscope] header { margin-bottom: var(--g2); }
187
- article[itemscope] h2 { font-size: var(--t-md); line-height: 1.35; margin: 0 0 var(--g1); }
229
+ article[itemscope] h2 { font-size: var(--t-md); line-height: 1.3; margin: 0 0 4px; }
188
230
  article[itemscope] h2 a { color: var(--ink); }
189
231
  article[itemscope] h2 a:hover { color: var(--violet); }
190
232
  article[itemscope] header p { font-size: var(--t-xs); line-height: 1.5; color: var(--ink-3); margin: 0; }
191
- article[itemscope] [itemprop="description"] { font-size: var(--t-xs); line-height: 1.5; margin: var(--g1) 0 0; color: var(--ink-2); }
192
- article[itemscope] [itemprop="jobTitle"],
193
- article[itemscope] [itemprop="addressLocality"] { color: var(--ink-3); }
194
- article[itemscope] > p:last-child small {
195
- display: inline-block; margin-top: var(--g2); background: var(--violet-s); color: var(--violet);
196
- padding: calc(var(--g1) / 2) var(--g1); border-radius: var(--pill); font-size: var(--t-xs); font-weight: 500;
233
+ .card-city { display: inline-flex; align-items: center; gap: 4px; margin-top: 4px; color: var(--ink-3); font-size: var(--t-xs); }
234
+ .card-city::before { content: ''; display: inline-block; width: 3px; height: 3px; border-radius: 50%; background: var(--ink-3); }
235
+ article[itemscope] [itemprop="description"] { font-size: var(--t-xs); line-height: 1.5; margin: var(--g2) 0 0; color: var(--ink-2); }
236
+ article[itemscope] ul { list-style: none; padding: 0; display: flex; flex-wrap: wrap; gap: 6px; margin-top: var(--g2); }
237
+ article[itemscope] ul li {
238
+ background: var(--violet-s); color: var(--violet);
239
+ padding: 2px var(--g1); border-radius: var(--pill); font-size: 0.7rem; font-weight: 500;
240
+ }
241
+
242
+ /* Card CTA */
243
+ .card-cta {
244
+ display: inline-flex; align-items: center; margin-top: auto; padding-top: var(--g3);
245
+ font-size: var(--t-xs); font-weight: 600; color: var(--violet);
246
+ transition: all var(--ease);
197
247
  }
248
+ .card-cta:hover { color: var(--ink); gap: 6px; }
198
249
 
199
250
  /* Single trainer */
200
251
  main > article {
201
252
  max-width: var(--w-8); margin: 0 auto; background: var(--card);
202
253
  border: 1px solid var(--line); border-radius: var(--r-lg); padding: var(--g5);
254
+ box-shadow: var(--shadow-md);
203
255
  }
204
256
  main > article > header { border-bottom: 1px solid var(--line); padding-bottom: var(--g3); margin-bottom: var(--g4); }
205
257
  main > article > header h1 { margin-bottom: var(--g2); }
@@ -224,49 +276,57 @@ main > article > footer { margin-top: var(--g5); padding-top: var(--g3); border-
224
276
  /* Pagination */
225
277
  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); }
226
278
  main > nav a {
227
- height: var(--g4); display: inline-flex; align-items: center; padding: 0 var(--g2);
279
+ height: 36px; display: inline-flex; align-items: center; padding: 0 var(--g3);
228
280
  border-radius: var(--pill); background: var(--white); border: 1px solid var(--line);
229
- font-size: var(--t-xs); font-weight: 500; transition: all var(--ease);
281
+ font-size: var(--t-xs); font-weight: 500; transition: all var(--ease); box-shadow: var(--shadow);
230
282
  }
231
- main > nav a:hover { border-color: var(--violet); color: var(--violet); }
283
+ main > nav a:hover { border-color: var(--violet); color: var(--violet); transform: translateY(-1px); }
232
284
 
233
285
  /* Trust */
234
- blockquote {
235
- margin: var(--g5) auto var(--g6); padding: var(--g5) var(--g4); max-width: var(--w-8);
236
- background: var(--teal-s); border: 1px solid rgba(13,148,136,.12);
237
- border-radius: var(--r-lg); text-align: center; border-left: none;
286
+ .trust {
287
+ margin: var(--g6) auto; padding: var(--g5); max-width: var(--w-8);
288
+ background: linear-gradient(135deg, var(--teal-s) 0%, #f0fdf8 100%);
289
+ border: 1px solid rgba(13,148,136,.15); border-radius: var(--r-lg); text-align: center;
290
+ }
291
+ .trust strong {
292
+ display: block; font-size: var(--t-lg); line-height: 1.3; margin-bottom: var(--g4); color: var(--teal);
293
+ }
294
+ .trust ul { list-style: none; padding: 0; display: flex; flex-direction: column; gap: var(--g2); }
295
+ .trust li {
296
+ font-size: var(--t-sm); color: var(--ink-2); line-height: 1.5;
297
+ display: flex; align-items: center; justify-content: center; gap: var(--g1);
238
298
  }
239
- blockquote strong { display: block; font-size: var(--t-md); line-height: 1.35; margin-bottom: var(--g2); color: var(--teal); }
240
- blockquote p { color: var(--ink-2); margin: 0 auto; font-size: var(--t-sm); }
299
+ .trust li::before { content: '✓'; color: var(--teal); font-weight: 700; }
241
300
 
242
301
  /* Forms */
243
302
  label { display: block; font-size: var(--t-sm); color: var(--ink-2); font-weight: 500; margin-bottom: var(--g1); }
244
303
  input[type="text"] {
245
- display: block; width: 100%; margin-top: var(--g1); height: var(--g5);
246
- padding: 0 var(--g2); background: var(--white); border: 1px solid var(--line);
304
+ display: block; width: 100%; margin-top: var(--g1); height: 48px;
305
+ padding: 0 var(--g3); background: var(--white); border: 1px solid var(--line);
247
306
  border-radius: var(--r); color: var(--ink); font-size: var(--t-sm); font-family: var(--font);
248
307
  transition: border-color var(--ease);
249
308
  }
250
- input[type="text"]:focus { outline: none; border-color: var(--violet); box-shadow: 0 0 0 3px rgba(124,92,252,.08); }
309
+ input[type="text"]:focus { outline: none; border-color: var(--violet); box-shadow: 0 0 0 3px var(--violet-glow); }
251
310
  form:not([role="search"]) button[type="submit"] {
252
- margin-top: var(--g3); height: var(--g5); padding: 0 var(--g4);
311
+ margin-top: var(--g3); height: 48px; padding: 0 var(--g4);
253
312
  border: none; border-radius: var(--pill); background: var(--violet); color: var(--white);
254
313
  font-size: var(--t-sm); font-weight: 600; font-family: var(--font); cursor: pointer;
255
- transition: background var(--ease);
314
+ transition: all var(--ease); box-shadow: 0 4px 14px var(--violet-glow);
256
315
  }
257
- form:not([role="search"]) button[type="submit"]:hover { background: var(--ink); }
316
+ form:not([role="search"]) button[type="submit"]:hover { background: var(--ink); transform: translateY(-1px); }
258
317
 
259
318
  /* Responsive */
260
319
  @media (max-width: 640px) {
261
320
  :root { --pad: var(--g3); }
262
321
  main { padding: 0 var(--pad) var(--g5); }
263
- hgroup { padding: var(--g5) var(--pad); }
322
+ hgroup { padding: var(--g6) var(--pad) var(--g5); }
264
323
  section:has(> article[itemscope]) { grid-template-columns: 1fr; }
265
324
  section > ol { grid-template-columns: 1fr; }
266
- section > dl { grid-template-columns: 1fr; max-width: var(--w-6); padding: var(--g4); }
325
+ section > dl { grid-template-columns: 1fr; max-width: 100%; padding: var(--g4); }
267
326
  main > article { padding: var(--g4); }
268
327
  main > article dl { grid-template-columns: 1fr; gap: calc(var(--g1) / 2) 0; }
269
328
  main > article dt { margin-top: var(--g2); }
270
- form[role="search"] { height: var(--g4); }
329
+ form[role="search"] { height: 44px; }
271
330
  form[role="search"] input { font-size: var(--t-xs); }
331
+ .trust ul { text-align: left; }
272
332
  }
@@ -7,6 +7,7 @@ export interface CatalogHeroProps {
7
7
  searchAction?: string;
8
8
  searchPlaceholder?: string;
9
9
  searchValue?: string;
10
+ ctas?: { label: string; href: string }[];
10
11
  }
11
12
 
12
13
  export function catalogHero(p: CatalogHeroProps): string {
@@ -16,17 +17,31 @@ export function catalogHero(p: CatalogHeroProps): string {
16
17
  <input type="search" name="q" placeholder="${esc(p.searchPlaceholder ?? 'Szukaj...')}" value="${esc(p.searchValue ?? '')}" />
17
18
  <button type="submit">Szukaj</button>
18
19
  </form>` : '';
20
+ const ctas = p.ctas?.length ? `<p class="hero-ctas">${p.ctas.map(
21
+ (c, i) => `<a href="${esc(c.href)}" class="${i === 0 ? 'cta-primary' : 'cta-secondary'}">${esc(c.label)}</a>`
22
+ ).join('\n')}</p>` : '';
19
23
  return `<hgroup>
20
24
  ${badge}
21
- <h1>${esc(p.title)}</h1>
25
+ <h1>${p.title}</h1>
22
26
  ${subtitle}
23
27
  ${search}
28
+ ${ctas}
24
29
  </hgroup>`;
25
30
  }
26
31
 
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>`;
32
+ const STAT_ICONS: Record<string, string> = {
33
+ people: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2"/><circle cx="9" cy="7" r="4"/><path d="M23 21v-2a4 4 0 0 0-3-3.87"/><path d="M16 3.13a4 4 0 0 1 0 7.75"/></svg>',
34
+ city: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M3 21h18"/><path d="M5 21V7l8-4v18"/><path d="M19 21V11l-6-4"/><path d="M9 9v.01M9 12v.01M9 15v.01M9 18v.01"/></svg>',
35
+ free: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M22 11.08V12a10 10 0 1 1-5.93-9.14"/><polyline points="22 4 12 14.01 9 11.01"/></svg>',
36
+ };
37
+
38
+ export function statBar(items: { value: string; label: string; icon?: string }[], summary?: string): string {
39
+ const divs = items.map(i => {
40
+ const icon = i.icon && STAT_ICONS[i.icon] ? `<span class="stat-icon">${STAT_ICONS[i.icon]}</span>` : '';
41
+ return `<div>${icon}<dt>${esc(i.value)}</dt><dd>${esc(i.label)}</dd></div>`;
42
+ }).join('\n');
43
+ const summaryP = summary ? `<p>${esc(summary)}</p>` : '';
44
+ return `<section aria-label="Statystyki">${summaryP}<dl>\n${divs}\n</dl></section>`;
30
45
  }
31
46
 
32
47
  export function categoryNav(items: { href: string; label: string }[], ariaLabel = 'Kategorie'): string {
@@ -40,8 +55,12 @@ export function steps(title: string, items: { title: string; description: string
40
55
  return `<section>\n<h2>${esc(title)}</h2>\n<ol>\n${lis}\n</ol>\n</section>`;
41
56
  }
42
57
 
43
- export function trustBlock(title: string, body: string): string {
44
- return `<blockquote>\n<strong>${esc(title)}</strong>\n<p>${esc(body)}</p>\n</blockquote>`;
58
+ export function trustBlock(title: string, points: string[]): string {
59
+ const items = points.map(p => `<li>${esc(p)}</li>`).join('\n');
60
+ return `<aside class="trust">
61
+ <strong>${esc(title)}</strong>
62
+ <ul>${items}</ul>
63
+ </aside>`;
45
64
  }
46
65
 
47
66
  export interface PaginationProps {
@@ -58,6 +77,6 @@ export function pagination(p: PaginationProps): string {
58
77
  const base = p.baseHref ?? '/';
59
78
  const extra = p.extraParams ?? '';
60
79
  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>` : '';
80
+ const next = p.current < p.total ? `<a href="${esc(base)}?p=${p.current + 1}${extra}">${esc(p.nextLabel ?? 'Następna \u2192')}</a>` : '';
62
81
  return `<nav><p>${prev} Strona ${p.current} z ${p.total} ${next}</p></nav>`;
63
82
  }
@@ -3,21 +3,25 @@ import { esc, fullName } from './helpers.ts';
3
3
 
4
4
  export function profileCard(p: Profile, href: string): string {
5
5
  const name = fullName(p);
6
+ const initials = `${(p.firstName?.[0] ?? '').toUpperCase()}${(p.lastName?.[0] ?? '').toUpperCase()}`;
6
7
 
7
- const city = p.city ? ` &middot; <span itemprop="address" itemscope itemtype="https://schema.org/PostalAddress"><span itemprop="addressLocality">${esc(p.city)}</span></span>` : '';
8
+ const city = p.city ? `<span itemprop="address" itemscope itemtype="https://schema.org/PostalAddress"><span itemprop="addressLocality">${esc(p.city)}</span></span>` : '';
8
9
 
9
10
  const bio = p.bio ? `<p itemprop="description">${esc(p.bio)}</p>` : '';
10
11
 
11
12
  const specs = p.specialties.length > 0
12
- ? `<p><small>${p.specialties.map(s => esc(s)).join(' &middot; ')}</small></p>`
13
+ ? `<ul>${p.specialties.slice(0, 3).map(s => `<li>${esc(s)}</li>`).join('')}</ul>`
13
14
  : '';
14
15
 
15
16
  return `<article itemscope itemtype="https://schema.org/Person">
17
+ <div class="card-avatar" aria-hidden="true">${initials}</div>
16
18
  <header>
17
19
  <h2><a href="${esc(href)}" itemprop="url"><span itemprop="name">${esc(name)}</span></a></h2>
18
- <p><span itemprop="jobTitle">${esc(p.jobTitle)}</span>${city}</p>
20
+ <p><span itemprop="jobTitle">${esc(p.jobTitle)}</span></p>
21
+ ${city ? `<p class="card-city">${city}</p>` : ''}
19
22
  </header>
20
23
  ${bio}
21
24
  ${specs}
25
+ <a href="${esc(href)}" class="card-cta">Zobacz profil &rarr;</a>
22
26
  </article>`;
23
27
  }