@press2ai/theme-therapy-soft 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@press2ai/theme-therapy-soft",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "description": "Warm sage/beige classless theme for therapy verticals. Crimson Text serif + Inter. Structurally compatible with @press2ai/engine TrenerTheme.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -24,6 +24,10 @@
24
24
  "exports": {
25
25
  ".": "./src/index.ts",
26
26
  "./templates": "./src/templates/index.ts",
27
- "./styles": "./src/styles/index.ts"
27
+ "./styles": "./src/styles/index.ts",
28
+ "./ai": "./src/ai.ts"
29
+ },
30
+ "peerDependencies": {
31
+ "@press2ai/engine": ">=0.4.3"
28
32
  }
29
33
  }
package/src/ai.ts ADDED
@@ -0,0 +1 @@
1
+ export const version = '0.2.0';
package/src/index.ts CHANGED
@@ -1,2 +1,2 @@
1
1
  export { composeCss, allCss } from './styles/index.ts';
2
- export type { TherapyProfile } from './templates/helpers.ts';
2
+ export { version } from './ai.ts';
@@ -1,82 +1,64 @@
1
- export const css = `:root {
2
- --font-sans: 'Inter', system-ui, -apple-system, sans-serif;
3
- --font-serif: 'Crimson Text', Georgia, 'Times New Roman', serif;
1
+ export const css = `@import url('https://fonts.googleapis.com/css2?family=Fraunces:ital,opsz,wght@0,9..144,300;0,9..144,400;0,9..144,600;1,9..144,400&family=DM+Sans:wght@400;500;600&display=swap');
4
2
 
5
- --g1: 0.5rem; --g2: 0.8125rem; --g3: 1.3125rem; --g4: 2.125rem; --g5: 3.4375rem; --g6: 5.5625rem; --g7: 9rem;
6
- --t-xs: 0.8125rem; --t-sm: 1rem; --t-md: 1.25rem; --t-lg: 1.625rem; --t-xl: 2.125rem; --t-2xl: 2.875rem; --t-3xl: 3.75rem;
7
- --container: 1180px; --pad: var(--g4);
8
- --w-6: 520px; --w-8: 720px; --w-10: 880px; --measure: 38rem;
3
+ :root {
4
+ --font-sans: 'DM Sans', system-ui, -apple-system, sans-serif;
5
+ --font-display: 'Fraunces', Georgia, serif;
9
6
 
10
- --sage-50: #f7f5f2;
11
- --sage-100: #efece7;
12
- --sage-200: #dde2dd;
13
- --sage-400: #a8baa8;
14
- --sage-500: #8ea78e;
15
- --sage-600: #7a8f7a;
16
- --sage-700: #6a7f6a;
17
- --sage-800: #4f5f4f;
7
+ --g1: 0.5rem; --g2: 0.75rem; --g3: 1rem; --g4: 1.5rem; --g5: 2.5rem; --g6: 4rem; --g7: 6rem;
8
+ --t-xs: 0.8125rem; --t-sm: 0.9375rem; --t-md: 1.125rem; --t-lg: 1.5625rem; --t-xl: 2.125rem; --t-2xl: 2.5rem; --t-3xl: 3.5rem;
9
+ --container: 1200px; --pad: var(--g5);
10
+ --measure: 38rem;
18
11
 
19
- --beige-50: #faf5ef;
20
- --beige-100: #f3ece4;
21
- --beige-200: #e8ddd0;
12
+ --purple: #a293ff;
13
+ --purple-soft: #efebff;
14
+ --purple-dark: #8677e0;
15
+ --gold: #f0be37;
16
+ --gold-soft: #fff5da;
17
+ --navy: #1d1d46;
18
+ --navy-2: #3d3d66;
19
+ --gray: #6e7878;
20
+ --gray-light: #d9e0e1;
21
+ --gray-bg: #f5f7f7;
22
+ --teal-soft: #ecf6f5;
23
+ --peach-soft: #fff6f1;
24
+ --white: #ffffff;
22
25
 
23
- --stone-300: #d6d3d1;
24
- --stone-400: #a8a29e;
25
- --stone-500: #78716c;
26
- --stone-600: #57534e;
27
- --stone-700: #44403c;
28
- --stone-900: #1c1917;
26
+ --bg: var(--white);
27
+ --card: var(--white);
28
+ --ink: var(--navy);
29
+ --ink-2: var(--gray);
30
+ --line: var(--gray-light);
29
31
 
30
- --emerald-100: #d1fae5;
31
- --emerald-700: #047857;
32
- --amber-100: #fef3c7;
33
- --amber-700: #b45309;
34
-
35
- --bg: var(--sage-50);
36
- --card: var(--beige-50);
37
- --ink: var(--stone-900);
38
- --ink-2: var(--stone-600);
39
- --ink-3: var(--stone-500);
40
- --line: var(--stone-300);
41
- --line-soft: var(--beige-200);
42
- --accent: var(--sage-600);
43
- --accent-h: var(--sage-700);
44
- --accent-soft: var(--sage-100);
45
-
46
- --r: 4px; --r-lg: 8px; --pill: 999px;
47
- --shadow: 0 1px 2px rgba(60,50,40,.04);
48
- --shadow-md: 0 4px 16px rgba(60,50,40,.06), 0 1px 3px rgba(60,50,40,.04);
49
- --shadow-up: 0 12px 28px rgba(60,50,40,.10), 0 2px 6px rgba(60,50,40,.04);
50
- --ease: 220ms cubic-bezier(.4,0,.2,1);
32
+ --r: 8px; --r-lg: 20px; --r-btn: 12px;
33
+ --shadow: 0 1px 3px rgba(29,29,70,.06);
34
+ --shadow-md: 0 4px 20px rgba(29,29,70,.08);
35
+ --shadow-up: 0 12px 32px rgba(29,29,70,.12);
36
+ --ease: 200ms cubic-bezier(.4,0,.2,1);
51
37
  }
52
38
  *, *::before, *::after { box-sizing: border-box; margin: 0; }
53
39
  html { font-size: 16px; -webkit-font-smoothing: antialiased; scroll-behavior: smooth; }
54
40
  body {
55
41
  font-family: var(--font-sans); font-weight: 400;
56
- color: var(--ink); background: var(--bg); line-height: 1.65; overflow-x: clip;
42
+ color: var(--ink); background: var(--bg); line-height: 1.5; overflow-x: clip;
57
43
  }
