curieous commited on
Commit
d7e5038
·
verified ·
1 Parent(s): eaa8d34

Update Epic Errands V1 visual design

Browse files
README.md CHANGED
@@ -20,8 +20,10 @@ the public app is not a `gr.HTML` island inside `gr.Blocks`.
20
  The prototype includes:
21
 
22
  - Home, Parent Goals, Kid Goals, and disabled DIY Lab navigation.
23
- - Classroom, Magical, and Comic style switching.
24
- - Theme-based parent/kid titles such as Chief Wizard and Junior Wizard.
 
 
25
  - Kid completion state separated from parent approval/reward state.
26
  - Parent approve-only reward flow.
27
  - Disabled V1.1 audio hook.
 
20
  The prototype includes:
21
 
22
  - Home, Parent Goals, Kid Goals, and disabled DIY Lab navigation.
23
+ - Quest, Classroom, and Comic app theme switching.
24
+ - Quest is the default visible theme; the internal style id `magical` is kept
25
+ only for V1 compatibility.
26
+ - Theme-based parent/kid titles such as Quest Keeper and Young Adventurer.
27
  - Kid completion state separated from parent approval/reward state.
28
  - Parent approve-only reward flow.
29
  - Disabled V1.1 audio hook.
epic_errands_space/quest_generation.py CHANGED
@@ -124,7 +124,7 @@ def _quest_title(goal_text: str, tone: str) -> str:
124
  tone_word = {
125
  "cozy": "Cozy",
126
  "brave": "Brave",
127
- "magical": "Magic",
128
  "silly": "Silly",
129
  "epic": "Epic",
130
  }.get(tone, "Cozy")
@@ -146,9 +146,9 @@ def _why_it_helps(goal_text: str) -> str:
146
 
147
  def _prompt_for_goal(goal: dict[str, str], tone: str) -> str:
148
  return (
149
- "A delightful storybook classroom adventure hero image for a children's "
150
- "goal-planning app. Warm handcrafted illustration, cozy school supplies, "
151
- "sunny classroom, gentle fantasy quest mood, no readable text, no UI, "
152
  "kid-safe, expressive, polished. "
153
  f"Tone: {tone}. Ordinary goal transformed visually: {goal['text']}."
154
  )
 
124
  tone_word = {
125
  "cozy": "Cozy",
126
  "brave": "Brave",
127
+ "magical": "Quest",
128
  "silly": "Silly",
129
  "epic": "Epic",
130
  }.get(tone, "Cozy")
 
146
 
147
  def _prompt_for_goal(goal: dict[str, str], tone: str) -> str:
148
  return (
149
+ "A delightful family questbook hero image for a children's "
150
+ "goal-planning app. Warm handcrafted illustration, parchment storybook "
151
+ "mood, clear everyday adventure, no readable text, no UI, "
152
  "kid-safe, expressive, polished. "
153
  f"Tone: {tone}. Ordinary goal transformed visually: {goal['text']}."
154
  )
frontend/index.html CHANGED
@@ -2,21 +2,16 @@
2
  <html lang="en">
3
  <head>
4
  <meta charset="utf-8">
5
- <meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
6
- <meta name="theme-color" content="#fffdf8">
7
- <title>Epic Errands</title>
8
  <link rel="preconnect" href="https://fonts.googleapis.com">
9
  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
10
- <link href="https://fonts.googleapis.com/css2?family=Baloo+2:wght@700;800&family=Nunito:wght@700;800;900&family=Material+Symbols+Rounded:opsz,wght,FILL,GRAD@24,600,0,0&display=swap" rel="stylesheet">
11
- <link rel="stylesheet" href="/frontend/styles/app.css">
 
12
  </head>
13
  <body>
14
- <main class="epic-app" aria-label="Epic Errands mobile prototype">
15
- <div id="epic-errands-app"></div>
16
- </main>
17
- <script>
18
- window.EPIC_ASSET_BASE = "/assets/";
19
- </script>
20
- <script src="/frontend/scripts/app.js" defer></script>
21
  </body>
22
  </html>
 
2
  <html lang="en">
3
  <head>
4
  <meta charset="utf-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1">
6
+ <title>Epic Errands V1 - Mobile Review Prototype</title>
 
7
  <link rel="preconnect" href="https://fonts.googleapis.com">
8
  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
