@press2ai/theme-specialist-glossy 0.4.4 → 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.4",
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,30 +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 */
124
- section[aria-label] > p { text-align: center; font-size: var(--t-sm); color: var(--ink-2); margin: 0 auto var(--g3); max-width: var(--measure); }
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); }
125
148
  section:has(> dl) { margin-bottom: 0; }
126
149
  section > dl {
127
- display: grid; grid-template-columns: repeat(auto-fit, minmax(100px, 1fr)); gap: var(--g3);
128
- 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);
129
152
  background: var(--white); border: 1px solid var(--line); border-radius: var(--r-lg);
153
+ box-shadow: var(--shadow-md);
130
154
  }
131
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; }
132
158
  section > dl dt { font-size: var(--t-xl); font-weight: 800; line-height: 1.2; color: var(--violet); }
133
- 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; }
134
160
 
135
161
  /* Category pills */
136
- 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); }
137
163
  nav[aria-label] a {
138
- 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);
139
165
  border-radius: var(--pill); font-size: var(--t-xs); font-weight: 500;
140
- 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);
141
168
  }
142
169
  nav[aria-label] a:nth-child(5n+1):hover { border-color: var(--violet); color: var(--violet); background: var(--violet-s); }
143
170
  nav[aria-label] a:nth-child(5n+2):hover { border-color: var(--teal); color: var(--teal); background: var(--teal-s); }
@@ -146,18 +173,20 @@ nav[aria-label] a:nth-child(5n+4):hover { border-color: var(--amber); color: var
146
173
  nav[aria-label] a:nth-child(5n+5):hover { border-color: var(--sky); color: var(--sky); background: var(--sky-s); }
147
174
 
148
175
  /* Steps */
149
- section:has(> ol) > h2 { text-align: center; }
176
+ section:has(> ol) > h2 { text-align: center; margin-bottom: var(--g5); }
150
177
  section > ol {
151
178
  list-style: none; padding: 0; display: grid;
152
- 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;
153
180
  }
154
181
  section > ol li {
155
182
  counter-increment: steps; background: var(--white); border: 1px solid var(--line);
156
- 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);
157
185
  }
186
+ section > ol li:hover { transform: translateY(-2px); box-shadow: var(--shadow-md); }
158
187
  section > ol li::before {
159
188
  content: counter(steps); display: flex; align-items: center; justify-content: center;
160
- width: var(--g5); height: var(--g5); margin: 0 auto var(--g3);
189
+ width: 48px; height: 48px; margin: 0 auto var(--g3);
161
190
  border-radius: 50%; font-size: var(--t-md); font-weight: 700;
162
191
  }
163
192
  section > ol li:nth-child(5n+1)::before { background: var(--violet-s); color: var(--violet); }
@@ -165,42 +194,64 @@ section > ol li:nth-child(5n+2)::before { background: var(--teal-s); color: var(
165
194
  section > ol li:nth-child(5n+3)::before { background: var(--amber-s); color: var(--amber); }
166
195
  section > ol li:nth-child(5n+4)::before { background: var(--rose-s); color: var(--rose); }
167
196
  section > ol li:nth-child(5n+5)::before { background: var(--sky-s); color: var(--sky); }
168
- section > ol li strong { display: block; font-size: var(--t-sm); line-height: 1.5; margin-bottom: var(--g1); color: var(--ink); }
169
- 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); }
170
199
 
171
200
  /* Trainer cards */
172
201
  section:has(> article[itemscope]) {
173
- 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);
174
203
  }
175
204
  section:has(> article[itemscope]) > h2 { grid-column: 1 / -1; margin-bottom: var(--g4); }
176
205
  article[itemscope] {
177
- background: var(--card); border: 1px solid var(--line); border-left: 3px solid var(--line);
178
- border-radius: var(--r-lg); padding: var(--g4) var(--g3);
179
- transition: border-color var(--ease), box-shadow var(--ease);
180
- }
181
- article[itemscope]:hover { border-color: var(--line-h); box-shadow: var(--shadow-up); }
182
- article[itemscope]:nth-child(5n+2) { border-left-color: var(--violet); }
183
- article[itemscope]:nth-child(5n+3) { border-left-color: var(--teal); }
184
- article[itemscope]:nth-child(5n+4) { border-left-color: var(--rose); }
185
- article[itemscope]:nth-child(5n+5) { border-left-color: var(--amber); }
186
- 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
+
187
228
  article[itemscope] header { margin-bottom: var(--g2); }
188
- 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; }
189
230
  article[itemscope] h2 a { color: var(--ink); }
190
231
  article[itemscope] h2 a:hover { color: var(--violet); }
191
232
  article[itemscope] header p { font-size: var(--t-xs); line-height: 1.5; color: var(--ink-3); margin: 0; }
192
- article[itemscope] [itemprop="description"] { font-size: var(--t-xs); line-height: 1.5; margin: var(--g1) 0 0; color: var(--ink-2); }
193
- article[itemscope] [itemprop="jobTitle"],
194
- article[itemscope] [itemprop="addressLocality"] { color: var(--ink-3); }
195
- article[itemscope] > p:last-child small {
196
- display: inline-block; margin-top: var(--g2); background: var(--violet-s); color: var(--violet);
197
- 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);
198
247
  }
