Roasted Bean Deploy commited on
Commit
63c7397
Β·
1 Parent(s): a3cc6f8

πŸ’° β‚Ή prices + dynamic cafe name everywhere

Browse files
data/menu.json CHANGED
@@ -6,7 +6,7 @@
6
  "id": "a1b2c3d4-0001",
7
  "name": "Cappuccino",
8
  "description": "Rich espresso topped with velvety steamed milk foam. A timeless Italian favorite.",
9
- "price": 4.5,
10
  "category": "coffee",
11
  "image": "https://images.unsplash.com/photo-1572442388796-11668a67e53d?w=160&h=160&fit=crop&auto=format",
12
  "available": true,
@@ -16,7 +16,7 @@
16
  "id": "a1b2c3d4-0002",
17
  "name": "Vanilla Latte",
18
  "description": "Smooth espresso with steamed milk and house-made vanilla syrup.",
19
- "price": 5,
20
  "category": "coffee",
21
  "image": "https://images.unsplash.com/photo-1461023058943-07fcbe16d735?w=160&h=160&fit=crop&auto=format",
22
  "available": true,
@@ -26,7 +26,7 @@
26
  "id": "a1b2c3d4-0003",
27
  "name": "Cold Brew",
28
  "description": "Slow-steeped for 18 hours \u2014 smooth, bold, and naturally sweet. Served over ice.",
29
- "price": 4.75,
30
  "category": "coffee",
31
  "image": "https://images.unsplash.com/photo-1517701550927-30cf4ba1dba5?w=160&h=160&fit=crop&auto=format",
32
  "available": true,
@@ -36,7 +36,7 @@
36
  "id": "a1b2c3d4-0004",
37
  "name": "Caramel Macchiato",
38
  "description": "Layered espresso and milk with a buttery caramel drizzle.",
39
- "price": 5.5,
40
  "category": "coffee",
41
  "image": "https://images.unsplash.com/photo-1485808191679-5f86510681a2?w=160&h=160&fit=crop&auto=format",
42
  "available": true,
@@ -46,7 +46,7 @@
46
  "id": "a1b2c3d4-0005",
47
  "name": "Mocha",
48
  "description": "Decadent chocolate meets bold espresso, crowned with whipped cream.",
49
- "price": 5.25,
50
  "category": "coffee",
51
  "image": "https://images.unsplash.com/photo-1578314675249-a6910f80cc4e?w=160&h=160&fit=crop&auto=format",
52
  "available": true,
@@ -56,7 +56,7 @@
56
  "id": "a1b2c3d4-0006",
57
  "name": "Matcha Latte",
58
  "description": "Ceremonial-grade Japanese matcha whisked with steamed oat milk.",
59
- "price": 5.5,
60
  "category": "tea",
61
  "image": "https://images.unsplash.com/photo-1536256263959-770b48d82b0a?w=160&h=160&fit=crop&auto=format",
62
  "available": true,
@@ -66,7 +66,7 @@
66
  "id": "a1b2c3d4-0007",
67
  "name": "Earl Grey",
68
  "description": "Fragrant black tea with bergamot. Served in a pot with a lemon twist.",
69
- "price": 3.75,
70
  "category": "tea",
71
  "image": "https://images.unsplash.com/photo-1594631252845-29fc4cc8cde9?w=160&h=160&fit=crop&auto=format",
72
  "available": true,
@@ -76,7 +76,7 @@
76
  "id": "a1b2c3d4-0008",
77
  "name": "Chamomile Honey",
78
  "description": "Soothing chamomile blossoms with a drizzle of local wildflower honey.",
79
- "price": 3.5,
80
  "category": "tea",
81
  "image": "https://images.unsplash.com/photo-1576092768241-dec231879fc3?w=160&h=160&fit=crop&auto=format",
82
  "available": true,
@@ -86,7 +86,7 @@
86
  "id": "a1b2c3d4-0009",
87
  "name": "Butter Croissant",
88
  "description": "Flaky, golden, and impossibly buttery. Baked fresh every morning.",
89
- "price": 3.75,
90
  "category": "pastries",
91
  "image": "https://images.unsplash.com/photo-1623334044303-241021148842?w=160&h=160&fit=crop&auto=format",
92
  "available": true,
@@ -96,7 +96,7 @@
96
  "id": "a1b2c3d4-0010",
97
  "name": "Blueberry Muffin",
98
  "description": "Tender crumb studded with wild blueberries and a streusel top.",