9
+ <link href="https://fonts.googleapis.com/css2?family=Baloo+2:wght@600;700;800&family=Lora:wght@600;700&family=Nunito:wght@500;600;700;800&display=swap" rel="stylesheet">
10
+ <link href="https://fonts.googleapis.com/css2?family=Material+Symbols+Rounded:opsz,wght,FILL,GRAD@24,500,0,0" rel="stylesheet">
11
+ <link rel="stylesheet" href="styles/app.css">
12
  </head>
13
  <body>
14
+ <main id="epic-errands-app" class="epic-app" aria-label="Epic Errands V1 mobile review prototype"></main>
15
+ <script src="scripts/app.js"></script>
 
 
 
 
 
16
  </body>
17
  </html>
frontend/scripts/app.js CHANGED
@@ -12,17 +12,17 @@
12
  kidTitle: "Star Student",
13
  rewardNoun: "badge",
14
  waitingCopy: "Waiting for Classroom Captain approval.",
15
- copy: "Warm school adventure with stickers, notebooks, and sunny goals.",
16
  },
17
  magical: {
18
- label: "Magical",
19
- icon: "auto_fix_high",
20
- goalNoun: "Spell Quest",
21
- parentTitle: "Chief Wizard",
22
- kidTitle: "Junior Wizard",
23
- rewardNoun: "charm",
24
- waitingCopy: "Waiting for Chief Wizard approval.",
25
- copy: "Cozy spellbook fantasy with gentle magic and glowing rewards.",
26
  },
