Esvanth commited on
Commit
5600d72
Β·
1 Parent(s): dfca613

Fix UI bugs and improve visual design

Browse files

- Fix hero subtitle color (was near-invisible on dark bg)
- Fix tab label double spaces on Task 2 and Task 3
- Fix sidebar step 3 instruction text accuracy
- Fix Task 4 insight numbers to match data table
- Add shimmer animation to hero title and pulse to glow orbs
- Add gradient background to app, metric cards with top accent border
- Add colour-coded left borders to each task card
- Stronger shadows on insight/warn boxes
- Improved sidebar brand with icon box and version tag

Files changed (1) hide show
  1. app.py +64 -24
app.py CHANGED
@@ -135,10 +135,15 @@ st.markdown("""
135
  <style>
136
  @import url('https://fonts.googleapis.com/css2?family=Inter:opsz,wght@14..32,300;14..32,400;14..32,500;14..32,600;14..32,700;14..32,800;14..32,900&display=swap');
137
 
 
 
 
 
 
138
  *, *::before, *::after { font-family: 'Inter', -apple-system, sans-serif !important; box-sizing: border-box; }
139
 
140
  /* Base */
141
- [data-testid="stAppViewContainer"] { background: #f0f2f8 !important; }
142
  .block-container { padding: .8rem 1.6rem 4rem !important; max-width: 1300px !important; }
143
  #MainMenu, footer, header { visibility: hidden; }
144
  ::-webkit-scrollbar { width: 4px; } ::-webkit-scrollbar-thumb { background: #cbd5e1; border-radius: 8px; }
@@ -171,21 +176,25 @@ st.markdown("""
171
  width: 420px; height: 420px;
172
  background: radial-gradient(circle, rgba(79,70,229,.22) 0%, transparent 60%);
173
  border-radius: 50%; pointer-events: none;
 
174
  }
175
  .hero::after {
176
  content: ''; position: absolute; bottom: -100px; left: 20%;
177
  width: 360px; height: 360px;
178
  background: radial-gradient(circle, rgba(5,150,105,.18) 0%, transparent 60%);
179
  border-radius: 50%; pointer-events: none;
 
180
  }