99
- "price": 4.25,
100
  "category": "pastries",
101
  "image": "https://images.unsplash.com/photo-1607958996333-41aef7caefaa?w=160&h=160&fit=crop&auto=format",
102
  "available": true,
@@ -106,7 +106,7 @@
106
  "id": "a1b2c3d4-0011",
107
  "name": "Cinnamon Roll",
108
  "description": "Soft, gooey, and generously swirled with cinnamon-brown sugar. Topped with cream cheese frosting.",
109
- "price": 5,
110
  "category": "pastries",
111
  "image": "https://images.unsplash.com/photo-1509365465985-25d11c17e812?w=160&h=160&fit=crop&auto=format",
112
  "available": true,
@@ -116,7 +116,7 @@
116
  "id": "a1b2c3d4-0012",
117
  "name": "Avocado Toast",
118
  "description": "Sourdough topped with smashed avocado, cherry tomatoes, feta, and chili flakes.",
119
- "price": 9.5,
120
  "category": "food",
121
  "image": "https://images.unsplash.com/photo-1541519227354-08fa5d50c44d?w=160&h=160&fit=crop&auto=format",
122
  "available": true,
@@ -126,7 +126,7 @@
126
  "id": "a1b2c3d4-0013",
127
  "name": "Caprese Panini",
128
  "description": "Fresh mozzarella, tomato, and basil pressed on ciabatta with balsamic glaze.",
129
- "price": 10.5,
130
  "category": "food",
131
  "image": "https://images.unsplash.com/photo-1509722747041-616f39b57569?w=160&h=160&fit=crop&auto=format",
132
  "available": true,
@@ -136,7 +136,7 @@
136
  "id": "a1b2c3d4-0014",
137
  "name": "A\u00e7a\u00ed Bowl",
138
  "description": "Blended a\u00e7a\u00ed with granola, banana, strawberries, coconut, and a drizzle of honey.",
139
- "price": 11,
140
  "category": "food",
141
  "image": "https://images.unsplash.com/photo-1590301157890-4810ed352733?w=160&h=160&fit=crop&auto=format",
142
  "available": true,
 
6
  "id": "a1b2c3d4-0001",
7
  "name": "Cappuccino",
8
  "description": "Rich espresso topped with velvety steamed milk foam. A timeless Italian favorite.",
9
+ "price": 375,
10
  "category": "coffee",
11
  "image": "https://images.unsplash.com/photo-1572442388796-11668a67e53d?w=160&h=160&fit=crop&auto=format",
12
  "available": true,
 
16
  "id": "a1b2c3d4-0002",
17
  "name": "Vanilla Latte",
18
  "description": "Smooth espresso with steamed milk and house-made vanilla syrup.",
19
+ "price": 415,
20
  "category": "coffee",
21
  "image": "https://images.unsplash.com/photo-1461023058943-07fcbe16d735?w=160&h=160&fit=crop&auto=format",
22
  "available": true,
 
26
  "id": "a1b2c3d4-0003",
27
  "name": "Cold Brew",
28
  "description": "Slow-steeped for 18 hours \u2014 smooth, bold, and naturally sweet. Served over ice.",
29
+ "price": 395,
30
  "category": "coffee",
31
  "image": "https://images.unsplash.com/photo-1517701550927-30cf4ba1dba5?w=160&h=160&fit=crop&auto=format",
32
  "available": true,
 
36
  "id": "a1b2c3d4-0004",
37
  "name": "Caramel Macchiato",
38
  "description": "Layered espresso and milk with a buttery caramel drizzle.",
39
+ "price": 455,
40
  "category": "coffee",
41
  "image": "https://images.unsplash.com/photo-1485808191679-5f86510681a2?w=160&h=160&fit=crop&auto=format",
42
  "available": true,
 
46
  "id": "a1b2c3d4-0005",
47
  "name": "Mocha",
48
  "description": "Decadent chocolate meets bold espresso, crowned with whipped cream.",
49
+ "price": 435,
50
  "category": "coffee",
51
  "image": "https://images.unsplash.com/photo-1578314675249-a6910f80cc4e?w=160&h=160&fit=crop&auto=format",
52
  "available": true,
 
56
  "id": "a1b2c3d4-0006",
57
  "name": "Matcha Latte",
58
  "description": "Ceremonial-grade Japanese matcha whisked with steamed oat milk.",
59
+ "price": 455,
60
  "category": "tea",