58
44
  h1, h2, h3, h4 {
59
- color: var(--ink); font-family: var(--font-serif); font-weight: 600;
60
- letter-spacing: -0.01em; line-height: 1.15;
61
- }
62
- h1 { font-size: clamp(var(--t-2xl), 5.5vw, var(--t-3xl)); margin-bottom: var(--g3); }
63
- h2 { font-size: clamp(var(--t-lg), 3vw, var(--t-xl)); margin-bottom: var(--g2); }
64
- h3 { font-size: var(--t-md); font-weight: 600; line-height: 1.35; margin-bottom: var(--g2); }
65
- h4 { font-size: var(--t-sm); font-weight: 600; }
66
- p {
67
- font-size: var(--t-sm); line-height: 1.7; color: var(--ink-2);
68
- margin-bottom: var(--g2); max-width: var(--measure);
45
+ color: var(--ink); font-family: var(--font-display); font-weight: 400;
46
+ line-height: 1.2; letter-spacing: -0.02em;
69
47
  }
70
- a { color: var(--accent-h); text-decoration: none; transition: color var(--ease); }
71
- a:hover { color: var(--ink); }
72
- small { font-size: var(--t-xs); color: var(--ink-3); }
48
+ h1 { font-size: clamp(var(--t-2xl), 5.5vw, var(--t-3xl)); margin-bottom: var(--g4); }
49
+ h2 { font-size: clamp(var(--t-lg), 3vw, var(--t-2xl)); margin-bottom: var(--g3); }
50
+ h3 { font-size: var(--t-md); font-weight: 500; font-family: var(--font-sans); margin-bottom: var(--g2); }
51
+ p { font-size: var(--t-sm); line-height: 1.6; color: var(--ink-2); margin-bottom: var(--g2); max-width: var(--measure); }
52
+ a { color: var(--purple); text-decoration: none; transition: color var(--ease); }
53
+ a:hover { color: var(--navy); }
54
+ small { font-size: var(--t-xs); color: var(--ink-2); }
73
55
  strong { color: var(--ink); font-weight: 600; }
74
56
  main {
75
57
  max-width: var(--container); margin-inline: auto;
76
58
  padding-inline: var(--pad); padding-top: 0; padding-bottom: 0;
77
59
  }
78
60
  main:not(:has(> section, > article, > div, > nav)) {
79
- padding-top: var(--g5); padding-bottom: var(--g5);
61
+ padding-top: var(--g6); padding-bottom: var(--g6);
80
62
  }
81
63
  main > * + * { margin-top: var(--g6); }