27
  comic: {
28
  label: "Comic",
@@ -119,7 +119,7 @@
119
  function goalTitle(goal) {
120
  const style = goalStyle(goal);
121
  const lower = goal.ordinaryGoal.toLowerCase();
122
- if (goal.styleId === "magical" && lower.includes("class project")) return `${style.goalNoun}: Bright Idea Bridge`;
123
  if (goal.styleId === "comic" && lower.includes("laundry")) return `${style.goalNoun}: Laundry Launch`;
124
  if (lower.includes("read")) return `${style.goalNoun}: Reading Lantern`;
125
  return `${style.goalNoun}: ${titleCase(goal.ordinaryGoal)}`;
@@ -127,7 +127,7 @@
127
 
128
  function rewardLabel(goal) {
129
  const style = goalStyle(goal);
130
- if (goal.styleId === "magical") return `Glow ${style.rewardNoun}`;
131
  if (goal.styleId === "comic") return `Pow ${style.rewardNoun}`;
132
  return `Helper ${style.rewardNoun}`;
133
  }
@@ -151,9 +151,9 @@
151
  const style = goalStyle(goal);
152
  if (goal.styleId === "magical") {
153
  return [
154
- "Gather your project ideas",
155
- "Build the first bright piece",
156
- "Check your spellbook notes",
157
  ];
158
  }
159
  if (goal.styleId === "comic") {
@@ -167,19 +167,19 @@
167
  return `
168
  <section class="screen" data-design-id="home-screen" aria-labelledby="home-title">
169
  <div class="screen-head">
170
- <h1 class="screen-title" id="home-title">Choose today's style</h1>
171
- <p class="screen-copy">${escapeHtml(style.parentTitle)} and ${escapeHtml(style.kidTitle)} will use this style for new goals.</p>
172
  </div>
173
 
174
  <section class="panel" data-design-id="style-mode-picker" aria-labelledby="style-label">
175
- <h2 class="section-label" id="style-label">Goal style</h2>
176
  <div class="style-grid">
177
  ${Object.entries(styles).map(([id, item]) => `
178
  <button class="style-option" data-action="select-style" data-style="${id}" aria-pressed="${state.defaultStyleId === id}">
179
  <span class="style-mark">${icon(item.icon)}</span>
180
  <span>
181
  <span class="style-name">${item.label}</span>
182
- <span class="style-meta">${item.goalNoun} / ${item.rewardNoun}. ${item.copy}</span>
183
  </span>
184
  <span class="selected-dot" aria-hidden="true"></span>
185
  </button>
@@ -233,7 +233,7 @@
233
  <form class="goal-create panel" data-design-id="parent-goal-create" aria-labelledby="create-goal-title">
234
  <div>
235
  <h2 class="section-label" id="create-goal-title">Create goal</h2>
236
- <p class="goal-create-copy">New goals snapshot the current ${escapeHtml(style.label)} style.</p>
237
  </div>
238
  <label class="goal-input-label" for="new-goal-input">Ordinary goal</label>
239
  <div class="goal-create-row">
@@ -273,7 +273,7 @@
273
  <section class="screen" data-design-id="kid-goals-screen" aria-labelledby="kid-title">
274
  <div class="screen-head">
275
  <h1 class="screen-title" id="kid-title">Kid Goals</h1>
276
- <p class="screen-copy">Tap a thumbnail to open the goal card, finish it, then wait for your grown-up's themed approval.</p>
277
  </div>
278
  <div class="kid-grid" data-design-id="kid-goal-thumbnail-grid">
279
  ${state.goals.map((goal) => {
@@ -392,7 +392,7 @@
392
  <header class="app-top">
393
  <div class="brand-row">
394
  <div class="brand-lockup">
395
- <p class="eyebrow">V1 mobile review</p>
396
  <h1 class="brand-title">Epic Errands</h1>
397
  </div>
398
  <span class="status-pill">${icon(style.icon)} ${escapeHtml(style.label)}</span>
 
12
  kidTitle: "Star Student",
13
  rewardNoun: "badge",
14
  waitingCopy: "Waiting for Classroom Captain approval.",
15
+ copy: "Bright school adventure with stickers, notebooks, and sunny goals.",
16
  },
17
  magical: {
18
+ label: "Quest",
19
+ icon: "auto_stories",
20
+ goalNoun: "Quest",
21
+ parentTitle: "Quest Keeper",
22
+ kidTitle: "Young Adventurer",
23
+ rewardNoun: "crest",
24
+ waitingCopy: "Waiting for Quest Keeper approval.",
25
+ copy: "Premium questbook fantasy with warm paper, ink lines, and earned crests.",
26
  },
27
  comic: {
28
  label: "Comic",
 
119
  function goalTitle(goal) {
120
  const style = goalStyle(goal);
121
  const lower = goal.ordinaryGoal.toLowerCase();
122
+ if (goal.styleId === "magical" && lower.includes("class project")) return `${style.goalNoun}: Bridge of Bright Ideas`;
123
  if (goal.styleId === "comic" && lower.includes("laundry")) return `${style.goalNoun}: Laundry Launch`;
124
  if (lower.includes("read")) return `${style.goalNoun}: Reading Lantern`;
125
  return `${style.goalNoun}: ${titleCase(goal.ordinaryGoal)}`;
 
127
 
128
  function rewardLabel(goal) {
129
  const style = goalStyle(goal);
130
+ if (goal.styleId === "magical") return `Orderkeeper ${style.rewardNoun}`;
131
  if (goal.styleId === "comic") return `Pow ${style.rewardNoun}`;
132
  return `Helper ${style.rewardNoun}`;
133
  }
 
151
  const style = goalStyle(goal);
152
  if (goal.styleId === "magical") {
153
  return [
154
+ "Gather the scattered clues",
155
+ "Build the first brave piece",
156
+ "Check the questbook notes",
157
  ];
158
  }
159
  if (goal.styleId === "comic") {
 
167
  return `
168
  <section class="screen" data-design-id="home-screen" aria-labelledby="home-title">
169
  <div class="screen-head">
170
+ <h1 class="screen-title" id="home-title">Set the app theme</h1>
171
+ <p class="screen-copy">Quest is the default visual style. Switch to Classroom or Comic before creating a new goal.</p>
172
  </div>
173
 
174
  <section class="panel" data-design-id="style-mode-picker" aria-labelledby="style-label">
175
+ <h2 class="section-label" id="style-label">App theme</h2>
176
  <div class="style-grid">
177
  ${Object.entries(styles).map(([id, item]) => `
178
  <button class="style-option" data-action="select-style" data-style="${id}" aria-pressed="${state.defaultStyleId === id}">
179
  <span class="style-mark">${icon(item.icon)}</span>
180
  <span>
181
  <span class="style-name">${item.label}</span>
182
+ <span class="style-meta">${item.parentTitle} / ${item.rewardNoun}. ${item.copy}</span>
183
  </span>
184
  <span class="selected-dot" aria-hidden="true"></span>
185
  </button>
 
233
  <form class="goal-create panel" data-design-id="parent-goal-create" aria-labelledby="create-goal-title">
234
  <div>
235
  <h2 class="section-label" id="create-goal-title">Create goal</h2>
236
+ <p class="goal-create-copy">New goals snapshot the current ${escapeHtml(style.label)} app theme.</p>
237
  </div>
238
  <label class="goal-input-label" for="new-goal-input">Ordinary goal</label>
239
  <div class="goal-create-row">
 
273
  <section class="screen" data-design-id="kid-goals-screen" aria-labelledby="kid-title">
274
  <div class="screen-head">
275
  <h1 class="screen-title" id="kid-title">Kid Goals</h1>
276
+ <p class="screen-copy">Tap a thumbnail to open the goal card, finish it, then wait for your grown-up's approval.</p>
277
  </div>
278
  <div class="kid-grid" data-design-id="kid-goal-thumbnail-grid">
279
  ${state.goals.map((goal) => {
 
392
  <header class="app-top">
393
  <div class="brand-row">
394
  <div class="brand-lockup">
395
+ <p class="eyebrow">V1 visual review</p>
396
  <h1 class="brand-title">Epic Errands</h1>
397
  </div>
398
  <span class="status-pill">${icon(style.icon)} ${escapeHtml(style.label)}</span>
frontend/styles/app.css CHANGED
@@ -1,12 +1,14 @@
1
  :root {
2
  --font-display: "Baloo 2", system-ui, sans-serif;
 
3
  --font-body: "Nunito", system-ui, sans-serif;
4
- --ink: #1f2a37;
5
- --muted: #607086;
6
- --line: rgba(31, 42, 55, 0.14);
7
- --paper: #fffdf8;
 
8
  --surface: #ffffff;
9
- --soft: #f4f7fb;
10
  --primary: #e3403a;
11
  --primary-ink: #ffffff;
12
  --success: #128a55;
@@ -32,7 +34,7 @@ body {
32
 
33
  body {
34
  margin: 0;
35
- background: #dfe9f7;
36
  color: var(--ink);
37
  font-family: var(--font-body);
38
  overflow: hidden;
@@ -77,8 +79,9 @@ input:focus-visible {
77
  padding: 18px;
78
  overflow: hidden;
79
  background:
80
- radial-gradient(circle at 20% 10%, rgba(255, 255, 255, 0.92), transparent 30%),
81
- linear-gradient(135deg, #d8ebff 0%, #fff2d8 52%, #f5e9ff 100%);
 
82
  }
83
 
84
  .phone {
@@ -91,12 +94,13 @@ input:focus-visible {
91
  display: grid;
92
  grid-template-rows: auto minmax(0, 1fr) auto;
93
  border: 1px solid rgba(31, 42, 55, 0.16);
94
- border-radius: 30px;
95
  background: var(--paper);
96
  box-shadow: var(--shadow);
97
  }
98
 
99
  .phone[data-style="classroom"] {
 
100
  --theme: #e3403a;
101
  --theme-2: #1467b3;
102
  --theme-3: #f7c948;
@@ -107,16 +111,20 @@ input:focus-visible {
107
  }
108
 
109
  .phone[data-style="magical"] {
110
- --theme: #7652c7;
111
- --theme-2: #0f877e;
112
- --theme-3: #efb84a;
113
- --theme-soft: #f2eaff;
114
- --theme-panel: #fff7e4;
115
- --theme-border: #c5b2f3;
116
- --reward: #b36b00;
 
 
 
117
  }
118
 
119
  .phone[data-style="comic"] {
 
120
  --theme: #136bd9;
121
  --theme-2: #d62957;
122
  --theme-3: #ffd33d;
@@ -129,7 +137,7 @@ input:focus-visible {
129
  .app-top {
130
  padding: 22px 20px 12px;
131
  background:
132
- linear-gradient(90deg, rgba(255, 255, 255, 0.9), rgba(255, 255, 255, 0.42)),
133
  var(--theme-panel);
134
  border-bottom: 1px solid var(--line);
135
  }
@@ -156,9 +164,9 @@ input:focus-visible {
156
  .brand-title {
157
  margin: 0;
158
  color: var(--ink);
159
- font-family: var(--font-display);
160
  font-size: 29px;
161
- line-height: 0.95;
162
  }
163
 
164
  .status-pill {
@@ -183,7 +191,7 @@ input:focus-visible {
183
  -webkit-overflow-scrolling: touch;
184
  padding: 18px 18px calc(var(--nav-h) + 18px);
185
  background:
186
- linear-gradient(180deg, rgba(255, 255, 255, 0.72), rgba(255, 255, 255, 0)),
187
  var(--theme-panel);
188
  }
189
 
@@ -199,9 +207,9 @@ input:focus-visible {
199
 
200
  .screen-title {
201
  margin: 0;
202
- font-family: var(--font-display);
203
  font-size: 28px;
204
- line-height: 1;
205
  }
206
 
207
  .screen-copy {
@@ -220,8 +228,8 @@ input:focus-visible {
220
  .avatar-slot,
221
  .goal-create {
222
  border: 1px solid var(--line);
223
- border-radius: var(--radius-md);
224
- background: rgba(255, 255, 255, 0.9);
225
  box-shadow: var(--shadow-tight);
226
  }
227
 
@@ -264,13 +272,14 @@ input:focus-visible {
264
  width: 46px;
265
  height: 46px;
266
  place-items: center;
267
- border-radius: 14px;
268
  background: var(--theme-soft);
269
  color: var(--theme);
270
  }
271
 
272
  .style-name {
273
  display: block;
 
274
  font-size: 18px;
275
  font-weight: 1000;
276
  }
@@ -365,7 +374,7 @@ input:focus-visible {
365
 
366
  .counter strong {
367
  color: var(--theme);
368
- font-family: var(--font-display);
369
  font-size: 38px;
370
  line-height: 0.9;
371
  }
@@ -444,6 +453,7 @@ input:focus-visible {
444
  }
445
 
446
  .goal-name {
 
447
  font-size: 17px;
448
  font-weight: 1000;
449
  }
@@ -485,7 +495,7 @@ input:focus-visible {
485
  .create-button {
486
  min-height: 44px;
487
  border: 0;
488
- border-radius: 999px;
489
  padding: 0 14px;
490
  background: var(--theme);
491
  color: var(--primary-ink);
@@ -523,6 +533,7 @@ input:focus-visible {
523
  overflow: hidden;
524
  text-align: left;
525
  color: var(--ink);
 
526
  }
527
 
528
  .kid-tile img {
@@ -608,7 +619,7 @@ input:focus-visible {
608
  max-width: calc(100% - 24px);
609
  padding: 8px 10px;
610
  border: 1px solid rgba(255, 255, 255, 0.72);
611
- border-radius: 999px;
612
  background: rgba(255, 255, 255, 0.9);
613
  color: var(--theme);
614
  font-size: 12px;
@@ -619,14 +630,16 @@ input:focus-visible {
619
  display: grid;
620
  gap: 12px;
621
  padding: 14px;
622
- background: var(--surface);
 
 
623
  }
624
 
625
  .goal-card h2 {
626
  margin: 0;
627
- font-family: var(--font-display);
628
  font-size: 28px;
629
- line-height: 0.98;
630
  }
631
 
632
  .step-list {
 
1
  :root {
2
  --font-display: "Baloo 2", system-ui, sans-serif;
3
+ --font-quest: "Lora", Georgia, serif;
4
  --font-body: "Nunito", system-ui, sans-serif;
5
+ --font-heading: var(--font-display);
6
+ --ink: #241d19;
7
+ --muted: #655f59;
8
+ --line: rgba(62, 47, 33, 0.16);
9
+ --paper: #fff8e8;
10
  --surface: #ffffff;
11
+ --soft: #f5efe3;
12
  --primary: #e3403a;
13
  --primary-ink: #ffffff;
14
  --success: #128a55;
 
34
 
35
  body {
36
  margin: 0;
37
+ background: #e9dcc5;
38
  color: var(--ink);
39
  font-family: var(--font-body);
40
  overflow: hidden;
 
79
  padding: 18px;
80
  overflow: hidden;
81
  background:
82
+ radial-gradient(circle at 16% 12%, rgba(255, 252, 240, 0.95), transparent 28%),
83
+ radial-gradient(circle at 86% 16%, rgba(109, 84, 53, 0.18), transparent 22%),
84
+ linear-gradient(135deg, #d7c29e 0%, #fff1d5 48%, #dfe7d5 100%);
85
  }
86
 
87
  .phone {
 
94
  display: grid;
95
  grid-template-rows: auto minmax(0, 1fr) auto;
96
  border: 1px solid rgba(31, 42, 55, 0.16);
97
+ border-radius: 26px;
98
  background: var(--paper);
99
  box-shadow: var(--shadow);
100
  }
101
 
102
  .phone[data-style="classroom"] {
103
+ --font-heading: var(--font-display);
104
  --theme: #e3403a;
105
  --theme-2: #1467b3;
106
  --theme-3: #f7c948;
 
111
  }
112
 
113
  .phone[data-style="magical"] {
114
+ --font-heading: var(--font-quest);
115
+ --theme: #31583e;
116
+ --theme-2: #5a3f78;
117
+ --theme-3: #c79335;
118
+ --theme-soft: #f2e6cc;
119
+ --theme-panel: #fff6e3;
120
+ --theme-border: #aa8752;
121
+ --reward: #2f6b45;
122
+ --line: rgba(95, 66, 33, 0.24);
123
+ --surface: #fffaf0;
124
  }
125
 
126
  .phone[data-style="comic"] {
127
+ --font-heading: var(--font-display);
128
  --theme: #136bd9;
129
  --theme-2: #d62957;
130
  --theme-3: #ffd33d;
 
137
  .app-top {
138
  padding: 22px 20px 12px;
139
  background:
140
+ linear-gradient(90deg, rgba(255, 252, 244, 0.96), rgba(255, 252, 244, 0.55)),
141
  var(--theme-panel);
142
  border-bottom: 1px solid var(--line);
143
  }
 
164
  .brand-title {
165
  margin: 0;
166
  color: var(--ink);
167
+ font-family: var(--font-heading);
168
  font-size: 29px;
169
+ line-height: 1;
170
  }
171
 
172
  .status-pill {
 
191
  -webkit-overflow-scrolling: touch;
192
  padding: 18px 18px calc(var(--nav-h) + 18px);
193
  background:
194
+ linear-gradient(180deg, rgba(255, 253, 247, 0.72), rgba(255, 255, 255, 0)),
195
  var(--theme-panel);
196
  }
197
 
 
207
 
208
  .screen-title {
209
  margin: 0;
210
+ font-family: var(--font-heading);
211
  font-size: 28px;
212
+ line-height: 1.05;
213
  }
214
 
215
  .screen-copy {
 
228
  .avatar-slot,
229
  .goal-create {
230
  border: 1px solid var(--line);
231
+ border-radius: var(--radius-sm);
232
+ background: rgba(255, 253, 247, 0.92);
233
  box-shadow: var(--shadow-tight);
234
  }
235
 
 
272
  width: 46px;
273
  height: 46px;
274
  place-items: center;
275
+ border-radius: 12px;
276
  background: var(--theme-soft);
277
  color: var(--theme);
278
  }
279
 
280
  .style-name {
281
  display: block;
282
+ font-family: var(--font-heading);
283
  font-size: 18px;
284
  font-weight: 1000;
285
  }
 
374
 
375
  .counter strong {
376
  color: var(--theme);
377
+ font-family: var(--font-heading);
378
  font-size: 38px;
379
  line-height: 0.9;
380
  }
 
453
  }
454
 
455
  .goal-name {
456
+ font-family: var(--font-heading);
457
  font-size: 17px;
458
  font-weight: 1000;
459
  }
 
495
  .create-button {
496
  min-height: 44px;
497
  border: 0;
498
+ border-radius: 12px;
499
  padding: 0 14px;
500
  background: var(--theme);
501
  color: var(--primary-ink);
 
533
  overflow: hidden;
534
  text-align: left;
535
  color: var(--ink);
536
+ background: var(--theme-soft);
537
  }
538
 
539
  .kid-tile img {
 
619
  max-width: calc(100% - 24px);
620
  padding: 8px 10px;
621
  border: 1px solid rgba(255, 255, 255, 0.72);
622
+ border-radius: 12px;
623
  background: rgba(255, 255, 255, 0.9);
624
  color: var(--theme);
625
  font-size: 12px;
 
630
  display: grid;
631
  gap: 12px;
632
  padding: 14px;
633
+ background:
634
+ linear-gradient(180deg, rgba(255, 255, 255, 0.44), rgba(255, 255, 255, 0)),
635
+ var(--surface);
636
  }
637
 
638
  .goal-card h2 {
639
  margin: 0;
640
+ font-family: var(--font-heading);
641
  font-size: 28px;
642
+ line-height: 1.05;
643
  }
644
 
645
  .step-list {