181
  .hero-title {
182
- font-size: 2.2rem; font-weight: 900; letter-spacing: -.05em; line-height: 1.05;
183
  margin: 0 0 10px;
184
- background: linear-gradient(135deg, #ffffff 30%, #bfdbfe 70%, #6ee7b7 100%);
 
185
  -webkit-background-clip: text; -webkit-text-fill-color: transparent; background-clip: text;
 
186
  }
187
  .hero-sub {
188
- color: #475569; font-size: .86rem; font-weight: 400;
189
  margin-bottom: 28px; line-height: 1.65; max-width: 560px;
190
  }
191
  .hero-stats {
@@ -215,8 +224,10 @@ st.markdown("""
215
  box-shadow: 0 4px 24px rgba(0,0,0,.05), 0 1px 3px rgba(0,0,0,.03);
216
  display: flex; gap: 18px; align-items: flex-start;
217
  transition: box-shadow .2s ease, transform .2s ease;
 
 
218
  }
219
- .task-card:hover { box-shadow: 0 12px 40px rgba(0,0,0,.1); transform: translateY(-2px); }
220
  .task-icon {
221
  width: 52px; height: 52px; border-radius: 15px; flex-shrink: 0;
222
  display: flex; align-items: center; justify-content: center; font-size: 1.5rem;
@@ -233,7 +244,7 @@ st.markdown("""
233
  border: 1px solid #86efac; border-radius: 16px;
234
  padding: 16px 20px 16px 60px; position: relative;
235
  color: #14532d; font-size: .82rem; line-height: 1.8; margin: 14px 0;
236
- box-shadow: 0 4px 20px rgba(5,150,105,.1);
237
  }
238
  .insight::before {
239
  content: 'βœ“'; position: absolute; left: 16px; top: 16px;
@@ -250,7 +261,7 @@ st.markdown("""
250
  border: 1px solid #fcd34d; border-radius: 16px;
251
  padding: 16px 20px 16px 60px; position: relative;
252
  color: #78350f; font-size: .82rem; line-height: 1.8; margin: 14px 0;
253
- box-shadow: 0 4px 20px rgba(217,119,6,.1);
254
  }
255
  .warn-box::before {
256
  content: '!'; position: absolute; left: 16px; top: 16px;
@@ -293,11 +304,13 @@ st.markdown("""
293
 
294
  /* Metrics */
295
  div[data-testid="metric-container"] {
296
- background: #fff; border-radius: 16px; padding: 18px 20px;
297
- border: 1px solid #e2e8f0; box-shadow: 0 4px 20px rgba(0,0,0,.05);
 
 
298
  transition: transform .18s ease, box-shadow .18s ease;
299
  }
300
- div[data-testid="metric-container"]:hover { transform: translateY(-3px); box-shadow: 0 10px 32px rgba(0,0,0,.09); }
301
  div[data-testid="metric-container"] label { font-size: .68rem !important; font-weight: 800 !important; color: #94a3b8 !important; text-transform: uppercase; letter-spacing: .08em; }
302
  div[data-testid="metric-container"] [data-testid="stMetricValue"] { font-size: 1.5rem !important; font-weight: 900 !important; color: #0f172a !important; letter-spacing: -.03em; }
303
 
@@ -386,6 +399,32 @@ details > summary::marker { display: none !important; }
386
 
387
  /* Slider */
388
  .stSlider [data-testid="stTickBarMin"], .stSlider [data-testid="stTickBarMax"] { font-size: .72rem !important; }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
389
  </style>
390
  """, unsafe_allow_html=True)
391
 
@@ -395,16 +434,17 @@ details > summary::marker { display: none !important; }
395
  with st.sidebar:
396
  st.markdown("""
397
  <div class='sb-brand'>
398
- <div class='sb-icon'>πŸ›’</div>
399
  <div class='sb-name'>EcoCart AI</div>
400
  <div class='sb-sub'>Esvanth Mohankumar Β· 24311073</div>
 
401
  </div>""", unsafe_allow_html=True)
402
 
403
  st.markdown("<div class='sb-section'>How to use</div>", unsafe_allow_html=True)
404
  for n, t in [("1","Pick a task tab above"),
405
- ("2","Tasks 2, 3, 5 - press Run"),
406
- ("3","Tasks 1 & 3 - press Play"),
407
- ("4","Task 6 - adjust the sliders")]:
408
  st.markdown(f"""<div class='sb-step'>
409
  <div class='sb-num'>{n}</div>
410
  <span class='sb-step-txt'>{t}</span></div>""", unsafe_allow_html=True)
@@ -430,7 +470,7 @@ with st.sidebar:
430
  st.markdown("""
431
  <div class='hero'>
432
  <div class='hero-title'>EcoCart AI System</div>
433
- <div class='hero-sub'>Six AI tasks built to solve one real logistics problem - every chart and number runs from actual Python scripts</div>
434
  <div style='display:flex;gap:10px;flex-wrap:wrap;margin-top:4px;'>
435
  <div style='background:rgba(96,165,250,.18);border:1.5px solid rgba(96,165,250,.4);border-radius:14px;padding:14px 22px;text-align:center;min-width:86px;backdrop-filter:blur(8px);'>
436
  <div style='color:#93c5fd;font-size:1.7rem;font-weight:900;letter-spacing:-.04em;line-height:1;'>6</div>
@@ -457,8 +497,8 @@ st.markdown("""
457
 
458
  T1, T2, T3, T4, T5, T6 = st.tabs([
459
  "πŸ€– Task 1 - AI Agents",
460
- "βš–οΈ Task 2 - Bias",
461
- "πŸ—ΊοΈ Task 3 - Routes",
462
  "πŸ“Š Task 4 - A* vs IDA*",
463
  "πŸ“ˆ Task 5 - Forecast",
464
  "πŸ’Ό Task 6 - Business",
@@ -469,7 +509,7 @@ T1, T2, T3, T4, T5, T6 = st.tabs([
469
  # ══════════════════════════════════════════════════════════════════════════════
470
  with T1:
471
  st.markdown("""
472
- <div class='task-card'>
473
  <div class='task-icon' style='background:linear-gradient(135deg,#4f46e5,#818cf8);box-shadow:0 6px 20px rgba(99,102,241,.4);font-size:1.5rem;'>πŸ€–</div>
474
  <div>
475
  <div class='task-title'>Three agents, one delivery map. Completely different decisions.</div>
@@ -710,7 +750,7 @@ with T1:
710
  # ══════════════════════════════════════════════════════════════════════════════
711
  with T2:
712
  st.markdown("""
713
- <div class='task-card'>
714
  <div class='task-icon' style='background:linear-gradient(135deg,#b45309,#f59e0b);box-shadow:0 6px 20px rgba(180,83,9,.4);font-size:1.5rem;'>βš–οΈ</div>
715
  <div>
716
  <div class='task-title'>The model was being unfair. Nobody noticed until now.</div>
@@ -771,7 +811,7 @@ with T2:
771
  # ══════════════════════════════════════════════════════════════════════════════
772
  with T3:
773
  st.markdown("""
774
- <div class='task-card'>
775
  <div class='task-icon' style='background:linear-gradient(135deg,#0369a1,#38bdf8);box-shadow:0 6px 20px rgba(3,105,161,.4);font-size:1.5rem;'>πŸ—ΊοΈ</div>
776
  <div>
777
  <div class='task-title'>Four algorithms, one delivery network. Which one wins?</div>
@@ -1071,7 +1111,7 @@ with T3:
1071
  # ══════════════════════════════════════════════════════════════════════════════
1072
  with T4:
1073
  st.markdown("""
1074
- <div class='task-card'>
1075
  <div class='task-icon' style='background:linear-gradient(135deg,#6d28d9,#a78bfa);box-shadow:0 6px 20px rgba(109,40,217,.4);font-size:1.5rem;'>πŸ“Š</div>
1076
  <div>
1077
  <div class='task-title'>Same shortest path, completely different strategies</div>
@@ -1128,7 +1168,7 @@ with T4:
1128
  <div class='insight'>
1129
  Both algorithms found <b>identical optimal paths</b> on every single route - path costs match exactly.
1130
  But A* was faster and expanded fewer nodes every time. The starkest example: R4β†’R9, where
1131
- A* needed 7 node expansions in 0.130 ms while IDA* needed 50 in 0.642 ms.
1132
  For EcoCart's current network, A* is the clear winner. IDA*'s value shows up at national scale β€”
1133
  when the network has millions of nodes and storing A*'s visited set would exhaust memory.
1134
  </div>""", unsafe_allow_html=True)
@@ -1138,7 +1178,7 @@ with T4:
1138
  # ══════════════════════════════════════════════════════════════════════════════
1139
  with T5:
1140
  st.markdown("""
1141
- <div class='task-card'>
1142
  <div class='task-icon' style='background:linear-gradient(135deg,#047857,#34d399);box-shadow:0 6px 20px rgba(4,120,87,.4);font-size:1.5rem;'>πŸ“ˆ</div>
1143
  <div>
1144
  <div class='task-title'>Can a simple model beat 200 decision trees?</div>
@@ -1206,7 +1246,7 @@ with T5:
1206
  # ══════════════════════════════════════════════════════════════════════════════
1207
  with T6:
1208
  st.markdown("""
1209
- <div class='task-card'>
1210
  <div class='task-icon' style='background:linear-gradient(135deg,#c2410c,#fb923c);box-shadow:0 6px 20px rgba(194,65,12,.4);font-size:1.5rem;'>πŸ’Ό</div>
1211
  <div>
1212
  <div class='task-title'>What does all of this actually save the business?</div>
 
135
  <style>
136
  @import url('https://fonts.googleapis.com/css2?family=Inter:opsz,wght@14..32,300;14..32,400;14..32,500;14..32,600;14..32,700;14..32,800;14..32,900&display=swap');
137
 
138
+ @keyframes shimmer{0%{background-position:-300% center}100%{background-position:300% center}}
139
+ @keyframes glow-pulse{0%,100%{opacity:.18}50%{opacity:.42}}
140
+ @keyframes slide-up{from{opacity:0;transform:translateY(14px)}to{opacity:1;transform:translateY(0)}}
141
+ @keyframes dot-ping{0%,100%{box-shadow:0 0 0 0 rgba(129,140,248,.7)}50%{box-shadow:0 0 0 5px rgba(129,140,248,0)}}
142
+
143
  *, *::before, *::after { font-family: 'Inter', -apple-system, sans-serif !important; box-sizing: border-box; }
144
 
145
  /* Base */
146
+ [data-testid="stAppViewContainer"] { background: linear-gradient(155deg,#edf0ff 0%,#f0f2f8 45%,#f3f0ff 100%) !important; }
147
  .block-container { padding: .8rem 1.6rem 4rem !important; max-width: 1300px !important; }
148
  #MainMenu, footer, header { visibility: hidden; }
149
  ::-webkit-scrollbar { width: 4px; } ::-webkit-scrollbar-thumb { background: #cbd5e1; border-radius: 8px; }
 
176
  width: 420px; height: 420px;
177
  background: radial-gradient(circle, rgba(79,70,229,.22) 0%, transparent 60%);
178
  border-radius: 50%; pointer-events: none;
179
+ animation: glow-pulse 5s ease-in-out infinite;
180
  }
181
  .hero::after {
182
  content: ''; position: absolute; bottom: -100px; left: 20%;
183
  width: 360px; height: 360px;
184
  background: radial-gradient(circle, rgba(5,150,105,.18) 0%, transparent 60%);
185
  border-radius: 50%; pointer-events: none;
186
+ animation: glow-pulse 5s ease-in-out infinite 2.5s;
187
  }
188
  .hero-title {
189
+ font-size: 2.4rem; font-weight: 900; letter-spacing: -.055em; line-height: 1.05;
190
  margin: 0 0 10px;
191
+ background: linear-gradient(135deg, #ffffff 0%, #bfdbfe 35%, #6ee7b7 65%, #ffffff 100%);
192
+ background-size: 300% auto;
193
  -webkit-background-clip: text; -webkit-text-fill-color: transparent; background-clip: text;
194
+ animation: shimmer 8s linear infinite;
195
  }
196
  .hero-sub {
197
+ color: #94a3b8; font-size: .86rem; font-weight: 400;
198
  margin-bottom: 28px; line-height: 1.65; max-width: 560px;
199
  }
200
  .hero-stats {
 
224
  box-shadow: 0 4px 24px rgba(0,0,0,.05), 0 1px 3px rgba(0,0,0,.03);
225
  display: flex; gap: 18px; align-items: flex-start;
226
  transition: box-shadow .2s ease, transform .2s ease;
227
+ animation: slide-up .45s ease both;
228
+ border-left-width: 4px;
229
  }
230
+ .task-card:hover { box-shadow: 0 16px 48px rgba(0,0,0,.12); transform: translateY(-3px); }
231
  .task-icon {
232
  width: 52px; height: 52px; border-radius: 15px; flex-shrink: 0;
233
  display: flex; align-items: center; justify-content: center; font-size: 1.5rem;
 
244
  border: 1px solid #86efac; border-radius: 16px;
245
  padding: 16px 20px 16px 60px; position: relative;
246
  color: #14532d; font-size: .82rem; line-height: 1.8; margin: 14px 0;
247
+ box-shadow: 0 8px 32px rgba(5,150,105,.15), inset 0 1px 0 rgba(255,255,255,.7);
248
  }
249
  .insight::before {
250
  content: 'βœ“'; position: absolute; left: 16px; top: 16px;
 
261
  border: 1px solid #fcd34d; border-radius: 16px;
262
  padding: 16px 20px 16px 60px; position: relative;
263
  color: #78350f; font-size: .82rem; line-height: 1.8; margin: 14px 0;
264
+ box-shadow: 0 8px 32px rgba(217,119,6,.15), inset 0 1px 0 rgba(255,255,255,.7);
265
  }
266
  .warn-box::before {
267
  content: '!'; position: absolute; left: 16px; top: 16px;
 
304
 
305
  /* Metrics */
306
  div[data-testid="metric-container"] {
307
+ background: linear-gradient(145deg, #fff 0%, #f8fafc 100%);
308
+ border-radius: 16px; padding: 18px 20px;
309
+ border: 1px solid #e2e8f0; border-top: 3px solid #6366f1;
310
+ box-shadow: 0 4px 20px rgba(0,0,0,.06);
311
  transition: transform .18s ease, box-shadow .18s ease;
312
  }
313
+ div[data-testid="metric-container"]:hover { transform: translateY(-3px); box-shadow: 0 12px 36px rgba(0,0,0,.1); }
314
  div[data-testid="metric-container"] label { font-size: .68rem !important; font-weight: 800 !important; color: #94a3b8 !important; text-transform: uppercase; letter-spacing: .08em; }
315
  div[data-testid="metric-container"] [data-testid="stMetricValue"] { font-size: 1.5rem !important; font-weight: 900 !important; color: #0f172a !important; letter-spacing: -.03em; }
316
 
 
399
 
400
  /* Slider */
401
  .stSlider [data-testid="stTickBarMin"], .stSlider [data-testid="stTickBarMax"] { font-size: .72rem !important; }
402
+
403
+ /* Hero badge */
404
+ .hero-badge {
405
+ display: inline-flex; align-items: center; gap: 8px;
406
+ background: rgba(99,102,241,.14); border: 1.5px solid rgba(99,102,241,.3);
407
+ border-radius: 20px; padding: 5px 14px; margin-bottom: 16px;
408
+ backdrop-filter: blur(8px);
409
+ }
410
+ .hero-badge-dot {
411
+ width: 7px; height: 7px; border-radius: 50%; background: #818cf8; flex-shrink: 0;
412
+ animation: dot-ping 2.4s ease-in-out infinite;
413
+ }
414
+ .hero-badge-txt { font-size: .63rem; font-weight: 700; color: #a5b4fc; text-transform: uppercase; letter-spacing: .1em; }
415
+
416
+ /* Sidebar brand icon box */
417
+ .sb-icon-box {
418
+ width: 64px; height: 64px; border-radius: 20px; margin: 0 auto 10px;
419
+ background: linear-gradient(135deg, #0f172a 0%, #1e3a5f 100%);
420
+ display: flex; align-items: center; justify-content: center;
421
+ font-size: 2rem; box-shadow: 0 6px 24px rgba(15,23,42,.25);
422
+ }
423
+ .sb-version {
424
+ display: inline-block; background: #f0f9ff; border: 1px solid #bae6fd;
425
+ border-radius: 10px; padding: 2px 9px; font-size: .6rem;
426
+ font-weight: 700; color: #0ea5e9; margin-top: 5px;
427
+ }
428
  </style>
429
  """, unsafe_allow_html=True)
430
 
 
434
  with st.sidebar:
435
  st.markdown("""
436
  <div class='sb-brand'>
437
+ <div class='sb-icon-box'>πŸ›’</div>
438
  <div class='sb-name'>EcoCart AI</div>
439
  <div class='sb-sub'>Esvanth Mohankumar Β· 24311073</div>
440
+ <div class='sb-version'>v2.0 Β· May 2026</div>
441
  </div>""", unsafe_allow_html=True)
442
 
443
  st.markdown("<div class='sb-section'>How to use</div>", unsafe_allow_html=True)
444
  for n, t in [("1","Pick a task tab above"),
445
+ ("2","Tasks 2, 3, 5 β€” press Run"),
446
+ ("3","Tasks 1 & 3 β€” use Play / Slider"),
447
+ ("4","Task 6 β€” adjust the sliders")]:
448
  st.markdown(f"""<div class='sb-step'>
449
  <div class='sb-num'>{n}</div>
450
  <span class='sb-step-txt'>{t}</span></div>""", unsafe_allow_html=True)
 
470
  st.markdown("""
471
  <div class='hero'>
472
  <div class='hero-title'>EcoCart AI System</div>
473
+ <div class='hero-sub'>Six AI tasks built to solve one real logistics problem β€” every chart and number runs from actual Python scripts</div>
474
  <div style='display:flex;gap:10px;flex-wrap:wrap;margin-top:4px;'>
475
  <div style='background:rgba(96,165,250,.18);border:1.5px solid rgba(96,165,250,.4);border-radius:14px;padding:14px 22px;text-align:center;min-width:86px;backdrop-filter:blur(8px);'>
476
  <div style='color:#93c5fd;font-size:1.7rem;font-weight:900;letter-spacing:-.04em;line-height:1;'>6</div>
 
497
 
498
  T1, T2, T3, T4, T5, T6 = st.tabs([
499
  "πŸ€– Task 1 - AI Agents",
500
+ "βš–οΈ Task 2 - Bias",
501
+ "πŸ—ΊοΈ Task 3 - Routes",
502
  "πŸ“Š Task 4 - A* vs IDA*",
503
  "πŸ“ˆ Task 5 - Forecast",
504
  "πŸ’Ό Task 6 - Business",
 
509
  # ══════════════════════════════════════════════════════════════════════════════
510
  with T1:
511
  st.markdown("""
512
+ <div class='task-card' style='border-left-color:#6366f1;'>
513
  <div class='task-icon' style='background:linear-gradient(135deg,#4f46e5,#818cf8);box-shadow:0 6px 20px rgba(99,102,241,.4);font-size:1.5rem;'>πŸ€–</div>
514
  <div>
515
  <div class='task-title'>Three agents, one delivery map. Completely different decisions.</div>
 
750
  # ══════════════════════════════════════════════════════════════════════════════
751
  with T2:
752
  st.markdown("""
753
+ <div class='task-card' style='border-left-color:#f59e0b;'>
754
  <div class='task-icon' style='background:linear-gradient(135deg,#b45309,#f59e0b);box-shadow:0 6px 20px rgba(180,83,9,.4);font-size:1.5rem;'>βš–οΈ</div>
755
  <div>
756
  <div class='task-title'>The model was being unfair. Nobody noticed until now.</div>
 
811
  # ══════════════════════════════════════════════════════════════════════════════
812
  with T3:
813
  st.markdown("""
814
+ <div class='task-card' style='border-left-color:#0ea5e9;'>
815
  <div class='task-icon' style='background:linear-gradient(135deg,#0369a1,#38bdf8);box-shadow:0 6px 20px rgba(3,105,161,.4);font-size:1.5rem;'>πŸ—ΊοΈ</div>
816
  <div>
817
  <div class='task-title'>Four algorithms, one delivery network. Which one wins?</div>
 
1111
  # ══════════════════════════════════════════════════════════════════════════════
1112
  with T4:
1113
  st.markdown("""
1114
+ <div class='task-card' style='border-left-color:#8b5cf6;'>
1115
  <div class='task-icon' style='background:linear-gradient(135deg,#6d28d9,#a78bfa);box-shadow:0 6px 20px rgba(109,40,217,.4);font-size:1.5rem;'>πŸ“Š</div>
1116
  <div>
1117
  <div class='task-title'>Same shortest path, completely different strategies</div>
 
1168
  <div class='insight'>
1169
  Both algorithms found <b>identical optimal paths</b> on every single route - path costs match exactly.
1170
  But A* was faster and expanded fewer nodes every time. The starkest example: R4β†’R9, where
1171
+ A* needed 7 node expansions in 0.125 ms while IDA* needed 50 in 0.673 ms.
1172
  For EcoCart's current network, A* is the clear winner. IDA*'s value shows up at national scale β€”
1173
  when the network has millions of nodes and storing A*'s visited set would exhaust memory.
1174
  </div>""", unsafe_allow_html=True)
 
1178
  # ══════════════════════════════════════════════════════════════════════════════
1179
  with T5:
1180
  st.markdown("""
1181
+ <div class='task-card' style='border-left-color:#10b981;'>
1182
  <div class='task-icon' style='background:linear-gradient(135deg,#047857,#34d399);box-shadow:0 6px 20px rgba(4,120,87,.4);font-size:1.5rem;'>πŸ“ˆ</div>
1183
  <div>
1184
  <div class='task-title'>Can a simple model beat 200 decision trees?</div>
 
1246
  # ══════════════════════════════════════════════════════════════════════════════
1247
  with T6:
1248
  st.markdown("""
1249
+ <div class='task-card' style='border-left-color:#f97316;'>
1250
  <div class='task-icon' style='background:linear-gradient(135deg,#c2410c,#fb923c);box-shadow:0 6px 20px rgba(194,65,12,.4);font-size:1.5rem;'>πŸ’Ό</div>
1251
  <div>
1252
  <div class='task-title'>What does all of this actually save the business?</div>