248
+ .card-cta:hover { color: var(--ink); gap: 6px; }
199
249
 
200
250
  /* Single trainer */
201
251
  main > article {
202
252
  max-width: var(--w-8); margin: 0 auto; background: var(--card);
203
253
  border: 1px solid var(--line); border-radius: var(--r-lg); padding: var(--g5);
254
+ box-shadow: var(--shadow-md);
204
255
  }
205
256
  main > article > header { border-bottom: 1px solid var(--line); padding-bottom: var(--g3); margin-bottom: var(--g4); }
206
257
  main > article > header h1 { margin-bottom: var(--g2); }
@@ -225,49 +276,57 @@ main > article > footer { margin-top: var(--g5); padding-top: var(--g3); border-
225
276
  /* Pagination */
226
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); }
227
278
  main > nav a {
228
- 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);
229
280
  border-radius: var(--pill); background: var(--white); border: 1px solid var(--line);
230
- 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);
231
282
  }
232
- 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); }
233
284
 
234
285
  /* Trust */
235
- blockquote {
236
- margin: var(--g5) auto var(--g6); padding: var(--g5) var(--g4); max-width: var(--w-8);
237
- background: var(--teal-s); border: 1px solid rgba(13,148,136,.12);
238
- 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);
239
298
  }
240
- blockquote strong { display: block; font-size: var(--t-md); line-height: 1.35; margin-bottom: var(--g2); color: var(--teal); }
241
- 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; }
242
300
 
243
301
  /* Forms */
244
302
  label { display: block; font-size: var(--t-sm); color: var(--ink-2); font-weight: 500; margin-bottom: var(--g1); }
245
303
  input[type="text"] {
246
- display: block; width: 100%; margin-top: var(--g1); height: var(--g5);
247
- 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);
248
306
  border-radius: var(--r); color: var(--ink); font-size: var(--t-sm); font-family: var(--font);
249
307
  transition: border-color var(--ease);
250
308
  }
251
- 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); }
252
310
  form:not([role="search"]) button[type="submit"] {
253
- margin-top: var(--g3); height: var(--g5); padding: 0 var(--g4);
311
+ margin-top: var(--g3); height: 48px; padding: 0 var(--g4);
254
312
  border: none; border-radius: var(--pill); background: var(--violet); color: var(--white);
255
313
  font-size: var(--t-sm); font-weight: 600; font-family: var(--font); cursor: pointer;
256
- transition: background var(--ease);
314
+ transition: all var(--ease); box-shadow: 0 4px 14px var(--violet-glow);
257
315
  }
258
- 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); }
259
317
 
260
318
  /* Responsive */
261
319
  @media (max-width: 640px) {
262
320
  :root { --pad: var(--g3); }
263
321
  main { padding: 0 var(--pad) var(--g5); }
264
- hgroup { padding: var(--g5) var(--pad); }
322
+ hgroup { padding: var(--g6) var(--pad) var(--g5); }
265
323
  section:has(> article[itemscope]) { grid-template-columns: 1fr; }
266
324
  section > ol { grid-template-columns: 1fr; }
267
- 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); }
268
326
  main > article { padding: var(--g4); }
269
327
  main > article dl { grid-template-columns: 1fr; gap: calc(var(--g1) / 2) 0; }
270
328
  main > article dt { margin-top: var(--g2); }
271
- form[role="search"] { height: var(--g4); }
329
+ form[role="search"] { height: 44px; }
272
330
  form[role="search"] input { font-size: var(--t-xs); }
331
+ .trust ul { text-align: left; }
273
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,16 +17,29 @@ 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 }[], summary?: string): string {
28
- const divs = items.map(i => `<div><dt>${esc(i.value)}</dt><dd>${esc(i.label)}</dd></div>`).join('\n');
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');
29
43
  const summaryP = summary ? `<p>${esc(summary)}</p>` : '';
30
44
  return `<section aria-label="Statystyki">${summaryP}<dl>\n${divs}\n</dl></section>`;
31
45
  }
@@ -41,8 +55,12 @@ export function steps(title: string, items: { title: string; description: string
41
55
  return `<section>\n<h2>${esc(title)}</h2>\n<ol>\n${lis}\n</ol>\n</section>`;
42
56
  }
43
57
 
44
- export function trustBlock(title: string, body: string): string {
45
- 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>`;
46
64
  }
47
65
 
48
66
  export interface PaginationProps {
@@ -59,6 +77,6 @@ export function pagination(p: PaginationProps): string {
59
77
  const base = p.baseHref ?? '/';
60
78
  const extra = p.extraParams ?? '';
61
79
  const prev = p.current > 1 ? `<a href="${esc(base)}?p=${p.current - 1}${extra}">${esc(p.prevLabel ?? '\u2190 Poprzednia')}</a>` : '';
62
- 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>` : '';
63
81
  return `<nav><p>${prev} Strona ${p.current} z ${p.total} ${next}</p></nav>`;
64
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
  }