61
  "image": "https://images.unsplash.com/photo-1536256263959-770b48d82b0a?w=160&h=160&fit=crop&auto=format",
62
  "available": true,
 
66
  "id": "a1b2c3d4-0007",
67
  "name": "Earl Grey",
68
  "description": "Fragrant black tea with bergamot. Served in a pot with a lemon twist.",
69
+ "price": 310,
70
  "category": "tea",
71
  "image": "https://images.unsplash.com/photo-1594631252845-29fc4cc8cde9?w=160&h=160&fit=crop&auto=format",
72
  "available": true,
 
76
  "id": "a1b2c3d4-0008",
77
  "name": "Chamomile Honey",
78
  "description": "Soothing chamomile blossoms with a drizzle of local wildflower honey.",
79
+ "price": 290,
80
  "category": "tea",
81
  "image": "https://images.unsplash.com/photo-1576092768241-dec231879fc3?w=160&h=160&fit=crop&auto=format",
82
  "available": true,
 
86
  "id": "a1b2c3d4-0009",
87
  "name": "Butter Croissant",
88
  "description": "Flaky, golden, and impossibly buttery. Baked fresh every morning.",
89
+ "price": 310,
90
  "category": "pastries",
91
  "image": "https://images.unsplash.com/photo-1623334044303-241021148842?w=160&h=160&fit=crop&auto=format",
92
  "available": true,
 
96
  "id": "a1b2c3d4-0010",
97
  "name": "Blueberry Muffin",
98
  "description": "Tender crumb studded with wild blueberries and a streusel top.",
99
+ "price": 350,
100
  "category": "pastries",
101
  "image": "https://images.unsplash.com/photo-1607958996333-41aef7caefaa?w=160&h=160&fit=crop&auto=format",
102
  "available": true,
 
106
  "id": "a1b2c3d4-0011",
107
  "name": "Cinnamon Roll",
108
  "description": "Soft, gooey, and generously swirled with cinnamon-brown sugar. Topped with cream cheese frosting.",
109
+ "price": 415,
110
  "category": "pastries",
111
  "image": "https://images.unsplash.com/photo-1509365465985-25d11c17e812?w=160&h=160&fit=crop&auto=format",
112
  "available": true,
 
116
  "id": "a1b2c3d4-0012",
117
  "name": "Avocado Toast",
118
  "description": "Sourdough topped with smashed avocado, cherry tomatoes, feta, and chili flakes.",
119
+ "price": 790,
120
  "category": "food",
121
  "image": "https://images.unsplash.com/photo-1541519227354-08fa5d50c44d?w=160&h=160&fit=crop&auto=format",
122
  "available": true,
 
126
  "id": "a1b2c3d4-0013",
127
  "name": "Caprese Panini",
128
  "description": "Fresh mozzarella, tomato, and basil pressed on ciabatta with balsamic glaze.",
129
+ "price": 870,
130
  "category": "food",
131
  "image": "https://images.unsplash.com/photo-1509722747041-616f39b57569?w=160&h=160&fit=crop&auto=format",
132
  "available": true,
 
136
  "id": "a1b2c3d4-0014",
137
  "name": "A\u00e7a\u00ed Bowl",
138
  "description": "Blended a\u00e7a\u00ed with granola, banana, strawberries, coconut, and a drizzle of honey.",
139
+ "price": 915,
140
  "category": "food",
141
  "image": "https://images.unsplash.com/photo-1590301157890-4810ed352733?w=160&h=160&fit=crop&auto=format",
142
  "available": true,
public/admin.html CHANGED
@@ -30,7 +30,7 @@
30
  <header class="topbar">
31
  <div class="topbar-inner">
32
  <div class="topbar-brand">
33
- <a href="/" class="topbar-logo" target="_blank">The Roasted Bean</a>
34
  <span class="topbar-badge">Admin</span>
35
  </div>
36
  <nav class="topbar-nav" id="topbarNav">
@@ -96,7 +96,7 @@
96
  <form id="infoForm" class="form-block">
97
  <div class="field">
98
  <label for="infoName">Cafe name</label>
99
- <input type="text" id="infoName" placeholder="The Roasted Bean">
100
  </div>
101
  <div class="field">
102
  <label for="infoTagline">Tagline</label>
 
30
  <header class="topbar">
31
  <div class="topbar-inner">
32
  <div class="topbar-brand">
33
+ <a href="/" class="topbar-logo" target="_blank" data-cafe-name>The Roasted Bean</a>
34
  <span class="topbar-badge">Admin</span>
