@press2ai/theme-specialist-glossy 0.4.4 → 0.5.1

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.1",
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); }
@@ -145,19 +172,34 @@ nav[aria-label] a:nth-child(5n+3):hover { border-color: var(--rose); color: var(
145
172
  nav[aria-label] a:nth-child(5n+4):hover { border-color: var(--amber); color: var(--amber); background: var(--amber-s); }
146
173
  nav[aria-label] a:nth-child(5n+5):hover { border-color: var(--sky); color: var(--sky); background: var(--sky-s); }
147
174
 
175
+ /* How it works — full-bleed band */
176
+ .how-it-works {
177
+ margin: 0 calc(50% - 50vw) var(--g7) calc(50% - 50vw);
178
+ padding: var(--g7) var(--pad);
179
+ background: var(--white);
180
+ border-top: 1px solid var(--line);
181
+ border-bottom: 1px solid var(--line);
182
+ }
183
+ .how-it-works > section {
184
+ max-width: var(--container);
185
+ margin: 0 auto;
186
+ }
187
+
148
188
  /* Steps */
149
- section:has(> ol) > h2 { text-align: center; }
189
+ section:has(> ol) > h2 { text-align: center; margin-bottom: var(--g5); }
150
190
  section > ol {
151
191
  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;
192
+ grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: var(--g4); margin: 0; counter-reset: steps;
153
193
  }
154
194
  section > ol li {
155
195
  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;
196
+ border-radius: var(--r-lg); padding: var(--g5) var(--g4); text-align: center;
197
+ box-shadow: var(--shadow); transition: all var(--ease);
157
198
  }
199
+ section > ol li:hover { transform: translateY(-2px); box-shadow: var(--shadow-md); }
158
200
  section > ol li::before {
159
201
  content: counter(steps); display: flex; align-items: center; justify-content: center;
160
- width: var(--g5); height: var(--g5); margin: 0 auto var(--g3);
202
+ width: 48px; height: 48px; margin: 0 auto var(--g3);
161
203
  border-radius: 50%; font-size: var(--t-md); font-weight: 700;
162
204
  }
163
205
  section > ol li:nth-child(5n+1)::before { background: var(--violet-s); color: var(--violet); }
@@ -165,42 +207,64 @@ section > ol li:nth-child(5n+2)::before { background: var(--teal-s); color: var(
165
207
  section > ol li:nth-child(5n+3)::before { background: var(--amber-s); color: var(--amber); }
166
208
  section > ol li:nth-child(5n+4)::before { background: var(--rose-s); color: var(--rose); }
167
209
  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); }
210
+ section > ol li strong { display: block; font-size: var(--t-md); line-height: 1.4; margin-bottom: var(--g1); color: var(--ink); }
211
+ section > ol li span { font-size: var(--t-sm); line-height: 1.5; color: var(--ink-3); }
170
212
 
171
213
  /* Trainer cards */
172
214
  section:has(> article[itemscope]) {
173
- display: grid; grid-template-columns: repeat(auto-fill, minmax(var(--w-6), 1fr)); gap: var(--g3);
215
+ display: grid; grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); gap: var(--g4);
174
216
  }
175
217
  section:has(> article[itemscope]) > h2 { grid-column: 1 / -1; margin-bottom: var(--g4); }
176
218
  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); }
219
+ position: relative; background: var(--card); border: 1px solid var(--line);
220
+ border-radius: var(--r-lg); padding: var(--g4);
221
+ display: flex; flex-direction: column;
222
+ box-shadow: var(--shadow); transition: all var(--ease);
223
+ }
224
+ article[itemscope]:hover { transform: translateY(-3px); box-shadow: var(--shadow-up); border-color: var(--line-h); }
225
+
226
+ /* Card avatar */
227
+ .card-avatar {
228
+ width: 48px; height: 48px; border-radius: 50%;
229
+ display: flex; align-items: center; justify-content: center;
230
+ font-size: var(--t-sm); font-weight: 700; color: var(--white);
231
+ margin-bottom: var(--g3); flex-shrink: 0;
232
+ }
233
+ article[itemscope]:nth-child(5n+2) .card-avatar { background: var(--violet); }
234
+ article[itemscope]:nth-child(5n+3) .card-avatar { background: var(--teal); }
235
+ article[itemscope]:nth-child(5n+4) .card-avatar { background: var(--rose); }
236
+ article[itemscope]:nth-child(5n+5) .card-avatar { background: var(--amber); }
237
+ article[itemscope]:nth-child(5n+6) .card-avatar { background: var(--sky); }
238
+ article[itemscope]:nth-child(5n+1) .card-avatar,
239
+ article[itemscope]:first-child .card-avatar { background: var(--violet); }
240
+
187
241
  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); }
242
+ article[itemscope] h2 { font-size: var(--t-md); line-height: 1.3; margin: 0 0 4px; }
189
243
  article[itemscope] h2 a { color: var(--ink); }
190
244
  article[itemscope] h2 a:hover { color: var(--violet); }
191
245
  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;
246
+ .card-city { display: inline-flex; align-items: center; gap: 4px; margin-top: 4px; color: var(--ink-3); font-size: var(--t-xs); }
247
+ .card-city::before { content: ''; display: inline-block; width: 3px; height: 3px; border-radius: 50%; background: var(--ink-3); }
248
+ article[itemscope] [itemprop="description"] { font-size: var(--t-xs); line-height: 1.5; margin: var(--g2) 0 0; color: var(--ink-2); }
249
+ article[itemscope] ul { list-style: none; padding: 0; display: flex; flex-wrap: wrap; gap: 6px; margin-top: var(--g2); }
250
+ article[itemscope] ul li {
251
+ background: var(--violet-s); color: var(--violet);
252
+ padding: 2px var(--g1); border-radius: var(--pill); font-size: 0.7rem; font-weight: 500;
198
253
  }