82
64
  @media (max-width: 640px) {
@@ -1,20 +1,13 @@
1
1
  export const css = `section:has(> article[itemscope]) {
2
2
  display: grid; grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
3
- gap: var(--g3);
3
+ gap: var(--g4);
4
4
  }
5
5
  section:has(> article[itemscope]) > h2 {
6
6
  grid-column: 1 / -1; text-align: center; margin-bottom: var(--g4);
7
- font-family: var(--font-serif); font-weight: 400;
8
- font-size: clamp(var(--t-lg), 3vw, var(--t-xl));
9
- }
10
- section:has(> article[itemscope]) > h2::before {
11
- content: 'Nasi terapeuci'; display: block;
12
- font-family: var(--font-sans); font-size: var(--t-xs); font-weight: 500;
13
- color: var(--sage-700); letter-spacing: 0.1em; text-transform: uppercase;
14
- margin-bottom: var(--g2);
7
+ font-family: var(--font-display);
15
8
  }
16
9
  section:has(> article[itemscope]) > nav[aria-label] {
17
- grid-column: 1 / -1; margin-bottom: var(--g3);
10
+ grid-column: 1 / -1; margin-bottom: var(--g3); justify-content: center;
18
11
  }
19
12
  @media (max-width: 640px) {
20
13
  section:has(> article[itemscope]) { grid-template-columns: 1fr; }
@@ -3,10 +3,8 @@ export const css = `nav[aria-label] {
3
3
  }
4
4
  nav[aria-label] a {
5
5
  display: inline-flex; align-items: center; height: 40px; padding: 0 var(--g3);
6
- font-size: var(--t-xs); font-weight: 500;
7
- background: var(--beige-50); border: 1px solid var(--line);
8
- color: var(--ink-2); transition: all var(--ease);
6
+ border-radius: var(--r-btn); font-size: var(--t-xs); font-weight: 500;
7
+ background: var(--purple-soft); border: none; color: var(--navy);
8
+ transition: all var(--ease);
9
9
  }
10
- nav[aria-label] a:hover {
11
- background: var(--sage-100); border-color: var(--sage-400); color: var(--sage-700);
12
- }`;
10
+ nav[aria-label] a:hover { background: var(--purple); color: var(--white); }`;
@@ -0,0 +1,18 @@
1
+ export const css = `section[aria-label="CTA"] {
2
+ margin-inline: calc(50% - 50vw); padding: var(--g6) var(--pad);
3
+ background: linear-gradient(170deg, var(--navy) 0%, #2a2a5c 100%);
4
+ text-align: center; color: var(--white);
5
+ }
6
+ section[aria-label="CTA"] > h2 {
7
+ color: var(--white); max-width: 18ch; margin: 0 auto var(--g3);
8
+ }
9
+ section[aria-label="CTA"] > p {
10
+ color: rgba(255,255,255,.7); font-size: var(--t-md); max-width: var(--measure);
11
+ margin: 0 auto var(--g5);
12
+ }
13
+ section[aria-label="CTA"] > a {
14
+ display: inline-flex; align-items: center; height: 56px; padding: 0 var(--g5);
15
+ border-radius: var(--r-btn); background: var(--gold); color: var(--navy);
16
+ font-weight: 600; font-size: var(--t-sm); transition: background var(--ease);
17
+ }
18
+ section[aria-label="CTA"] > a:hover { background: #e5b030; color: var(--navy); }`;
@@ -0,0 +1,25 @@
1
+ export const css = `section[aria-label="FAQ"] {
2
+ max-width: 800px; margin: var(--g6) auto;
3
+ }
4
+ section[aria-label="FAQ"] > h2 { text-align: center; margin-bottom: var(--g5); }
5
+ section[aria-label="FAQ"] details {
6
+ border-bottom: 1px solid var(--line); overflow: hidden;
7
+ }
8
+ section[aria-label="FAQ"] details > summary {
9
+ display: flex; justify-content: space-between; align-items: center;
10
+ padding: var(--g3) 0; cursor: pointer; list-style: none;
11
+ font-family: var(--font-sans); font-size: var(--t-sm); font-weight: 500;
12
+ color: var(--ink); transition: color var(--ease);
13
+ }
14
+ section[aria-label="FAQ"] details > summary::-webkit-details-marker { display: none; }
15
+ section[aria-label="FAQ"] details > summary::after {
16
+ content: '+'; font-size: var(--t-lg); font-weight: 300; color: var(--purple);
17
+ transition: transform var(--ease);
18
+ }
19
+ section[aria-label="FAQ"] details[open] > summary::after {
20
+ content: '−';
21
+ }
22
+ section[aria-label="FAQ"] details > summary:hover { color: var(--purple); }
23
+ section[aria-label="FAQ"] details > div {
24
+ padding: 0 0 var(--g3); font-size: var(--t-sm); line-height: 1.7; color: var(--ink-2);
25
+ }`;
@@ -1,29 +1,36 @@
1
1
  export const css = `body > footer {
2
- border-top: 1px solid var(--line-soft); background: var(--beige-50);
3
- padding: var(--g6) 0 var(--g4); margin-top: var(--g6);
2
+ background: var(--purple); color: var(--white);
3
+ padding: var(--g6) 0 var(--g4); margin-top: var(--g7);
4
4
  }
5
5
  body > footer > small {
6
6
  display: block; max-width: var(--container); margin-inline: auto; padding-inline: var(--pad);
7
- color: var(--ink-3); font-size: var(--t-xs);
7
+ color: rgba(255,255,255,.7); font-size: var(--t-xs);
8
8
  }
9
- body > footer a { color: var(--ink-2); transition: color var(--ease); }
10
- body > footer a:hover { color: var(--accent-h); }
9
+ body > footer a { color: var(--white); transition: opacity var(--ease); }
10
+ body > footer a:hover { opacity: .7; }
11
11
  body > footer > small > nav {
12
12
  display: grid; grid-template-columns: 2fr 1fr 1fr; gap: var(--g5);
13
- margin-bottom: var(--g5); padding-bottom: var(--g4);
14
- border-bottom: 1px solid var(--line-soft);
13
+ margin-bottom: var(--g5); padding-bottom: var(--g5);
14
+ border-bottom: 1px solid rgba(255,255,255,.15);
15
15
  }
16
16
  body > footer > small > nav section { all: unset; display: block; }
17
17
  body > footer > small > nav strong {
18
18
  display: block; font-family: var(--font-sans); font-size: var(--t-xs);
19
- font-weight: 600; color: var(--ink); margin-bottom: var(--g2);
19
+ font-weight: 600; color: var(--white);
20
+ text-transform: uppercase; letter-spacing: 0.06em; margin-bottom: var(--g3);
20
21
  }
21
- body > footer > small > nav p { font-size: var(--t-xs); line-height: 1.7; color: var(--ink-3); margin: 0; max-width: 36ch; }
22
- body > footer > small > nav a { display: block; font-size: var(--t-xs); line-height: 2; color: var(--ink-2); }
23
- body > footer > small > nav a:hover { color: var(--accent-h); }
22
+ body > footer > small > nav p {
23
+ font-size: var(--t-xs); line-height: 1.7; color: rgba(255,255,255,.6);
24
+ margin: 0; max-width: 36ch;
25
+ }
26
+ body > footer > small > nav a {
27
+ display: block; font-size: var(--t-xs); line-height: 2.2;
28
+ color: rgba(255,255,255,.7);
29
+ }
30
+ body > footer > small > nav a:hover { color: var(--white); opacity: 1; }
24
31
  body > footer > small > p {
25
- font-size: var(--t-xs); color: var(--ink-3); text-align: left;
32
+ font-size: var(--t-xs); color: rgba(255,255,255,.5); text-align: left;
26
33
  }
27
34
  @media (max-width: 640px) {
28
- body > footer > small > nav { grid-template-columns: 1fr; gap: var(--g3); }
35
+ body > footer > small > nav { grid-template-columns: 1fr; gap: var(--g4); }
29
36
  }`;
@@ -1,20 +1,20 @@
1
1
  export const css = `form:not([role="search"]) label {
2
2
  display: block; font-size: var(--t-sm); color: var(--ink-2);
3
- font-weight: 500; margin-bottom: var(--g1); font-family: var(--font-sans);
3
+ font-weight: 500; margin-bottom: var(--g1);
4
4
  }
5
5
  form:not([role="search"]) input[type="text"] {
6
6
  display: block; width: 100%; margin-top: var(--g1); height: 48px;
7
- padding: 0 var(--g3); background: var(--beige-50); border: 1px solid var(--line);
8
- color: var(--ink); font-size: var(--t-sm); font-family: var(--font-sans);
7
+ padding: 0 var(--g3); background: var(--white); border: 1px solid var(--line);
8
+ border-radius: var(--r); color: var(--ink); font-size: var(--t-sm); font-family: var(--font-sans);
9
9
  transition: border-color var(--ease);
10
10
  }
11
11
  form:not([role="search"]) input[type="text"]:focus {
12
- outline: none; border-color: var(--sage-600);
12
+ outline: none; border-color: var(--purple); box-shadow: 0 0 0 3px rgba(162,147,255,.15);
13
13
  }
14
14
  form:not([role="search"]) button[type="submit"] {
15
- margin-top: var(--g3); height: 48px; padding: 0 var(--g4);
16
- border: none; background: var(--sage-600); color: var(--beige-50);
17
- font-size: var(--t-sm); font-weight: 500; font-family: var(--font-sans);
15
+ margin-top: var(--g3); height: 48px; padding: 0 var(--g5);
16
+ border: none; border-radius: var(--r-btn); background: var(--gold); color: var(--navy);
17
+ font-size: var(--t-sm); font-weight: 600; font-family: var(--font-sans);
18
18
  cursor: pointer; transition: background var(--ease);
19
19
  }
20
- form:not([role="search"]) button[type="submit"]:hover { background: var(--sage-700); }`;
20
+ form:not([role="search"]) button[type="submit"]:hover { background: #e5b030; }`;
@@ -1,16 +1,18 @@
1
1
  export const css = `body > header {
2
- background: var(--beige-50); border-bottom: 1px solid var(--line-soft);
2
+ position: sticky; top: 0; z-index: 50;
3
+ background: rgba(255,255,255,.92); backdrop-filter: blur(16px);
4
+ border-bottom: 1px solid var(--line);
3
5
  }
4
6
  body > header nav {
5
7
  max-width: var(--container); margin-inline: auto; padding-inline: var(--pad);
6
- height: 80px; display: flex; align-items: center; justify-content: space-between;
8
+ height: 72px; display: flex; align-items: center; justify-content: space-between;
7
9
  }
8
10
  body > header nav a {
9
11
  color: var(--ink-2); text-decoration: none; font-size: var(--t-xs);
10
12
  font-weight: 500; transition: color var(--ease);
11
13
  }
12
- body > header nav a:hover { color: var(--ink); }
14
+ body > header nav a:hover { color: var(--purple); }
13
15
  body > header nav a strong {
14
- font-family: var(--font-serif); font-size: var(--t-md); font-weight: 600;
15
- color: var(--ink); letter-spacing: 0;
16
+ font-family: var(--font-display); font-size: var(--t-md); font-weight: 400;
17
+ color: var(--ink); letter-spacing: -0.01em;
16
18
  }`;
@@ -2,67 +2,66 @@ export const css = `hgroup {
2
2
  position: relative; text-align: center; isolation: isolate;
3
3
  padding: var(--g7) var(--pad) var(--g6);
4
4
  margin-inline: calc(50% - 50vw);
5
- background: var(--sage-100);
6
- border-bottom: 1px solid var(--line-soft);
7
- }
8
- hgroup > * { position: relative; max-width: var(--w-10); margin-inline: auto; }
9
- hgroup > p:first-child {
10
- display: inline-flex; margin: 0 auto var(--g3); padding: 0;
5
+ background: linear-gradient(170deg, var(--navy) 0%, #2a2a5c 40%, #3d2d6b 100%);
6
+ color: var(--white);
11
7
  }
8
+ hgroup > * { position: relative; max-width: 860px; margin-inline: auto; }
9
+ hgroup > p:first-child { display: inline-flex; margin: 0 auto var(--g4); padding: 0; }
12
10
  hgroup > p:first-child small {
13
11
  display: inline-flex; align-items: center; gap: var(--g1);
14
- background: var(--beige-50); padding: var(--g1) var(--g2);
15
- border: 1px solid var(--sage-200); border-radius: var(--pill);
16
- font-size: var(--t-xs); font-weight: 500; color: var(--sage-700);
17
- letter-spacing: 0.04em; text-transform: uppercase;
12
+ background: rgba(255,255,255,.1); backdrop-filter: blur(8px);
13
+ padding: var(--g1) var(--g3); border: 1px solid rgba(255,255,255,.15);
14
+ border-radius: 999px; font-size: var(--t-xs); font-weight: 500; color: var(--gold);
15
+ letter-spacing: 0.04em;
18
16
  }
19
17
  hgroup > p:first-child small::before {
20
18
  content: ''; width: 6px; height: 6px; border-radius: 50%;
21
- background: var(--sage-500); box-shadow: 0 0 0 3px rgba(142,167,142,.25);
19
+ background: var(--gold); box-shadow: 0 0 0 3px rgba(240,190,55,.3);
22
20
  }
23
21
  hgroup h1 {
24
- font-family: var(--font-serif); font-weight: 400;
25
- max-width: 22ch; margin: 0 auto var(--g4); color: var(--stone-900);
26
- letter-spacing: -0.015em;
22
+ font-family: var(--font-display); font-weight: 300;
23
+ max-width: 16ch; margin: 0 auto var(--g4); color: var(--white);
24
+ letter-spacing: -0.02em; line-height: 1.1;
27
25
  }
28
26
  hgroup > p:not(:first-child) {
29
- font-family: var(--font-sans); font-size: var(--t-md); font-weight: 400;
30
- line-height: 1.6; color: var(--ink-2); max-width: var(--measure);
31
- margin: 0 auto var(--g4);
27
+ font-size: var(--t-md); font-weight: 400; line-height: 1.6;
28
+ color: rgba(255,255,255,.7); max-width: var(--measure);
29
+ margin: 0 auto var(--g5);
32
30
  }
33
31
  hgroup > nav {
34
32
  display: flex; gap: var(--g2); flex-wrap: wrap; justify-content: center;
35
- margin-top: var(--g4); margin-bottom: 0;
33
+ margin-top: var(--g4);
36
34
  }
37
35
  hgroup > nav > a {
38
- display: inline-flex; align-items: center; height: 52px; padding: 0 var(--g4);
39
- font-weight: 500; font-size: var(--t-sm); transition: all var(--ease);
40
- background: var(--beige-50); color: var(--ink); border: 1px solid var(--line);
36
+ display: inline-flex; align-items: center; height: 56px; padding: 0 var(--g5);
37
+ border-radius: var(--r-btn); font-weight: 500; font-size: var(--t-sm);
38
+ transition: all var(--ease);
39
+ background: rgba(255,255,255,.08); color: var(--white); border: 1px solid rgba(255,255,255,.15);
41
40
  }
42
41
  hgroup > nav > a:first-child {
43
- background: var(--sage-600); color: var(--beige-50); border-color: transparent;
42
+ background: var(--gold); color: var(--navy); border-color: transparent;
43
+ font-weight: 600;
44
44
  }
45
- hgroup > nav > a:first-child:hover { background: var(--sage-700); }
46
- hgroup > nav > a:not(:first-child):hover { background: var(--beige-100); }
45
+ hgroup > nav > a:first-child:hover { background: #e5b030; }
46
+ hgroup > nav > a:not(:first-child):hover { background: rgba(255,255,255,.15); }
47
47
  form[role="search"] {
48
- display: flex; max-width: var(--w-6); height: 52px;
49
- margin: var(--g4) auto 0; background: var(--beige-50);
50
- border: 1px solid var(--line); overflow: hidden; transition: all var(--ease);
48
+ display: flex; max-width: 520px; height: 56px;
49
+ margin: var(--g5) auto 0; background: var(--white);
50
+ border-radius: var(--r-btn); overflow: hidden;
51
+ box-shadow: 0 8px 32px rgba(0,0,0,.2);
51
52
  }
52
- form[role="search"]:focus-within { border-color: var(--sage-600); }
53
53
  form[role="search"] input {
54
54
  flex: 1; min-width: 0; border: none; background: transparent; color: var(--ink);
55
- padding: 0 var(--g3); font-size: var(--t-sm); font-family: var(--font-sans); outline: none;
56
- -webkit-appearance: none; appearance: none;
55
+ padding: 0 var(--g4); font-size: var(--t-sm); font-family: var(--font-sans); outline: none;
57
56
  }
58
- form[role="search"] input::placeholder { color: var(--ink-3); }
57
+ form[role="search"] input::placeholder { color: var(--ink-2); }
59
58
  form[role="search"] button {
60
- flex-shrink: 0; height: 100%; border: none; background: var(--sage-600); color: var(--beige-50);
61
- padding: 0 var(--g4); font-size: var(--t-sm); font-weight: 500;
59
+ flex-shrink: 0; height: 100%; border: none; background: var(--purple); color: var(--white);
60
+ padding: 0 var(--g5); font-size: var(--t-sm); font-weight: 600;
62
61
  font-family: var(--font-sans); cursor: pointer; transition: background var(--ease);
63
62
  }
64
- form[role="search"] button:hover { background: var(--sage-700); }
63
+ form[role="search"] button:hover { background: var(--purple-dark); }
65
64
  @media (max-width: 640px) {
66
- hgroup { padding: var(--g5) var(--pad) var(--g4); }
67
- hgroup > nav > a, form[role="search"] { height: 44px; }
65
+ hgroup { padding: var(--g6) var(--pad) var(--g5); }
66
+ hgroup > nav > a, form[role="search"] { height: 48px; }
68
67
  }`;
@@ -9,16 +9,14 @@ import { css as profileCard } from './profile-card.ts';
9
9
  import { css as profileArticle } from './profile-article.ts';
10
10
  import { css as pagination } from './pagination.ts';
11
11
  import { css as forms } from './forms.ts';
12
+ import { css as process } from './process.ts';
13
+ import { css as faq } from './faq.ts';
14
+ import { css as cta } from './cta.ts';
12
15
 
13
16
  const components: Record<string, string> = {
14
- hero,
15
- statBar,
16
- categoryNav,
17
- catalogGrid,
18
- profileCard,
19
- profileArticle,
20
- pagination,
21
- forms,
17
+ hero, statBar, categoryNav, catalogGrid,
18
+ profileCard, profileArticle, pagination, forms,
19
+ process, faq, cta,
22
20
  };
23
21
 
24
22
  const layoutCss = base + '\n' + header + '\n' + footer;
@@ -29,4 +27,4 @@ export function composeCss(...names: string[]): string {
29
27
 
30
28
  export const allCss = layoutCss + '\n' + Object.values(components).join('\n');
31
29
 
32
- export { base, header, footer, hero, statBar, categoryNav, catalogGrid, profileCard, profileArticle, pagination, forms };
30
+ export { base, header, footer, hero, statBar, categoryNav, catalogGrid, profileCard, profileArticle, pagination, forms, process, faq, cta };
@@ -1,13 +1,11 @@
1
1
  export const css = `main > nav p {
2
2
  display: flex; align-items: center; justify-content: center; gap: var(--g3);
3
- font-size: var(--t-xs); color: var(--ink-3); font-family: var(--font-sans);
3
+ font-size: var(--t-xs); color: var(--ink-2);
4
4
  }
5
5
  main > nav a {
6
6
  height: 40px; display: inline-flex; align-items: center; padding: 0 var(--g3);
7
- background: var(--beige-50); border: 1px solid var(--line);
8
- font-size: var(--t-xs); font-weight: 500; color: var(--ink-2);
7
+ border-radius: var(--r-btn); background: var(--purple-soft);
8
+ font-size: var(--t-xs); font-weight: 500; color: var(--navy); border: none;
9
9
  transition: all var(--ease);
10
10
  }
11
- main > nav a:hover {
12
- background: var(--sage-100); border-color: var(--sage-400); color: var(--sage-700);
13
- }`;
11
+ main > nav a:hover { background: var(--purple); color: var(--white); }`;
@@ -0,0 +1,33 @@
1
+ export const css = `section[aria-label="Proces"] {
2
+ margin-inline: calc(50% - 50vw); padding: var(--g6) var(--pad);
3
+ background: var(--gray-bg);
4
+ }
5
+ section[aria-label="Proces"] > h2 {
6
+ text-align: center; max-width: var(--container); margin: 0 auto var(--g2);
7
+ }
8
+ section[aria-label="Proces"] > p {
9
+ text-align: center; max-width: var(--container); margin: 0 auto var(--g5);
10
+ font-size: var(--t-md); color: var(--ink-2);
11
+ }
12
+ section[aria-label="Proces"] > ol {
13
+ display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
14
+ gap: var(--g4); max-width: var(--container); margin: 0 auto;
15
+ list-style: none; padding: 0; counter-reset: step;
16
+ }
17
+ section[aria-label="Proces"] > ol > li {
18
+ counter-increment: step; text-align: center;
19
+ background: var(--white); border-radius: var(--r-lg); padding: var(--g5) var(--g3);
20
+ box-shadow: var(--shadow);
21
+ }
22
+ section[aria-label="Proces"] > ol > li::before {
23
+ content: counter(step, decimal-leading-zero);
24
+ display: block; font-family: var(--font-display); font-size: var(--t-2xl);
25
+ font-weight: 300; color: var(--purple); margin-bottom: var(--g3);
26
+ }
27
+ section[aria-label="Proces"] > ol > li > strong {
28
+ display: block; font-family: var(--font-sans); font-size: var(--t-sm);
29
+ font-weight: 600; margin-bottom: var(--g2);
30
+ }
31
+ section[aria-label="Proces"] > ol > li > span {
32
+ font-size: var(--t-xs); color: var(--ink-2); line-height: 1.6;
33
+ }`;
@@ -1,54 +1,47 @@
1
1
  export const css = `main > article {
2
- max-width: var(--w-8); margin-inline: auto;
2
+ max-width: 720px; margin-inline: auto;
3
3
  padding: var(--g6) 0;
4
4
  }
5
5
  main > article > header {
6
6
  padding-bottom: var(--g4); margin-bottom: var(--g4);
7
- border-bottom: 1px solid var(--line-soft);
7
+ border-bottom: 2px solid var(--purple);
8
8
  }
9
9
  main > article > header h1 {
10
- font-family: var(--font-serif); font-weight: 400;
10
+ font-family: var(--font-display); font-weight: 400;
11
11
  font-size: clamp(var(--t-xl), 5vw, var(--t-2xl));
12
- letter-spacing: -0.01em; line-height: 1.1; margin-bottom: var(--g1);
12
+ letter-spacing: -0.02em; line-height: 1.15; margin-bottom: var(--g1);
13
13
  }
14
14
  main > article > header p {
15
- font-size: var(--t-md); color: var(--sage-700); margin: 0; font-weight: 400;
16
- font-style: italic; font-family: var(--font-serif);
15
+ font-size: var(--t-md); color: var(--purple); margin: 0;
16
+ font-family: var(--font-display); font-style: italic;
17
17
  }
18
18
  main > article address {
19
19
  font-style: normal; font-size: var(--t-sm); color: var(--ink-2);
20
- padding: var(--g2) 0; margin-bottom: var(--g3); border-bottom: 1px solid var(--line-soft);
20
+ padding: var(--g2) 0; margin-bottom: var(--g4); border-bottom: 1px solid var(--line);
21
21
  }
22
- main > article address strong { color: var(--ink-3); font-weight: 500; }
23
22
  main > article section {
24
- margin: var(--g4) 0; padding-top: var(--g4); border-top: 1px solid var(--line-soft);
23
+ margin: var(--g5) 0; padding-top: var(--g4); border-top: 1px solid var(--line);
25
24
  }
26
25
  main > article section h2 {
27
26
  font-family: var(--font-sans); font-size: var(--t-xs); font-weight: 600;
28
- text-transform: uppercase; letter-spacing: 0.1em; color: var(--sage-700);
27
+ text-transform: uppercase; letter-spacing: 0.1em; color: var(--purple);
29
28
  margin: 0 0 var(--g3);
30
29
  }
31
- main > article section > p {
32
- font-family: var(--font-serif); font-size: var(--t-md); line-height: 1.7;
33
- color: var(--ink-2); max-width: none;
34
- }
35
- main > article ul {
36
- list-style: none; padding: 0; display: flex; flex-wrap: wrap; gap: var(--g1);
37
- }
30
+ main > article ul { list-style: none; padding: 0; display: flex; flex-wrap: wrap; gap: var(--g1); }
38
31
  main > article ul li {
39
- font-size: var(--t-xs); font-weight: 500; color: var(--sage-800);
40
- padding: var(--g1) var(--g2); background: var(--sage-100);
32
+ font-size: var(--t-xs); font-weight: 500; color: var(--purple-dark);
33
+ padding: var(--g1) var(--g2); background: var(--purple-soft); border-radius: 999px;
41
34
  }
42
35
  main > article dl {
43
36
  display: grid; grid-template-columns: 9rem 1fr; gap: var(--g2) var(--g3);
44
37
  }
45
38
  main > article dt {
46
- font-size: var(--t-xs); color: var(--ink-3); font-weight: 500;
39
+ font-size: var(--t-xs); color: var(--ink-2); font-weight: 600;
47
40
  text-transform: uppercase; letter-spacing: 0.06em;
48
41
  }
49
- main > article dd { margin: 0; font-size: var(--t-sm); color: var(--ink); }
50
- main > article dd a { color: var(--sage-700); }
51
- main > article dd a:hover { color: var(--ink); }
42
+ main > article dd { margin: 0; font-size: var(--t-sm); }
43
+ main > article dd a { color: var(--purple); }
44
+ main > article dd a:hover { color: var(--navy); }
52
45
  @media (max-width: 640px) {
53
46
  main > article { padding: var(--g4) 0; }
54
47
  main > article dl { grid-template-columns: 1fr; gap: 2px 0; }
@@ -1,35 +1,31 @@
1
1
  const S = 'section:has(> article[itemscope]) > article[itemscope]';
2
2
  export const css = `${S} {
3
- position: relative; background: var(--beige-50); border: 1px solid var(--line-soft);
4
- padding: var(--g3); display: flex; flex-direction: column;
3
+ background: var(--card); border: 1px solid var(--line);
4
+ border-radius: var(--r-lg); padding: var(--g4);
5
+ display: flex; flex-direction: column;
5
6
  box-shadow: var(--shadow); transition: all var(--ease);
6
7
  }
7
- ${S}:hover {
8
- border-color: var(--sage-400); box-shadow: var(--shadow-md);
9
- }
8
+ ${S}:hover { box-shadow: var(--shadow-md); border-color: var(--purple); }
10
9
  ${S} > div[aria-hidden] {
11
10
  width: 56px; height: 56px; border-radius: 50%;
12
11
  display: flex; align-items: center; justify-content: center;
13
- font-family: var(--font-serif); font-size: var(--t-md); font-weight: 600;
14
- color: var(--beige-50); background: var(--sage-600);
15
- margin-bottom: var(--g3); flex-shrink: 0;
12
+ font-family: var(--font-display); font-size: var(--t-md); font-weight: 400;
13
+ color: var(--white); background: var(--purple);
14
+ margin-bottom: var(--g3);
16
15
  }
17
16
  ${S} header { margin-bottom: var(--g2); }
18
17
  ${S} h2 {
19
- font-family: var(--font-serif); font-size: var(--t-md); font-weight: 600;
20
- line-height: 1.25; margin: 0 0 var(--g1); letter-spacing: 0;
18
+ font-family: var(--font-sans); font-size: var(--t-sm); font-weight: 600;
19
+ line-height: 1.3; margin: 0 0 4px;
21
20
  }
22
21
  ${S} h2 a { color: var(--ink); }
23
- ${S} h2 a:hover { color: var(--sage-700); }
24
- ${S} header p {
25
- font-size: var(--t-xs); line-height: 1.5; color: var(--ink-3); margin: 0 0 2px;
26
- }
22
+ ${S} h2 a:hover { color: var(--purple); }
23
+ ${S} header p { font-size: var(--t-xs); line-height: 1.5; color: var(--ink-2); margin: 0; }
27
24
  ${S} header p:has([itemprop="address"]) {
28
- display: inline-flex; align-items: center; gap: 6px; margin-top: var(--g1);
29
- color: var(--stone-500);
25
+ display: inline-flex; align-items: center; gap: 6px; margin-top: 4px;
30
26
  }
31
27
  ${S} header p:has([itemprop="address"])::before {
32
- content: '\u00b7'; color: var(--sage-500); font-weight: 700;
28
+ content: ''; width: 4px; height: 4px; border-radius: 50%; background: var(--purple);
33
29
  }
34
30
  ${S} [itemprop="description"] {
35
31
  font-size: var(--t-xs); line-height: 1.6; margin: var(--g2) 0 0; color: var(--ink-2);
@@ -39,19 +35,13 @@ ${S} ul {
39
35
  margin: var(--g2) 0 0;
40
36
  }
41
37
  ${S} ul li {
42
- background: var(--sage-100); color: var(--sage-800);
43
- padding: 3px var(--g1); font-size: 0.75rem; font-weight: 500;
38
+ background: var(--purple-soft); color: var(--purple-dark);
39
+ padding: 3px var(--g2); border-radius: 999px; font-size: 0.75rem; font-weight: 500;
44
40
  }
45
41
  ${S} > a:last-child {
46
42
  display: inline-flex; align-items: center; justify-content: center;
47
- margin-top: auto; padding: var(--g2) 0;
48
- background: var(--sage-600); color: var(--beige-50);
49
- font-size: var(--t-xs); font-weight: 500;
50
- margin-left: calc(-1 * var(--g3)); margin-right: calc(-1 * var(--g3));
51
- margin-bottom: calc(-1 * var(--g3));
52
- transition: background var(--ease);
53
- }
54
- ${S} > article > a:last-child:hover,
55
- ${S} > a:last-child:hover { background: var(--sage-700); color: var(--beige-50); }
56
- ${S} > * + * { margin-top: 0; }
57
- ${S} > a:last-child { margin-top: var(--g3); }`;
43
+ margin-top: auto; padding-top: var(--g3);
44
+ font-size: var(--t-xs); font-weight: 600; color: var(--purple);
45
+ transition: color var(--ease);
46
+ }
47
+ ${S} > a:last-child:hover { color: var(--navy); }`;
@@ -1,31 +1,29 @@
1
1
  export const css = `section[aria-label="Statystyki"] {
2
- background: var(--beige-50); border-top: 1px solid var(--line-soft);
3
- border-bottom: 1px solid var(--line-soft);
4
2
  margin-inline: calc(50% - 50vw); padding: var(--g5) var(--pad);
3
+ background: var(--gray-bg); border-bottom: 1px solid var(--line);
5
4
  }
6
5
  section[aria-label="Statystyki"] > p {
7
- text-align: center; font-size: var(--t-md); font-weight: 400; line-height: 1.6;
8
- color: var(--ink); margin: 0 auto var(--g4); max-width: var(--measure);
9
- font-family: var(--font-serif); font-style: italic;
6
+ text-align: center; font-family: var(--font-display); font-style: italic;
7
+ font-size: var(--t-md); color: var(--ink); margin: 0 auto var(--g4); max-width: var(--measure);
10
8
  }
11
9
  section[aria-label="Statystyki"] > dl {
12
- display: grid; grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
13
- gap: var(--g4); max-width: var(--w-10); margin: 0 auto; padding: 0;
10
+ display: grid; grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
11
+ gap: var(--g4); max-width: 800px; margin: 0 auto; padding: 0;
14
12
  }
15
13
  section[aria-label="Statystyki"] > dl div { text-align: center; }
16
14
  section[aria-label="Statystyki"] > dl div > span:has(> svg) {
17
- display: flex; align-items: center; justify-content: center; width: 44px; height: 44px;
18
- margin: 0 auto var(--g2); color: var(--sage-600);
15
+ display: flex; align-items: center; justify-content: center;
16
+ width: 48px; height: 48px; margin: 0 auto var(--g2);
17
+ background: var(--purple-soft); border-radius: 50%; color: var(--purple);
19
18
  }
20
- section[aria-label="Statystyki"] > dl div > span:has(> svg) > svg { width: 24px; height: 24px; }
19
+ section[aria-label="Statystyki"] > dl div > span:has(> svg) > svg { width: 22px; height: 22px; }
21
20
  section[aria-label="Statystyki"] > dl dt {
22
- font-family: var(--font-serif); font-size: var(--t-2xl); font-weight: 400;
23
- line-height: 1.1; color: var(--stone-900);
21
+ font-family: var(--font-display); font-size: var(--t-2xl); font-weight: 300;
22
+ line-height: 1.1; color: var(--navy);
24
23
  }
25
24
  section[aria-label="Statystyki"] > dl dd {
26
- margin: var(--g1) 0 0; font-size: var(--t-xs); line-height: 1.4;
27
- color: var(--ink-3); font-weight: 400;
25
+ margin: var(--g1) 0 0; font-size: var(--t-xs); color: var(--ink-2); font-weight: 500;
28
26
  }
29
27
  @media (max-width: 640px) {
30
- section[aria-label="Statystyki"] > dl { grid-template-columns: repeat(2, 1fr); gap: var(--g3); }
28
+ section[aria-label="Statystyki"] > dl { grid-template-columns: repeat(2, 1fr); }
31
29
  }`;
@@ -1,22 +1,12 @@
1
+ import type { TrenerProfile } from '@press2ai/engine/template-trener';
2
+
1
3
  export function esc(s: string | undefined | null): string {
2
4
  if (!s) return '';
3
5
  return s.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;');
4
6
  }
5
7
 
6
- export interface TherapyProfile {
7
- slug: string;
8
- firstName: string;
9
- lastName: string;
10
- jobTitle: string;
11
- city?: string;
12
- bio?: string;
13
- photo?: string;
14
- specialties: string[];
15
- languages: string[];
16
- business: { name?: string; taxId?: string; classification: string[] };
17
- social: Record<string, string>;
18
- }
19
-
20
- export function fullName(p: TherapyProfile): string {
8
+ export function fullName(p: TrenerProfile): string {
21
9
  return `${p.firstName} ${p.lastName}`;
22
10
  }
11
+
12
+ export type { TrenerProfile };
@@ -2,4 +2,4 @@ export { layout, type LayoutProps } from './layout.ts';
2
2
  export { profileCard } from './profile-card.ts';
3
3
  export { profileArticle } from './profile-article.ts';
4
4
  export { catalogHero, catalogGrid, statBar, categoryNav, pagination, type CatalogHeroProps, type PaginationProps } from './catalog.ts';
5
- export { esc, fullName, type TherapyProfile } from './helpers.ts';
5
+ export { esc, fullName, type TrenerProfile } from './helpers.ts';
@@ -6,29 +6,25 @@ export interface LayoutProps {
6
6
  jsonLd?: object;
7
7
  siteName?: string;
8
8
  homeHref?: string;
9
- baseUrl?: string;
10
9
  headExtra?: string;
11
10
  navExtra?: string;
12
11
  footerContent?: string;
12
+ bodyScript?: string;
13
13
  }
14
14
 
15
- const THEME_VERSION = '0.1.0';
15
+ const THEME_VERSION = '0.2.0';
16
16
 
17
17
  export function layout(props: LayoutProps, body: string): string {
18
18
  const {
19
- title,
20
- description,
21
- jsonLd,
22
- siteName = 'press2ai',
23
- homeHref = '/',
24
- headExtra = '',
25
- navExtra = '',
26
- footerContent,
19
+ title, description, jsonLd,
20
+ siteName = 'press2ai', homeHref = '/',
21
+ headExtra = '', navExtra = '',
22
+ footerContent, bodyScript = '',
27
23
  } = props;
28
24
 
29
25
  const footer = footerContent ??
30
26
  `Powered by <a href="https://www.npmjs.com/org/press2ai">press2ai</a> &middot;
31
- <a href="https://www.npmjs.com/package/@press2ai/theme-therapy-soft/v/${THEME_VERSION}">@press2ai/theme-therapy-soft v${THEME_VERSION}</a>`;
27
+ <a href="https://www.npmjs.com/package/@press2ai/theme-therapy-soft/v/${THEME_VERSION}">theme-therapy-soft v${THEME_VERSION}</a>`;
32
28
 
33
29
  return `<!doctype html>
34
30
  <html lang="pl">
@@ -39,10 +35,11 @@ export function layout(props: LayoutProps, body: string): string {
39
35
  ${description ? `<meta name="description" content="${esc(description)}">` : ''}
40
36
  <meta property="og:title" content="${esc(title)}">
41
37
  ${description ? `<meta property="og:description" content="${esc(description)}">` : ''}
38
+ <meta property="og:type" content="website">
42
39
  ${jsonLd ? `<script type="application/ld+json">${JSON.stringify(jsonLd).replace(/</g, '\\u003c')}</script>` : ''}
43
40
  <link rel="preconnect" href="https://fonts.googleapis.com">
44
41
  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
45
- <link href="https://fonts.googleapis.com/css2?family=Crimson+Text:ital,wght@0,400;0,600;1,400&family=Inter:wght@300;400;500;600&display=swap" rel="stylesheet">
42
+ <link href="https://fonts.googleapis.com/css2?family=Fraunces:ital,opsz,wght@0,9..144,300;0,9..144,400;0,9..144,600;1,9..144,400&family=DM+Sans:wght@400;500;600&display=swap" rel="stylesheet">
46
43
  ${headExtra}
47
44
  </head>
48
45
  <body>
@@ -56,6 +53,7 @@ ${navExtra}
56
53
  <footer>
57
54
  <small>${footer}</small>
58
55
  </footer>
56
+ ${bodyScript}
59
57
  </body>
60
58
  </html>`;
61
59
  }
@@ -1,6 +1,15 @@
1
- import { esc, fullName, type TherapyProfile } from './helpers.ts';
1
+ import { esc, fullName, type TrenerProfile } from './helpers.ts';
2
2
 
3
- export function profileArticle(p: TherapyProfile): string {
3
+ const SOCIAL_URL_PREFIX: Record<string, string> = {
4
+ linkedin: 'https://linkedin.com/in/',
5
+ youtube: 'https://youtube.com/@',
6
+ tiktok: 'https://tiktok.com/@',
7
+ facebook: 'https://facebook.com/',
8
+ twitter: 'https://x.com/',
9
+ instagram: 'https://instagram.com/',
10
+ };
11
+
12
+ export function profileArticle(p: TrenerProfile): string {
4
13
  const name = fullName(p);
5
14
  const socials = Object.entries(p.social ?? {}).filter(([, v]) => v);
6
15
 
@@ -37,16 +46,8 @@ ${p.languages.map(l => `<li itemprop="knowsLanguage">${esc(l)}</li>`).join('\n')
37
46
  </section>`
38
47
  : '';
39
48
 
40
- const socialUrlPrefix: Record<string, string> = {
41
- linkedin: 'https://linkedin.com/in/',
42
- youtube: 'https://youtube.com/@',
43
- tiktok: 'https://tiktok.com/@',
44
- facebook: 'https://facebook.com/',
45
- twitter: 'https://x.com/',
46
- instagram: 'https://instagram.com/',
47
- };
48
49
  const contactItems = socials.map(([n, handle]) => {
49
- const prefix = socialUrlPrefix[n] ?? `https://${esc(n)}.com/`;
50
+ const prefix = SOCIAL_URL_PREFIX[n] ?? `https://${esc(n)}.com/`;
50
51
  return `<dt>${esc(n)}</dt><dd><a href="${prefix}${esc(handle as string)}" rel="noopener">@${esc(handle as string)}</a></dd>`;
51
52
  });
52
53
 
@@ -1,6 +1,6 @@
1
- import { esc, fullName, type TherapyProfile } from './helpers.ts';
1
+ import { esc, fullName, type TrenerProfile } from './helpers.ts';
2
2
 
3
- export function profileCard(p: TherapyProfile, href: string): string {
3
+ export function profileCard(p: TrenerProfile, href: string): string {
4
4
  const name = fullName(p);
5
5
  const initials = `${(p.firstName?.[0] ?? '').toUpperCase()}${(p.lastName?.[0] ?? '').toUpperCase()}`;
6
6