35
  </div>
36
  <nav class="topbar-nav" id="topbarNav">
 
96
  <form id="infoForm" class="form-block">
97
  <div class="field">
98
  <label for="infoName">Cafe name</label>
99
+ <input type="text" id="infoName" placeholder="Cafe Name">
100
  </div>
101
  <div class="field">
102
  <label for="infoTagline">Tagline</label>
public/index.html CHANGED
@@ -14,7 +14,7 @@
14
  <!-- Navigation -->
15
  <nav class="nav" id="nav">
16
  <div class="nav-inner">
17
- <a href="#" class="nav-logo">The Roasted Bean</a>
18
  <div class="nav-links">
19
  <a href="#menu">Menu</a>
20
  <a href="/order">Order</a>
@@ -68,7 +68,7 @@
68
  <div class="about-layout">
69
  <div class="about-text">
70
  <h2 class="section-title">From farm to cup, we pay attention at every step</h2>
71
- <p>The Roasted Bean started in 2018 with a 3-kilo roaster in a garage and a conviction that coffee could be better. Today we operate a full cafe and roastery in Portland's east side, but the conviction hasn't changed.</p>
72
  <p>We buy directly from producers in Ethiopia, Colombia, Guatemala, and beyond β€” paying well above commodity prices because quality farming deserves quality compensation. Each lot is roasted to highlight its unique character, not to conform to a house style.</p>
73
  <div class="about-figures">
74
  <div class="figure">
@@ -106,6 +106,7 @@
106
  src="https://images.unsplash.com/photo-1501339847302-ac426a4a7cbb?w=1920&q=85&fit=crop&crop=center"
107
  alt="Interior of The Roasted Bean cafe"
108
  loading="lazy"
 
109
  />
110
  </div>
111
  <div class="visit-content">
@@ -149,7 +150,7 @@
149
  <div class="container">
150
  <div class="footer-grid">
151
  <div>
152
- <p class="footer-name">The Roasted Bean</p>
153
  <p class="footer-tagline">Specialty coffee roasters<br>Portland, Oregon</p>
154
  </div>
155
  <div class="footer-links">
 
14
  <!-- Navigation -->
15
  <nav class="nav" id="nav">
16
  <div class="nav-inner">
17
+ <a href="#" class="nav-logo" data-cafe-name>The Roasted Bean</a>
18
  <div class="nav-links">
19
  <a href="#menu">Menu</a>
20
  <a href="/order">Order</a>
 
68
  <div class="about-layout">
69
  <div class="about-text">
70
  <h2 class="section-title">From farm to cup, we pay attention at every step</h2>
71
+ <p><span class="cafe-name-ref">The Roasted Bean</span> started in 2018 with a 3-kilo roaster in a garage and a conviction that coffee could be better. Today we operate a full cafe and roastery in Portland's east side, but the conviction hasn't changed.</p>
72
  <p>We buy directly from producers in Ethiopia, Colombia, Guatemala, and beyond β€” paying well above commodity prices because quality farming deserves quality compensation. Each lot is roasted to highlight its unique character, not to conform to a house style.</p>
73
  <div class="about-figures">
74
  <div class="figure">
 
106
  src="https://images.unsplash.com/photo-1501339847302-ac426a4a7cbb?w=1920&q=85&fit=crop&crop=center"
107
  alt="Interior of The Roasted Bean cafe"
108
  loading="lazy"
109
+ id="visitImage"
110
  />
111
  </div>
112
  <div class="visit-content">
 
150
  <div class="container">
151
  <div class="footer-grid">
152
  <div>
153
+ <p class="footer-name" data-cafe-name>The Roasted Bean</p>
154
  <p class="footer-tagline">Specialty coffee roasters<br>Portland, Oregon</p>
155
  </div>
156
  <div class="footer-links">