199
254
 
255
+ /* Card CTA */
256
+ .card-cta {
257
+ display: inline-flex; align-items: center; margin-top: auto; padding-top: var(--g3);
258
+ font-size: var(--t-xs); font-weight: 600; color: var(--violet);
259
+ transition: all var(--ease);
260
+ }
261
+ .card-cta:hover { color: var(--ink); gap: 6px; }
262
+
200
263
  /* Single trainer */
201
264
  main > article {
202
265
  max-width: var(--w-8); margin: 0 auto; background: var(--card);
203
266
  border: 1px solid var(--line); border-radius: var(--r-lg); padding: var(--g5);
267
+ box-shadow: var(--shadow-md);
204
268
  }
205
269
  main > article > header { border-bottom: 1px solid var(--line); padding-bottom: var(--g3); margin-bottom: var(--g4); }
206
270
  main > article > header h1 { margin-bottom: var(--g2); }
@@ -225,49 +289,57 @@ main > article > footer { margin-top: var(--g5); padding-top: var(--g3); border-
225
289
  /* Pagination */
226
290
  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
291
  main > nav a {
228
- height: var(--g4); display: inline-flex; align-items: center; padding: 0 var(--g2);
292
+ height: 36px; display: inline-flex; align-items: center; padding: 0 var(--g3);
229
293
  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);
294
+ font-size: var(--t-xs); font-weight: 500; transition: all var(--ease); box-shadow: var(--shadow);
231
295
  }
232
- main > nav a:hover { border-color: var(--violet); color: var(--violet); }
296
+ main > nav a:hover { border-color: var(--violet); color: var(--violet); transform: translateY(-1px); }
233
297
 
234
298
  /* 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;
299
+ .trust {
300
+ margin: var(--g6) auto; padding: var(--g5); max-width: var(--w-8);
301
+ background: linear-gradient(135deg, var(--teal-s) 0%, #f0fdf8 100%);
302
+ border: 1px solid rgba(13,148,136,.15); border-radius: var(--r-lg); text-align: center;
303
+ }
304
+ .trust strong {
305
+ display: block; font-size: var(--t-lg); line-height: 1.3; margin-bottom: var(--g4); color: var(--teal);
306
+ }
307
+ .trust ul { list-style: none; padding: 0; display: flex; flex-direction: column; gap: var(--g2); }
308
+ .trust li {
309
+ font-size: var(--t-sm); color: var(--ink-2); line-height: 1.5;
310
+ display: flex; align-items: center; justify-content: center; gap: var(--g1);
239
311
  }
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); }
312
+ .trust li::before { content: '✓'; color: var(--teal); font-weight: 700; }
242
313
 
243
314
  /* Forms */
244
315
  label { display: block; font-size: var(--t-sm); color: var(--ink-2); font-weight: 500; margin-bottom: var(--g1); }
245
316
  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);
317
+ display: block; width: 100%; margin-top: var(--g1); height: 48px;
318
+ padding: 0 var(--g3); background: var(--white); border: 1px solid var(--line);
248
319
  border-radius: var(--r); color: var(--ink); font-size: var(--t-sm); font-family: var(--font);
249
320
  transition: border-color var(--ease);
250
321
  }
251
- input[type="text"]:focus { outline: none; border-color: var(--violet); box-shadow: 0 0 0 3px rgba(124,92,252,.08); }
322
+ input[type="text"]:focus { outline: none; border-color: var(--violet); box-shadow: 0 0 0 3px var(--violet-glow); }
252
323
  form:not([role="search"]) button[type="submit"] {
253
- margin-top: var(--g3); height: var(--g5); padding: 0 var(--g4);
324
+ margin-top: var(--g3); height: 48px; padding: 0 var(--g4);
254
325
  border: none; border-radius: var(--pill); background: var(--violet); color: var(--white);
255
326
  font-size: var(--t-sm); font-weight: 600; font-family: var(--font); cursor: pointer;
256
- transition: background var(--ease);
327
+ transition: all var(--ease); box-shadow: 0 4px 14px var(--violet-glow);
257
328
  }
258
- form:not([role="search"]) button[type="submit"]:hover { background: var(--ink); }
329
+ form:not([role="search"]) button[type="submit"]:hover { background: var(--ink); transform: translateY(-1px); }
259
330
 
260
331
  /* Responsive */
261
332
  @media (max-width: 640px) {
262
333
  :root { --pad: var(--g3); }
263
334
  main { padding: 0 var(--pad) var(--g5); }
264
- hgroup { padding: var(--g5) var(--pad); }
335
+ hgroup { padding: var(--g6) var(--pad) var(--g5); }
265
336
  section:has(> article[itemscope]) { grid-template-columns: 1fr; }
266
337
  section > ol { grid-template-columns: 1fr; }
267
- section > dl { grid-template-columns: 1fr; max-width: var(--w-6); padding: var(--g4); }
338
+ section > dl { grid-template-columns: 1fr; max-width: 100%; padding: var(--g4); }
268
339
  main > article { padding: var(--g4); }
269
340
  main > article dl { grid-template-columns: 1fr; gap: calc(var(--g1) / 2) 0; }
270
341
  main > article dt { margin-top: var(--g2); }
271
- form[role="search"] { height: var(--g4); }
342
+ form[role="search"] { height: 44px; }
272
343
  form[role="search"] input { font-size: var(--t-xs); }
344
+ .trust ul { text-align: left; }
273
345
  }
@@ -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
  }