public/js/admin.js CHANGED
@@ -60,6 +60,11 @@ async function setupDashboard() {
60
  async function loadMenuData() {
61
  const res = await fetch('/api/menu');
62
  menuData = await res.json();
 
 
 
 
 
63
  }
64
 
65
  // ── Navigation ──────────────────────────────────────────────────────────────
 
60
  async function loadMenuData() {
61
  const res = await fetch('/api/menu');
62
  menuData = await res.json();
63
+ // Update cafe name everywhere in admin
64
+ if (menuData.info?.name) {
65
+ document.title = `Admin β€” ${menuData.info.name}`;
66
+ document.querySelectorAll('[data-cafe-name]').forEach(el => el.textContent = menuData.info.name);
67
+ }
68
  }
69
 
70
  // ── Navigation ──────────────────────────────────────────────────────────────
public/js/main.js CHANGED
@@ -63,6 +63,23 @@ function populateHero(info) {
63
  if (info.name) {
64
  document.getElementById('cafeName').textContent = info.name;
65
  document.title = `${info.name} β€” Specialty Coffee Roasters`;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
66
  }
67
  if (info.address) {
68
  const el = document.getElementById('cafeAddressSmall');
@@ -151,7 +168,7 @@ function buildMenu(items, categories) {
151
  </div>
152
  <div class="menu-card-header">
153
  <h3 class="menu-card-name">${escapeHtml(item.name)}</h3>
154
- <span class="menu-card-price">$${item.price.toFixed(2)}</span>
155
  </div>
156
  <span class="menu-card-label">Tasting</span>
157
  <p class="menu-card-description">${escapeHtml(item.description)}</p>
 
63
  if (info.name) {
64
  document.getElementById('cafeName').textContent = info.name;
65
  document.title = `${info.name} β€” Specialty Coffee Roasters`;
66
+ // Update all name references throughout the page
67
+ const nameEls = document.querySelectorAll('[data-cafe-name]');
68
+ nameEls.forEach(el => { el.textContent = info.name; });
69
+ // Update copyright
70
+ const copyEl = document.querySelector('.footer-copy');
71
+ if (copyEl) copyEl.textContent = `Β© 2024 ${info.name}`;
72
+ // Update about text references
73
+ const aboutRefs = document.querySelectorAll('.cafe-name-ref');
74
+ aboutRefs.forEach(el => { el.textContent = info.name; });
75
+ // Update visit image alt text
76
+ const visitImg = document.getElementById('visitImage');
77
+ if (visitImg && info.name) {
78
+ visitImg.alt = `Interior of ${info.name} cafe`;
79
+ }
80
+ // Update footer name
81
+ const footerName = document.querySelector('.footer-name');
82
+ if (footerName) footerName.textContent = info.name;
83
  }
84
  if (info.address) {
85
  const el = document.getElementById('cafeAddressSmall');
 
168
  </div>
169
  <div class="menu-card-header">
170
  <h3 class="menu-card-name">${escapeHtml(item.name)}</h3>
171
+ <span class="menu-card-price">β‚Ή${item.price.toFixed(0)}</span>
172
  </div>
173
  <span class="menu-card-label">Tasting</span>
174
  <p class="menu-card-description">${escapeHtml(item.description)}</p>
public/js/order.js CHANGED
@@ -25,6 +25,11 @@ async function init() {
25
  const tablesData = await tablesRes.json();
26
  tablesCount = tablesData.tables || 0;
27
 
 
 
 
 
 
28
  // No table from URL β€” show table selector
29
  if (!tableNumber) {
30
  document.getElementById('tableDisplay').style.display = 'none';
@@ -95,7 +100,7 @@ function renderItems(catId = 'all') {
95
  <div class="ord-item-name">${esc(item.name)}</div>
96
  <div class="ord-item-desc">${esc(item.description || '')}</div>
97
  </div>
98
- <div class="ord-item-price">$${item.price.toFixed(2)}</div>
99
  <button class="ord-item-add" ${!item.available ? 'disabled' : ''}>${qty > 0 ? qty : '+'}</button>
100
  </div>
101
  `;
@@ -153,14 +158,14 @@ function renderCart() {
153
  <div class="cart-item">
154
  <div class="cart-item-info">
155
  <div class="cart-item-name">${esc(c.name)}</div>
156
- <div class="cart-item-meta">$${c.price.toFixed(2)} each</div>
157
  </div>
158
  <div class="cart-item-qty">
159
  <button class="cart-qty-btn" data-action="minus" data-mid="${c.mid}">βˆ’</button>
160
  <span class="cart-qty-num">${c.qty}</span>
161
  <button class="cart-qty-btn" data-action="plus" data-mid="${c.mid}">+</button>
162
  </div>
163
- <div class="cart-item-price">$${(c.price * c.qty).toFixed(2)}</div>
164
  <button class="cart-item-remove" data-action="remove" data-mid="${c.mid}">βœ•</button>
165
  </div>
166
  `).join('');
@@ -177,7 +182,7 @@ function renderCart() {
177
  });
178
  }
179
 
180
- document.getElementById('cartTotal').textContent = `$${total.toFixed(2)}`;
181
  document.getElementById('cartCount').textContent = cart.reduce((s, c) => s + c.qty, 0);
182
  document.getElementById('cartBadge').style.display = cart.length > 0 ? '' : 'none';
183
 
@@ -211,12 +216,12 @@ async function loadLiveOrders() {
211
  </div>
212
  <ul class="live-order-items">
213
  ${o.items.map(i => i.mid
214
- ? `<li><span>${i.qty}Γ— ${esc(i.name)}</span> <span>$${(i.price * i.qty).toFixed(2)}</span></li>`
215
  : `<li class="lo-custom">"${esc(i.text)}"</li>`
216
  ).join('')}
217
  </ul>
218
  ${o.note ? `<p class="live-order-note">Note: ${esc(o.note)}</p>` : ''}
219
- <p class="live-order-total">$${o.total.toFixed(2)}</p>
220
  </div>
221
  `).join('');
222
  } catch { /* silently fail β€” customer-facing */ }
 
25
  const tablesData = await tablesRes.json();
26
  tablesCount = tablesData.tables || 0;
27
 
28
+ // Update page title
29
+ if (menuData?.info?.name) {
30
+ document.title = `Order β€” ${menuData.info.name}`;
31
+ }
32
+
33
  // No table from URL β€” show table selector
34
  if (!tableNumber) {
35
  document.getElementById('tableDisplay').style.display = 'none';
 
100
  <div class="ord-item-name">${esc(item.name)}</div>
101
  <div class="ord-item-desc">${esc(item.description || '')}</div>
102
  </div>
103
+ <div class="ord-item-price">β‚Ή${item.price.toFixed(0)}</div>
104
  <button class="ord-item-add" ${!item.available ? 'disabled' : ''}>${qty > 0 ? qty : '+'}</button>
105
  </div>
106
  `;
 
158
  <div class="cart-item">
159
  <div class="cart-item-info">
160
  <div class="cart-item-name">${esc(c.name)}</div>
161
+ <div class="cart-item-meta">β‚Ή${c.price.toFixed(0)} each</div>
162
  </div>
163
  <div class="cart-item-qty">
164
  <button class="cart-qty-btn" data-action="minus" data-mid="${c.mid}">βˆ’</button>
165
  <span class="cart-qty-num">${c.qty}</span>
166
  <button class="cart-qty-btn" data-action="plus" data-mid="${c.mid}">+</button>
167
  </div>
168
+ <div class="cart-item-price">β‚Ή${(c.price * c.qty).toFixed(0)}</div>
169
  <button class="cart-item-remove" data-action="remove" data-mid="${c.mid}">βœ•</button>
170
  </div>
171
  `).join('');
 
182
  });
183
  }
184
 
185
+ document.getElementById('cartTotal').textContent = `β‚Ή${total.toFixed(0)}`;
186
  document.getElementById('cartCount').textContent = cart.reduce((s, c) => s + c.qty, 0);
187
  document.getElementById('cartBadge').style.display = cart.length > 0 ? '' : 'none';
188
 
 
216
  </div>
217
  <ul class="live-order-items">
218
  ${o.items.map(i => i.mid
219
+ ? `<li><span>${i.qty}Γ— ${esc(i.name)}</span> <span>β‚Ή${(i.price * i.qty).toFixed(0)}</span></li>`
220
  : `<li class="lo-custom">"${esc(i.text)}"</li>`
221
  ).join('')}
222
  </ul>
223
  ${o.note ? `<p class="live-order-note">Note: ${esc(o.note)}</p>` : ''}
224
+ <p class="live-order-total">β‚Ή${o.total.toFixed(0)}</p>
225
  </div>
226
  `).join('');
227
  } catch { /* silently fail β€” customer-facing */ }
server.js CHANGED
@@ -353,6 +353,6 @@ function scheduleMidnightCleanup() {
353
 
354
  // ── Start ───────────────────────────────────────────────────────────────────
355
  app.listen(PORT, '0.0.0.0', () => {
356
- console.log(`β˜• The Roasted Bean serving on 0.0.0.0:${PORT}`);
357
  });
358
  scheduleMidnightCleanup();
 
353
 
354
  // ── Start ───────────────────────────────────────────────────────────────────
355
  app.listen(PORT, '0.0.0.0', () => {
356
+ console.log(`β˜• Cafe serving on 0.0.0.0:${PORT}`);
357
  });
358
  scheduleMidnightCleanup();