humanvprojectceo commited on
Commit
228f8fd
·
verified ·
1 Parent(s): 7c5d3c3

Update customer.html

Browse files
Files changed (1) hide show
  1. customer.html +163 -172
customer.html CHANGED
@@ -22,47 +22,12 @@
22
  display: ['Lalezar', 'serif'],
23
  },
24
  colors: {
25
- bazaar: {
26
- 950: '#1a0d07',
27
- 900: '#2d1810',
28
- 800: '#3d2418',
29
- 700: '#5c3a2a',
30
- 600: '#7a4e3a',
31
- 500: '#9c6b4f',
32
- 400: '#b8856a',
33
- 300: '#d4a88c',
34
- },
35
- azure: {
36
- 950: '#051a2e',
37
- 900: '#0a2540',
38
- 800: '#123a5e',
39
- 700: '#1e4976',
40
- 600: '#2d6ca8',
41
- 500: '#3d8bc4',
42
- 400: '#6ba7d4',
43
- 300: '#a3c8e4',
44
- },
45
- turk: {
46
- DEFAULT: '#0d9488',
47
- light: '#2dd4bf',
48
- glow: '#5eead4',
49
- deep: '#134e4a',
50
- },
51
- rug: {
52
- DEFAULT: '#8b1e3f',
53
- light: '#c23d5f',
54
- dark: '#5a1028',
55
- glow: '#e85d7e',
56
- },
57
- ochre: {
58
- DEFAULT: '#c9a961',
59
- light: '#e4c97a',
60
- dark: '#9c7d3a',
61
- pale: '#f0dca3',
62
- },
63
- ivory: '#faf3e7',
64
- cream: '#f5e6d3',
65
- saffron: '#d97706',
66
  },
67
  boxShadow: {
68
  'carpet': '0 10px 40px -10px rgba(139, 30, 63, 0.35), 0 0 0 1px rgba(201, 169, 97, 0.15)',
@@ -78,22 +43,10 @@
78
  'fade-in': 'fadeIn 0.35s ease-out',
79
  },
80
  keyframes: {
81
- float: {
82
- '0%, 100%': { transform: 'translateY(0px)' },
83
- '50%': { transform: 'translateY(-12px)' },
84
- },
85
- shimmer: {
86
- '0%, 100%': { opacity: '0.7' },
87
- '50%': { opacity: '1' },
88
- },
89
- pulseGlow: {
90
- '0%, 100%': { boxShadow: '0 0 20px rgba(201, 169, 97, 0.3)' },
91
- '50%': { boxShadow: '0 0 40px rgba(201, 169, 97, 0.6)' },
92
- },
93
- fadeIn: {
94
- '0%': { opacity: '0', transform: 'translateY(8px)' },
95
- '100%': { opacity: '1', transform: 'translateY(0)' },
96
- },
97
  },
98
  }
99
  }
@@ -103,21 +56,22 @@
103
  <style>
104
  :root {
105
  --pattern-url: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='80' height='80' viewBox='0 0 80 80'%3E%3Cg fill='none' stroke='%23c9a961' stroke-width='0.6' opacity='0.08'%3E%3Cpath d='M40 10 L50 20 L60 10 L70 20 L60 30 L70 40 L60 50 L70 60 L60 70 L50 60 L40 70 L30 60 L20 70 L10 60 L20 50 L10 40 L20 30 L10 20 L20 10 L30 20 Z'/%3E%3Ccircle cx='40' cy='40' r='12'/%3E%3Ccircle cx='40' cy='40' r='6'/%3E%3Cpath d='M40 28 L40 52 M28 40 L52 40'/%3E%3C/g%3E%3C/svg%3E");
 
106
  }
107
 
108
  * { box-sizing: border-box; }
109
 
110
- html {
111
- scroll-behavior: smooth;
112
  height: 100%;
113
  overflow: hidden;
114
- }
115
-
116
- html, body {
117
  overscroll-behavior: none;
118
  -webkit-overflow-scrolling: touch;
119
  }
120
 
 
 
 
 
121
  body {
122
  background-color: #1a0d07;
123
  color: #f5e6d3;
@@ -125,17 +79,10 @@
125
  font-feature-settings: "ss01", "cv01";
126
  margin: 0;
127
  padding: 0;
128
- height: 100vh;
129
- height: 100dvh;
130
  overflow: hidden;
131
- position: fixed;
132
- width: 100%;
133
  }
134
 
135
- .bg-pattern {
136
- background-image: var(--pattern-url);
137
- background-size: 80px 80px;
138
- }
139
 
140
  .bg-pattern-fine {
141
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='40' height='40' viewBox='0 0 40 40'%3E%3Cg fill='none' stroke='%23c9a961' stroke-width='0.4' opacity='0.1'%3E%3Cpath d='M20 0 L20 40 M0 20 L40 20'/%3E%3Ccircle cx='20' cy='20' r='3'/%3E%3Ccircle cx='0' cy='0' r='2'/%3E%3Ccircle cx='40' cy='0' r='2'/%3E%3Ccircle cx='0' cy='40' r='2'/%3E%3Ccircle cx='40' cy='40' r='2'/%3E%3C/g%3E%3C/svg%3E");
@@ -152,6 +99,7 @@
152
  background: linear-gradient(180deg, #c9a961, #8b1e3f);
153
  border-radius: 4px;
154
  }
 
155
 
156
  .glass-card {
157
  background: linear-gradient(135deg, rgba(45, 24, 16, 0.82) 0%, rgba(26, 13, 7, 0.78) 100%);
@@ -215,11 +163,8 @@
215
  .chat-markdown > * + * { margin-top: 0.6em; }
216
  .chat-markdown h1, .chat-markdown h2, .chat-markdown h3,
217
  .chat-markdown h4, .chat-markdown h5, .chat-markdown h6 {
218
- font-family: 'Lalezar', serif;
219
- color: #e4c97a;
220
- margin-top: 1em;
221
- margin-bottom: 0.4em;
222
- line-height: 1.3;
223
  }
224
  .chat-markdown h1 { font-size: 1.4em; }
225
  .chat-markdown h2 { font-size: 1.25em; }
@@ -235,62 +180,45 @@
235
  .chat-markdown em { color: #5eead4; font-style: italic; }
236
  .chat-markdown a { color: #2dd4bf; text-decoration: underline; text-underline-offset: 3px; }
237
  .chat-markdown code {
238
- background: rgba(13, 148, 136, 0.18);
239
- color: #5eead4;
240
- padding: 0.15em 0.4em;
241
- border-radius: 5px;
242
- font-size: 0.88em;
243
  border: 1px solid rgba(45, 212, 191, 0.2);
244
  font-family: 'Courier New', monospace;
245
- direction: ltr;
246
- display: inline-block;
247
  }
248
  .chat-markdown pre {
249
  background: rgba(5, 26, 46, 0.7);
250
  border: 1px solid rgba(45, 212, 191, 0.25);
251
  border-right: 3px solid #0d9488;
252
- padding: 0.9em 1em;
253
- border-radius: 8px;
254
- overflow-x: auto;
255
- margin: 0.6em 0;
256
- direction: ltr;
257
- text-align: left;
258
  }
259
  .chat-markdown pre code { background: transparent; border: none; padding: 0; color: #a3c8e4; font-size: 0.85em; }
260
  .chat-markdown blockquote {
261
  border-right: 3px solid #c9a961;
262
  background: linear-gradient(90deg, rgba(201, 169, 97, 0.08), transparent);
263
- padding: 0.5em 1em;
264
- margin: 0.6em 0;
265
- color: #f0dca3;
266
- font-style: italic;
267
  border-radius: 0 8px 8px 0;
268
  }
269
  .chat-markdown blockquote p { margin: 0; }
270
  .chat-markdown hr {
271
- border: none;
272
- height: 1px;
273
  background: linear-gradient(90deg, transparent, rgba(201, 169, 97, 0.5), transparent);
274
  margin: 1em 0;
275
  }
276
  .chat-markdown table {
277
- width: 100%;
278
- border-collapse: collapse;
279
- margin: 0.6em 0;
280
- font-size: 0.92em;
281
- background: rgba(45, 24, 16, 0.5);
282
- border-radius: 8px;
283
- overflow: hidden;
284
  border: 1px solid rgba(201, 169, 97, 0.25);
285
- display: block;
286
- overflow-x: auto;
287
  }
288
  .chat-markdown thead { background: linear-gradient(90deg, rgba(139, 30, 63, 0.4), rgba(201, 169, 97, 0.2)); }
289
  .chat-markdown th {
290
- padding: 0.55em 0.8em;
291
- text-align: right;
292
- color: #e4c97a;
293
- font-weight: 700;
294
  border-bottom: 1px solid rgba(201, 169, 97, 0.3);
295
  font-family: 'Lalezar', serif;
296
  }
@@ -303,8 +231,7 @@
303
 
304
  .btn-primary {
305
  background: linear-gradient(135deg, #c9a961 0%, #9c7d3a 100%);
306
- color: #1a0d07;
307
- font-weight: 800;
308
  transition: all 0.3s ease;
309
  box-shadow: 0 8px 20px -5px rgba(201, 169, 97, 0.4);
310
  }
@@ -315,19 +242,9 @@
315
  }
316
  .btn-primary:disabled { opacity: 0.5; cursor: not-allowed; transform: none; }
317
 
318
- .btn-rug {
319
- background: linear-gradient(135deg, #8b1e3f 0%, #5a1028 100%);
320
- color: #f5e6d3;
321
- border: 1px solid rgba(201, 169, 97, 0.3);
322
- }
323
- .btn-rug:hover { background: linear-gradient(135deg, #c23d5f 0%, #8b1e3f 100%); border-color: rgba(201, 169, 97, 0.6); }
324
-
325
  .typing-dots span {
326
- display: inline-block;
327
- width: 6px;
328
- height: 6px;
329
- border-radius: 50%;
330
- background: #c9a961;
331
  animation: typing 1.4s infinite;
332
  }
333
  .typing-dots span:nth-child(2) { animation-delay: 0.2s; }
@@ -366,8 +283,7 @@
366
 
367
  button, .no-select { -webkit-user-select: none; user-select: none; }
368
 
369
- /* ============ FOOTER FIX ============ */
370
- /* فوتر به صورت ثابت در پایین view قرار می‌گیرد و هرگز روی محتوا نمی‌افتد */
371
  .app-footer {
372
  flex-shrink: 0;
373
  position: relative;
@@ -378,42 +294,100 @@
378
  border-top: 1px solid rgba(201, 169, 97, 0.15);
379
  }
380
 
381
- /* Mobile First */
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
382
  @media (max-width: 639px) {
383
  .hero-title { font-size: 2.5rem !important; }
384
  .hero-logo { width: 70px !important; height: 70px !important; }
385
  .tables-grid { grid-template-columns: repeat(4, 1fr) !important; gap: 0.5rem !important; }
386
  .table-btn span { font-size: 1.5rem !important; }
387
  .info-cards { grid-template-columns: 1fr !important; }
388
- .chat-input-area { padding-bottom: calc(0.75rem + env(safe-area-inset-bottom)) !important; }
 
 
 
 
 
 
 
 
 
389
  }
390
 
 
391
  @media (min-width: 640px) and (max-width: 1023px) {
392
  .hero-title { font-size: 3.5rem !important; }
393
  .hero-logo { width: 90px !important; height: 90px !important; }
394
  .tables-grid { grid-template-columns: repeat(5, 1fr) !important; }
395
  .info-cards { grid-template-columns: repeat(2, 1fr) !important; }
 
 
 
 
 
 
 
396
  }
397
 
 
398
  @media (min-width: 1024px) {
399
  .hero-title { font-size: 4.5rem !important; }
400
  .hero-logo { width: 100px !important; height: 100px !important; }
401
  .tables-grid { grid-template-columns: repeat(10, 1fr) !important; }
402
  .info-cards { grid-template-columns: repeat(3, 1fr) !important; }
 
 
 
 
403
  }
404
 
 
405
  @media (max-height: 500px) and (orientation: landscape) {
406
  .hero-title { font-size: 2rem !important; }
407
  .hero-logo { width: 50px !important; height: 50px !important; }
408
  .hero-header { padding-top: 0.5rem !important; padding-bottom: 0.25rem !important; }
409
- .chat-column { min-height: 280px !important; }
 
 
 
410
  }
411
 
 
412
  @media (max-width: 380px) {
413
  .tables-grid { grid-template-columns: repeat(4, 1fr) !important; }
414
  .table-btn { padding: 0.375rem !important; }
415
  .table-btn span { font-size: 1.25rem !important; }
416
  .hero-title { font-size: 2rem !important; }
 
 
 
 
 
 
417
  }
418
 
419
  @supports (padding-bottom: env(safe-area-inset-bottom)) {
@@ -427,7 +401,6 @@
427
  <!-- ============ VIEW 1: TABLE SELECTION ============ -->
428
  <section id="view-table-selection" class="view-container view-visible">
429
 
430
- <!-- Ambient Background (fixed) -->
431
  <div class="absolute inset-0 overflow-hidden pointer-events-none z-0">
432
  <div class="absolute inset-0 bg-gradient-to-br from-bazaar-950 via-bazaar-900 to-azure-950"></div>
433
  <div class="absolute inset-0 bg-pattern opacity-40"></div>
@@ -436,10 +409,8 @@
436
  <div class="absolute top-1/3 left-1/4 w-[400px] h-[400px] rounded-full bg-ochre/8 blur-[120px] animate-shimmer"></div>
437
  </div>
438
 
439
- <!-- Scrollable wrapper (فقط header و main، بدون footer) -->
440
  <div class="scroll-area flex-1 min-h-0 relative z-10">
441
 
442
- <!-- Hero Header -->
443
  <header class="hero-header px-4 pt-6 pb-3 md:pt-10 md:pb-4 text-center relative flex-shrink-0">
444
  <div class="max-w-4xl mx-auto">
445
  <div class="inline-flex items-center gap-4 mb-4 animate-float">
@@ -469,7 +440,6 @@
469
  </div>
470
  </header>
471
 
472
- <!-- Main content -->
473
  <main class="px-4 md:px-8 pb-8 relative">
474
  <div class="max-w-5xl mx-auto">
475
 
@@ -509,7 +479,6 @@
509
  </div>
510
  </div>
511
 
512
- <!-- Info Cards -->
513
  <div class="info-cards grid grid-cols-1 md:grid-cols-3 gap-3 mb-6">
514
  <div class="glass-card rounded-2xl p-4 relative overflow-hidden group">
515
  <div class="absolute top-0 right-0 w-20 h-20 bg-rug/15 rounded-full blur-2xl group-hover:bg-rug/25 transition-all"></div>
@@ -554,17 +523,15 @@
554
  </main>
555
  </div>
556
 
557
- <!-- Footer (خارج از scroll-area، در پایین view-container) -->
558
  <footer class="app-footer py-3 text-center text-[10px] text-cream/40 safe-top safe-bottom">
559
  طراحی و توسعه توسط الگوریتم داده نسترن | با الهام از فرهنگ تبریز © ۲۰۲۶
560
  </footer>
561
  </section>
562
 
563
 
564
- <!-- ============ VIEW 2: CHAT (بدون فوتر) ============ -->
565
  <section id="view-chat" class="view-container view-hidden">
566
 
567
- <!-- Ambient Background -->
568
  <div class="absolute inset-0 overflow-hidden pointer-events-none z-0">
569
  <div class="absolute inset-0 bg-gradient-to-br from-bazaar-950 via-bazaar-900 to-azure-950"></div>
570
  <div class="absolute inset-0 bg-pattern opacity-30"></div>
@@ -604,11 +571,16 @@
604
  <span class="text-[10px] text-cream/60">میز</span>
605
  <span id="tableNumberDisplay" class="text-base md:text-lg font-display text-ochre-light table-number-glow">---</span>
606
  </div>
 
 
 
 
 
607
  </div>
608
  </div>
609
  </header>
610
 
611
- <!-- Main content -->
612
  <main class="flex-1 flex flex-col min-h-0 p-2.5 md:p-4 lg:p-6 z-10 relative gap-3 overflow-hidden">
613
  <div class="max-w-5xl w-full mx-auto flex-1 flex flex-col min-h-0 gap-3">
614
 
@@ -635,11 +607,12 @@
635
  </div>
636
  </div>
637
 
638
- <!-- Chat card -->
639
- <div class="chat-column flex-1 flex flex-col glass-card-azure rounded-2xl md:rounded-3xl overflow-hidden shadow-xl min-h-0 relative">
640
  <div class="absolute inset-0 bg-arch opacity-20 pointer-events-none"></div>
641
 
642
- <div class="relative flex-shrink-0 px-3.5 py-2.5 md:px-5 md:py-3 border-b border-turk/25 flex items-center gap-2.5 bg-gradient-to-l from-azure-950/60 to-azure-900/40">
 
643
  <div class="w-9 h-9 md:w-10 md:h-10 rounded-xl bg-gradient-to-br from-turk/30 to-azure-700/30 border border-turk/40 flex items-center justify-center shadow-mosque flex-shrink-0">
644
  <svg class="w-5 h-5 md:w-6 md:h-6 text-turk-glow" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8">
645
  <circle cx="12" cy="8" r="4"/>
@@ -647,7 +620,7 @@
647
  <path d="M9 10l2 2 4-4" stroke-linecap="round" stroke-linejoin="round" opacity="0.7"/>
648
  </svg>
649
  </div>
650
- <div class="min-w-0">
651
  <h3 class="text-xs md:text-sm font-display text-ochre-light tracking-wide">نیلا، دستیار کافه</h3>
652
  <p class="text-[9px] md:text-[10px] text-turk-light/80 font-medium flex items-center gap-1.5">
653
  <span class="w-1.5 h-1.5 rounded-full bg-turk-light animate-pulse"></span>
@@ -656,19 +629,21 @@
656
  </div>
657
  </div>
658
 
659
- <div id="chatMessages" class="relative flex-1 overflow-y-auto scroll-area p-3 md:p-4 space-y-3 min-h-0">
660
- <div class="flex gap-2.5 max-w-[88%]">
 
661
  <div class="w-7 h-7 md:w-8 md:h-8 rounded-xl bg-gradient-to-br from-turk/20 to-azure-700/20 border border-turk/30 flex items-center justify-center flex-shrink-0">
662
  <span class="text-ochre-light font-display text-[10px] md:text-[11px]">ن</span>
663
  </div>
664
- <div class="bg-bazaar-950/70 border border-ochre/20 text-cream text-xs md:text-sm rounded-2xl rounded-tr-none px-3 py-2 md:px-3.5 md:py-2.5 leading-relaxed shadow-inner-soft chat-markdown">
665
  سلام! من <strong>نیلا</strong> هستم، دستیار هوشمند کافه آی. به میزتون خوش اومدید 🌸<br>
666
  چه نوشیدنی، غذا یا شیرینی‌ای می‌پسندید؟ <em>منوی امروز</em> رو می‌تونم براتون بگم. 😊
667
  </div>
668
  </div>
669
  </div>
670
 
671
- <div id="chatLoader" class="hidden relative flex-shrink-0 px-3 py-2 md:px-4 md:py-2.5 flex items-center justify-between bg-azure-950/70 text-[9px] md:text-[10px] text-turk-light font-semibold border-t border-turk/20">
 
672
  <div class="flex items-center gap-2">
673
  <div class="typing-dots flex gap-1">
674
  <span></span><span></span><span></span>
@@ -678,7 +653,8 @@
678
  <button onclick="stopGeneration()" class="px-2.5 py-1 md:px-3 md:py-1.5 bg-rug-dark/40 border border-rug/40 hover:bg-rug/40 rounded-lg text-[9px] md:text-[10px] text-rug-light font-bold transition-all">توقف</button>
679
  </div>
680
 
681
- <form id="chatForm" onsubmit="sendCustomerMessage(event)" class="relative flex-shrink-0 p-2 md:p-3 border-t border-turk/20 bg-bazaar-950/60 flex gap-2 chat-input-area safe-bottom">
 
682
  <input type="text" id="chatInput" placeholder="پیام خود را بنویسید..." autocomplete="off"
683
  class="flex-1 min-w-0 bg-azure-950/60 border border-azure-700/40 text-xs md:text-sm text-cream placeholder-ochre/40 rounded-xl px-3.5 py-2.5 md:py-3 focus:outline-none focus:border-ochre/60 transition-all duration-300">
684
  <button type="submit" id="sendBtn" class="btn-primary px-3.5 md:px-4 py-2.5 md:py-3 rounded-xl text-xs flex items-center justify-center flex-shrink-0">
@@ -693,6 +669,7 @@
693
  </section>
694
 
695
  <script>
 
696
  function setVh() {
697
  const vh = window.innerHeight * 0.01;
698
  document.documentElement.style.setProperty('--vh', `${vh}px`);
@@ -701,6 +678,24 @@
701
  window.addEventListener('resize', setVh);
702
  window.addEventListener('orientationchange', () => setTimeout(setVh, 100));
703
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
704
  let currentTable = "{{ table_number }}" !== "None" && "{{ table_number }}" !== "" ? "{{ table_number }}" : null;
705
  let abortController = null;
706
  let isGenerating = false;
@@ -714,14 +709,16 @@
714
  if (currentTable && currentTable.trim() !== '') {
715
  enterChatView(currentTable, false);
716
  }
 
717
  });
718
 
719
  document.addEventListener('touchmove', function(e) {
720
- if (!e.target.closest('.scroll-area')) {
721
  e.preventDefault();
722
  }
723
  }, { passive: false });
724
 
 
725
  function switchView(targetView) {
726
  const sel = document.getElementById('view-table-selection');
727
  const chat = document.getElementById('view-chat');
@@ -741,9 +738,8 @@
741
  window.scrollTo(0, 0);
742
  const tablesScroll = sel.querySelector('.scroll-area');
743
  if (tablesScroll) tablesScroll.scrollTop = 0;
744
- const chatScroll = document.getElementById('chatMessages');
745
- if (chatScroll && targetView === 'chat') {
746
- setTimeout(() => { chatScroll.scrollTop = chatScroll.scrollHeight; }, 100);
747
  }
748
  }
749
 
@@ -768,6 +764,7 @@
768
  document.getElementById('draftOrderPanel').classList.add('hidden');
769
  }
770
 
 
771
  function renderTablesGrid() {
772
  const grid = document.getElementById('tablesGrid');
773
  grid.innerHTML = '';
@@ -800,23 +797,26 @@
800
  currentDraft = null;
801
  stopGeneration();
802
  if (currentTable) fetch(`/api/customer/stop/${currentTable}`, { method: 'POST' }).catch(() => {});
 
803
  }
804
 
805
  function appendInitialGreeting() {
806
  const container = document.getElementById('chatMessages');
807
  container.innerHTML = `
808
- <div class="flex gap-2.5 max-w-[88%]">
809
  <div class="w-7 h-7 md:w-8 md:h-8 rounded-xl bg-gradient-to-br from-turk/20 to-azure-700/20 border border-turk/30 flex items-center justify-center flex-shrink-0">
810
  <span class="text-ochre-light font-display text-[10px] md:text-[11px]">ن</span>
811
  </div>
812
- <div class="bg-bazaar-950/70 border border-ochre/20 text-cream text-xs md:text-sm rounded-2xl rounded-tr-none px-3 py-2 md:px-3.5 md:py-2.5 leading-relaxed shadow-inner-soft chat-markdown">
813
  سلام! من <strong>نیلا</strong> هستم، دستیار هوشمند کافه آی. به میزتون خوش اومدید 🌸<br>
814
  چه نوشیدنی، غذا یا شیرینی‌ای می‌پسندید؟ <em>منوی امروز</em> رو می‌تونم براتون بگم. 😊
815
  </div>
816
  </div>
817
  `;
 
818
  }
819
 
 
820
  async function sendCustomerMessage(e) {
821
  e.preventDefault();
822
  if (isGenerating) return;
@@ -867,13 +867,13 @@
867
  if (data.type === 'text') {
868
  fullText += data.content;
869
  botBubble.textContent = fullText;
870
- const chatScroll = document.getElementById('chatMessages');
871
- chatScroll.scrollTop = chatScroll.scrollHeight;
872
  } else if (data.type === 'draft') {
873
  currentDraft = data.items;
874
  showDraftPanel(currentDraft);
875
  } else if (data.type === 'error') {
876
  botBubble.textContent = '⚠️ ' + data.content;
 
877
  }
878
  } catch (parseErr) {}
879
  }
@@ -882,8 +882,7 @@
882
 
883
  botBubble.textContent = '';
884
  botBubble.innerHTML = marked.parse(fullText);
885
- const chatScroll = document.getElementById('chatMessages');
886
- chatScroll.scrollTop = chatScroll.scrollHeight;
887
 
888
  } catch (err) {
889
  if (err.name !== 'AbortError') {
@@ -928,8 +927,8 @@
928
  draftItems.innerHTML = '';
929
  items.forEach(item => {
930
  draftItems.innerHTML += `
931
- <div class="flex items-center justify-between text-[11px] md:text-xs bg-bazaar-900/70 px-2.5 py-2 rounded-lg border border-ochre/20 group">
932
- <span class="text-cream font-bold flex items-center gap-2">
933
  <span class="w-1 h-5 bg-gradient-to-b from-rug to-ochre rounded-full flex-shrink-0"></span>
934
  <span class="truncate">${escapeHtml(item.name)}</span>
935
  </span>
@@ -974,8 +973,8 @@
974
 
975
  if (role === 'user') {
976
  html = `
977
- <div class="flex justify-end gap-2 max-w-[88%] mr-auto">
978
- <div class="bg-gradient-to-br from-rug/20 to-rug-dark/30 border border-rug/30 text-cream text-xs md:text-sm rounded-2xl rounded-tl-none px-3 py-2 md:px-3.5 md:py-2.5 leading-relaxed shadow-inner-soft break-words">
979
  ${escapeHtml(content)}
980
  </div>
981
  <div class="w-7 h-7 md:w-8 md:h-8 rounded-xl bg-gradient-to-br from-ochre/30 to-rug/20 border border-ochre/40 flex items-center justify-center flex-shrink-0">
@@ -987,7 +986,7 @@
987
  `;
988
  } else {
989
  html = `
990
- <div class="flex gap-2.5 max-w-[88%]">
991
  <div class="w-7 h-7 md:w-8 md:h-8 rounded-xl bg-gradient-to-br from-turk/20 to-azure-700/20 border border-turk/30 flex items-center justify-center flex-shrink-0">
992
  <span class="text-ochre-light font-display text-[10px] md:text-[11px]">ن</span>
993
  </div>
@@ -999,7 +998,8 @@
999
  }
1000
 
1001
  container.insertAdjacentHTML('beforeend', html);
1002
- container.scrollTop = container.scrollHeight;
 
1003
  return bubbleId;
1004
  }
1005
 
@@ -1007,23 +1007,14 @@
1007
  return String(text).replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;').replace(/'/g, '&#039;');
1008
  }
1009
 
 
1010
  const chatInput = document.getElementById('chatInput');
1011
  if (chatInput) {
1012
  chatInput.addEventListener('focus', () => {
1013
- setTimeout(() => {
1014
- const chatScroll = document.getElementById('chatMessages');
1015
- if (chatScroll) chatScroll.scrollTop = chatScroll.scrollHeight;
1016
- }, 300);
1017
  });
1018
  }
1019
-
1020
- window.addEventListener('resize', () => {
1021
- setVh();
1022
- const chatScroll = document.getElementById('chatMessages');
1023
- if (chatScroll && document.getElementById('view-chat').classList.contains('view-visible')) {
1024
- setTimeout(() => { chatScroll.scrollTop = chatScroll.scrollHeight; }, 100);
1025
- }
1026
- });
1027
  </script>
1028
  </body>
1029
  </html>
 
22
  display: ['Lalezar', 'serif'],
23
  },
24
  colors: {
25
+ bazaar: { 950: '#1a0d07', 900: '#2d1810', 800: '#3d2418', 700: '#5c3a2a', 600: '#7a4e3a', 500: '#9c6b4f', 400: '#b8856a', 300: '#d4a88c' },
26
+ azure: { 950: '#051a2e', 900: '#0a2540', 800: '#123a5e', 700: '#1e4976', 600: '#2d6ca8', 500: '#3d8bc4', 400: '#6ba7d4', 300: '#a3c8e4' },
27
+ turk: { DEFAULT: '#0d9488', light: '#2dd4bf', glow: '#5eead4', deep: '#134e4a' },
28
+ rug: { DEFAULT: '#8b1e3f', light: '#c23d5f', dark: '#5a1028', glow: '#e85d7e' },
29
+ ochre: { DEFAULT: '#c9a961', light: '#e4c97a', dark: '#9c7d3a', pale: '#f0dca3' },
30
+ ivory: '#faf3e7', cream: '#f5e6d3', saffron: '#d97706',
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
31
  },
32
  boxShadow: {
33
  'carpet': '0 10px 40px -10px rgba(139, 30, 63, 0.35), 0 0 0 1px rgba(201, 169, 97, 0.15)',
 
43
  'fade-in': 'fadeIn 0.35s ease-out',
44
  },
45
  keyframes: {
46
+ float: { '0%, 100%': { transform: 'translateY(0px)' }, '50%': { transform: 'translateY(-12px)' } },
47
+ shimmer: { '0%, 100%': { opacity: '0.7' }, '50%': { opacity: '1' } },
48
+ pulseGlow: { '0%, 100%': { boxShadow: '0 0 20px rgba(201, 169, 97, 0.3)' }, '50%': { boxShadow: '0 0 40px rgba(201, 169, 97, 0.6)' } },
49
+ fadeIn: { '0%': { opacity: '0', transform: 'translateY(8px)' }, '100%': { opacity: '1', transform: 'translateY(0)' } },
 
 
 
 
 
 
 
 
 
 
 
 
50
  },
51
  }
52
  }
 
56
  <style>
57
  :root {
58
  --pattern-url: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='80' height='80' viewBox='0 0 80 80'%3E%3Cg fill='none' stroke='%23c9a961' stroke-width='0.6' opacity='0.08'%3E%3Cpath d='M40 10 L50 20 L60 10 L70 20 L60 30 L70 40 L60 50 L70 60 L60 70 L50 60 L40 70 L30 60 L20 70 L10 60 L20 50 L10 40 L20 30 L10 20 L20 10 L30 20 Z'/%3E%3Ccircle cx='40' cy='40' r='12'/%3E%3Ccircle cx='40' cy='40' r='6'/%3E%3Cpath d='M40 28 L40 52 M28 40 L52 40'/%3E%3C/g%3E%3C/svg%3E");
59
+ --vh: 1vh;
60
  }
61
 
62
  * { box-sizing: border-box; }
63
 
64
+ html, body {
 
65
  height: 100%;
66
  overflow: hidden;
 
 
 
67
  overscroll-behavior: none;
68
  -webkit-overflow-scrolling: touch;
69
  }
70
 
71
+ @supports (height: 100dvh) {
72
+ html, body { height: 100dvh; }
73
+ }
74
+
75
  body {
76
  background-color: #1a0d07;
77
  color: #f5e6d3;
 
79
  font-feature-settings: "ss01", "cv01";
80
  margin: 0;
81
  padding: 0;
 
 
82
  overflow: hidden;
 
 
83
  }
84
 
85
+ .bg-pattern { background-image: var(--pattern-url); background-size: 80px 80px; }
 
 
 
86
 
87
  .bg-pattern-fine {
88
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='40' height='40' viewBox='0 0 40 40'%3E%3Cg fill='none' stroke='%23c9a961' stroke-width='0.4' opacity='0.1'%3E%3Cpath d='M20 0 L20 40 M0 20 L40 20'/%3E%3Ccircle cx='20' cy='20' r='3'/%3E%3Ccircle cx='0' cy='0' r='2'/%3E%3Ccircle cx='40' cy='0' r='2'/%3E%3Ccircle cx='0' cy='40' r='2'/%3E%3Ccircle cx='40' cy='40' r='2'/%3E%3C/g%3E%3C/svg%3E");
 
99
  background: linear-gradient(180deg, #c9a961, #8b1e3f);
100
  border-radius: 4px;
101
  }
102
+ ::-webkit-scrollbar-thumb:hover { background: linear-gradient(180deg, #e4c97a, #c23d5f); }
103
 
104
  .glass-card {
105
  background: linear-gradient(135deg, rgba(45, 24, 16, 0.82) 0%, rgba(26, 13, 7, 0.78) 100%);
 
163
  .chat-markdown > * + * { margin-top: 0.6em; }
164
  .chat-markdown h1, .chat-markdown h2, .chat-markdown h3,
165
  .chat-markdown h4, .chat-markdown h5, .chat-markdown h6 {
166
+ font-family: 'Lalezar', serif; color: #e4c97a;
167
+ margin-top: 1em; margin-bottom: 0.4em; line-height: 1.3;
 
 
 
168
  }
169
  .chat-markdown h1 { font-size: 1.4em; }
170
  .chat-markdown h2 { font-size: 1.25em; }
 
180
  .chat-markdown em { color: #5eead4; font-style: italic; }
181
  .chat-markdown a { color: #2dd4bf; text-decoration: underline; text-underline-offset: 3px; }
182
  .chat-markdown code {
183
+ background: rgba(13, 148, 136, 0.18); color: #5eead4;
184
+ padding: 0.15em 0.4em; border-radius: 5px; font-size: 0.88em;
 
 
 
185
  border: 1px solid rgba(45, 212, 191, 0.2);
186
  font-family: 'Courier New', monospace;
187
+ direction: ltr; display: inline-block;
 
188
  }
189
  .chat-markdown pre {
190
  background: rgba(5, 26, 46, 0.7);
191
  border: 1px solid rgba(45, 212, 191, 0.25);
192
  border-right: 3px solid #0d9488;
193
+ padding: 0.9em 1em; border-radius: 8px;
194
+ overflow-x: auto; margin: 0.6em 0;
195
+ direction: ltr; text-align: left;
 
 
 
196
  }
197
  .chat-markdown pre code { background: transparent; border: none; padding: 0; color: #a3c8e4; font-size: 0.85em; }
198
  .chat-markdown blockquote {
199
  border-right: 3px solid #c9a961;
200
  background: linear-gradient(90deg, rgba(201, 169, 97, 0.08), transparent);
201
+ padding: 0.5em 1em; margin: 0.6em 0;
202
+ color: #f0dca3; font-style: italic;
 
 
203
  border-radius: 0 8px 8px 0;
204
  }
205
  .chat-markdown blockquote p { margin: 0; }
206
  .chat-markdown hr {
207
+ border: none; height: 1px;
 
208
  background: linear-gradient(90deg, transparent, rgba(201, 169, 97, 0.5), transparent);
209
  margin: 1em 0;
210
  }
211
  .chat-markdown table {
212
+ width: 100%; border-collapse: collapse; margin: 0.6em 0;
213
+ font-size: 0.92em; background: rgba(45, 24, 16, 0.5);
214
+ border-radius: 8px; overflow: hidden;
 
 
 
 
215
  border: 1px solid rgba(201, 169, 97, 0.25);
216
+ display: block; overflow-x: auto;
 
217
  }
218
  .chat-markdown thead { background: linear-gradient(90deg, rgba(139, 30, 63, 0.4), rgba(201, 169, 97, 0.2)); }
219
  .chat-markdown th {
220
+ padding: 0.55em 0.8em; text-align: right;
221
+ color: #e4c97a; font-weight: 700;
 
 
222
  border-bottom: 1px solid rgba(201, 169, 97, 0.3);
223
  font-family: 'Lalezar', serif;
224
  }
 
231
 
232
  .btn-primary {
233
  background: linear-gradient(135deg, #c9a961 0%, #9c7d3a 100%);
234
+ color: #1a0d07; font-weight: 800;
 
235
  transition: all 0.3s ease;
236
  box-shadow: 0 8px 20px -5px rgba(201, 169, 97, 0.4);
237
  }
 
242
  }
243
  .btn-primary:disabled { opacity: 0.5; cursor: not-allowed; transform: none; }
244
 
 
 
 
 
 
 
 
245
  .typing-dots span {
246
+ display: inline-block; width: 6px; height: 6px;
247
+ border-radius: 50%; background: #c9a961;
 
 
 
248
  animation: typing 1.4s infinite;
249
  }
250
  .typing-dots span:nth-child(2) { animation-delay: 0.2s; }
 
283
 
284
  button, .no-select { -webkit-user-select: none; user-select: none; }
285
 
286
+ /* ============ FOOTER ============ */
 
287
  .app-footer {
288
  flex-shrink: 0;
289
  position: relative;
 
294
  border-top: 1px solid rgba(201, 169, 97, 0.15);
295
  }
296
 
297
+ /* ============ CHAT COLUMN - KEY FIX ============ */
298
+ .chat-column {
299
+ display: flex;
300
+ flex-direction: column;
301
+ min-height: 0;
302
+ overflow: hidden;
303
+ }
304
+
305
+ .chat-messages-container {
306
+ flex: 1;
307
+ min-height: 0;
308
+ overflow-y: auto;
309
+ overflow-x: hidden;
310
+ overscroll-behavior: contain;
311
+ -webkit-overflow-scrolling: touch;
312
+ }
313
+
314
+ .chat-header-box,
315
+ .chat-loader-box,
316
+ .chat-input-box {
317
+ flex-shrink: 0;
318
+ }
319
+
320
+ /* ============ RESPONSIVE HEIGHTS ============ */
321
+
322
+ /* Mobile (< 640px) */
323
  @media (max-width: 639px) {
324
  .hero-title { font-size: 2.5rem !important; }
325
  .hero-logo { width: 70px !important; height: 70px !important; }
326
  .tables-grid { grid-template-columns: repeat(4, 1fr) !important; gap: 0.5rem !important; }
327
  .table-btn span { font-size: 1.5rem !important; }
328
  .info-cards { grid-template-columns: 1fr !important; }
329
+ .chat-column {
330
+ height: 65vh;
331
+ height: calc(var(--vh, 1vh) * 65);
332
+ min-height: 380px;
333
+ max-height: 550px;
334
+ flex-shrink: 0;
335
+ }
336
+ .chat-input-area {
337
+ padding-bottom: calc(0.75rem + env(safe-area-inset-bottom)) !important;
338
+ }
339
  }
340
 
341
+ /* Tablet (640px - 1023px) */
342
  @media (min-width: 640px) and (max-width: 1023px) {
343
  .hero-title { font-size: 3.5rem !important; }
344
  .hero-logo { width: 90px !important; height: 90px !important; }
345
  .tables-grid { grid-template-columns: repeat(5, 1fr) !important; }
346
  .info-cards { grid-template-columns: repeat(2, 1fr) !important; }
347
+ .chat-column {
348
+ height: 70vh;
349
+ height: calc(var(--vh, 1vh) * 70);
350
+ min-height: 420px;
351
+ max-height: 620px;
352
+ flex-shrink: 0;
353
+ }
354
  }
355
 
356
+ /* Desktop (>= 1024px) - چت کل ارتفاع را می‌گیرد */
357
  @media (min-width: 1024px) {
358
  .hero-title { font-size: 4.5rem !important; }
359
  .hero-logo { width: 100px !important; height: 100px !important; }
360
  .tables-grid { grid-template-columns: repeat(10, 1fr) !important; }
361
  .info-cards { grid-template-columns: repeat(3, 1fr) !important; }
362
+ .chat-column {
363
+ height: 100%;
364
+ max-height: 100%;
365
+ }
366
  }
367
 
368
+ /* Landscape mobile */
369
  @media (max-height: 500px) and (orientation: landscape) {
370
  .hero-title { font-size: 2rem !important; }
371
  .hero-logo { width: 50px !important; height: 50px !important; }
372
  .hero-header { padding-top: 0.5rem !important; padding-bottom: 0.25rem !important; }
373
+ .chat-column {
374
+ height: 75vh !important;
375
+ min-height: 280px !important;
376
+ }
377
  }
378
 
379
+ /* Small mobile */
380
  @media (max-width: 380px) {
381
  .tables-grid { grid-template-columns: repeat(4, 1fr) !important; }
382
  .table-btn { padding: 0.375rem !important; }
383
  .table-btn span { font-size: 1.25rem !important; }
384
  .hero-title { font-size: 2rem !important; }
385
+ .chat-column {
386
+ height: 60vh;
387
+ height: calc(var(--vh, 1vh) * 60);
388
+ min-height: 340px;
389
+ max-height: 500px;
390
+ }
391
  }
392
 
393
  @supports (padding-bottom: env(safe-area-inset-bottom)) {
 
401
  <!-- ============ VIEW 1: TABLE SELECTION ============ -->
402
  <section id="view-table-selection" class="view-container view-visible">
403
 
 
404
  <div class="absolute inset-0 overflow-hidden pointer-events-none z-0">
405
  <div class="absolute inset-0 bg-gradient-to-br from-bazaar-950 via-bazaar-900 to-azure-950"></div>
406
  <div class="absolute inset-0 bg-pattern opacity-40"></div>
 
409
  <div class="absolute top-1/3 left-1/4 w-[400px] h-[400px] rounded-full bg-ochre/8 blur-[120px] animate-shimmer"></div>
410
  </div>
411
 
 
412
  <div class="scroll-area flex-1 min-h-0 relative z-10">
413
 
 
414
  <header class="hero-header px-4 pt-6 pb-3 md:pt-10 md:pb-4 text-center relative flex-shrink-0">
415
  <div class="max-w-4xl mx-auto">
416
  <div class="inline-flex items-center gap-4 mb-4 animate-float">
 
440
  </div>
441
  </header>
442
 
 
443
  <main class="px-4 md:px-8 pb-8 relative">
444
  <div class="max-w-5xl mx-auto">
445
 
 
479
  </div>
480
  </div>
481
 
 
482
  <div class="info-cards grid grid-cols-1 md:grid-cols-3 gap-3 mb-6">
483
  <div class="glass-card rounded-2xl p-4 relative overflow-hidden group">
484
  <div class="absolute top-0 right-0 w-20 h-20 bg-rug/15 rounded-full blur-2xl group-hover:bg-rug/25 transition-all"></div>
 
523
  </main>
524
  </div>
525
 
 
526
  <footer class="app-footer py-3 text-center text-[10px] text-cream/40 safe-top safe-bottom">
527
  طراحی و توسعه توسط الگوریتم داده نسترن | با الهام از فرهنگ تبریز © ۲۰۲۶
528
  </footer>
529
  </section>
530
 
531
 
532
+ <!-- ============ VIEW 2: CHAT ============ -->
533
  <section id="view-chat" class="view-container view-hidden">
534
 
 
535
  <div class="absolute inset-0 overflow-hidden pointer-events-none z-0">
536
  <div class="absolute inset-0 bg-gradient-to-br from-bazaar-950 via-bazaar-900 to-azure-950"></div>
537
  <div class="absolute inset-0 bg-pattern opacity-30"></div>
 
571
  <span class="text-[10px] text-cream/60">میز</span>
572
  <span id="tableNumberDisplay" class="text-base md:text-lg font-display text-ochre-light table-number-glow">---</span>
573
  </div>
574
+ <button onclick="backToTables()" class="p-1.5 text-turk/60 hover:text-ochre-light transition-colors rounded-lg hover:bg-bazaar-800/50" title="تغییر میز">
575
+ <svg class="w-4 h-4" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
576
+ <path stroke-linecap="round" stroke-linejoin="round" d="M15.232 5.232l3.536 3.536m-2.036-5.036a2.5 2.5 0 113.536 3.536L6.5 21.036H3v-3.572L16.732 3.732z"/>
577
+ </svg>
578
+ </button>
579
  </div>
580
  </div>
581
  </header>
582
 
583
+ <!-- Main content with controlled height -->
584
  <main class="flex-1 flex flex-col min-h-0 p-2.5 md:p-4 lg:p-6 z-10 relative gap-3 overflow-hidden">
585
  <div class="max-w-5xl w-full mx-auto flex-1 flex flex-col min-h-0 gap-3">
586
 
 
607
  </div>
608
  </div>
609
 
610
+ <!-- Chat column (fixed height controlled by CSS) -->
611
+ <div class="chat-column glass-card-azure rounded-2xl md:rounded-3xl shadow-xl relative">
612
  <div class="absolute inset-0 bg-arch opacity-20 pointer-events-none"></div>
613
 
614
+ <!-- Chat header (flex-shrink-0) -->
615
+ <div class="chat-header-box relative px-3.5 md:px-5 py-2.5 md:py-3 border-b border-turk/25 flex items-center gap-2.5 bg-gradient-to-l from-azure-950/60 to-azure-900/40">
616
  <div class="w-9 h-9 md:w-10 md:h-10 rounded-xl bg-gradient-to-br from-turk/30 to-azure-700/30 border border-turk/40 flex items-center justify-center shadow-mosque flex-shrink-0">
617
  <svg class="w-5 h-5 md:w-6 md:h-6 text-turk-glow" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8">
618
  <circle cx="12" cy="8" r="4"/>
 
620
  <path d="M9 10l2 2 4-4" stroke-linecap="round" stroke-linejoin="round" opacity="0.7"/>
621
  </svg>
622
  </div>
623
+ <div class="min-w-0 flex-1">
624
  <h3 class="text-xs md:text-sm font-display text-ochre-light tracking-wide">نیلا، دستیار کافه</h3>
625
  <p class="text-[9px] md:text-[10px] text-turk-light/80 font-medium flex items-center gap-1.5">
626
  <span class="w-1.5 h-1.5 rounded-full bg-turk-light animate-pulse"></span>
 
629
  </div>
630
  </div>
631
 
632
+ <!-- Chat messages (SCROLLABLE - key fix) -->
633
+ <div id="chatMessages" class="chat-messages-container p-3 md:p-4 space-y-3 relative">
634
+ <div class="flex gap-2 md:gap-2.5 max-w-[88%]">
635
  <div class="w-7 h-7 md:w-8 md:h-8 rounded-xl bg-gradient-to-br from-turk/20 to-azure-700/20 border border-turk/30 flex items-center justify-center flex-shrink-0">
636
  <span class="text-ochre-light font-display text-[10px] md:text-[11px]">ن</span>
637
  </div>
638
+ <div class="bg-bazaar-950/70 border border-ochre/20 text-cream text-xs md:text-sm rounded-2xl rounded-tr-none px-3 py-2 md:px-3.5 md:py-2.5 leading-relaxed shadow-inner-soft chat-markdown break-words" style="flex: 1; max-width: calc(100% - 2.5rem);">
639
  سلام! من <strong>نیلا</strong> هستم، دستیار هوشمند کافه آی. به میزتون خوش اومدید 🌸<br>
640
  چه نوشیدنی، غذا یا شیرینی‌ای می‌پسندید؟ <em>منوی امروز</em> رو می‌تونم براتون بگم. 😊
641
  </div>
642
  </div>
643
  </div>
644
 
645
+ <!-- Chat loader (flex-shrink-0) -->
646
+ <div id="chatLoader" class="chat-loader-box hidden relative px-3 py-2 md:px-4 md:py-2.5 flex items-center justify-between bg-azure-950/70 text-[9px] md:text-[10px] text-turk-light font-semibold border-t border-turk/20">
647
  <div class="flex items-center gap-2">
648
  <div class="typing-dots flex gap-1">
649
  <span></span><span></span><span></span>
 
653
  <button onclick="stopGeneration()" class="px-2.5 py-1 md:px-3 md:py-1.5 bg-rug-dark/40 border border-rug/40 hover:bg-rug/40 rounded-lg text-[9px] md:text-[10px] text-rug-light font-bold transition-all">توقف</button>
654
  </div>
655
 
656
+ <!-- Chat input (flex-shrink-0) -->
657
+ <form id="chatForm" onsubmit="sendCustomerMessage(event)" class="chat-input-box relative p-2 md:p-3 border-t border-turk/20 bg-bazaar-950/60 flex gap-2 chat-input-area safe-bottom">
658
  <input type="text" id="chatInput" placeholder="پیام خود را بنویسید..." autocomplete="off"
659
  class="flex-1 min-w-0 bg-azure-950/60 border border-azure-700/40 text-xs md:text-sm text-cream placeholder-ochre/40 rounded-xl px-3.5 py-2.5 md:py-3 focus:outline-none focus:border-ochre/60 transition-all duration-300">
660
  <button type="submit" id="sendBtn" class="btn-primary px-3.5 md:px-4 py-2.5 md:py-3 rounded-xl text-xs flex items-center justify-center flex-shrink-0">
 
669
  </section>
670
 
671
  <script>
672
+ // ============ VIEWPORT HEIGHT FIX ============
673
  function setVh() {
674
  const vh = window.innerHeight * 0.01;
675
  document.documentElement.style.setProperty('--vh', `${vh}px`);
 
678
  window.addEventListener('resize', setVh);
679
  window.addEventListener('orientationchange', () => setTimeout(setVh, 100));
680
 
681
+ // ============ AUTO SCROLL HELPER ============
682
+ function scrollChatToBottom(smooth = true) {
683
+ const chatScroll = document.getElementById('chatMessages');
684
+ if (chatScroll) {
685
+ if (smooth) {
686
+ chatScroll.scrollTo({ top: chatScroll.scrollHeight, behavior: 'smooth' });
687
+ } else {
688
+ chatScroll.scrollTop = chatScroll.scrollHeight;
689
+ }
690
+ }
691
+ }
692
+
693
+ window.addEventListener('resize', () => {
694
+ setVh();
695
+ setTimeout(scrollChatToBottom, 150);
696
+ });
697
+
698
+ // ============ CONFIG ============
699
  let currentTable = "{{ table_number }}" !== "None" && "{{ table_number }}" !== "" ? "{{ table_number }}" : null;
700
  let abortController = null;
701
  let isGenerating = false;
 
709
  if (currentTable && currentTable.trim() !== '') {
710
  enterChatView(currentTable, false);
711
  }
712
+ setTimeout(scrollChatToBottom, 100);
713
  });
714
 
715
  document.addEventListener('touchmove', function(e) {
716
+ if (!e.target.closest('.scroll-area') && !e.target.closest('.chat-messages-container')) {
717
  e.preventDefault();
718
  }
719
  }, { passive: false });
720
 
721
+ // ============ VIEW MANAGEMENT ============
722
  function switchView(targetView) {
723
  const sel = document.getElementById('view-table-selection');
724
  const chat = document.getElementById('view-chat');
 
738
  window.scrollTo(0, 0);
739
  const tablesScroll = sel.querySelector('.scroll-area');
740
  if (tablesScroll) tablesScroll.scrollTop = 0;
741
+ if (targetView === 'chat') {
742
+ setTimeout(scrollChatToBottom, 100);
 
743
  }
744
  }
745
 
 
764
  document.getElementById('draftOrderPanel').classList.add('hidden');
765
  }
766
 
767
+ // ============ TABLES GRID ============
768
  function renderTablesGrid() {
769
  const grid = document.getElementById('tablesGrid');
770
  grid.innerHTML = '';
 
797
  currentDraft = null;
798
  stopGeneration();
799
  if (currentTable) fetch(`/api/customer/stop/${currentTable}`, { method: 'POST' }).catch(() => {});
800
+ setTimeout(scrollChatToBottom, 100);
801
  }
802
 
803
  function appendInitialGreeting() {
804
  const container = document.getElementById('chatMessages');
805
  container.innerHTML = `
806
+ <div class="flex gap-2 md:gap-2.5 max-w-[88%]">
807
  <div class="w-7 h-7 md:w-8 md:h-8 rounded-xl bg-gradient-to-br from-turk/20 to-azure-700/20 border border-turk/30 flex items-center justify-center flex-shrink-0">
808
  <span class="text-ochre-light font-display text-[10px] md:text-[11px]">ن</span>
809
  </div>
810
+ <div class="bg-bazaar-950/70 border border-ochre/20 text-cream text-xs md:text-sm rounded-2xl rounded-tr-none px-3 py-2 md:px-3.5 md:py-2.5 leading-relaxed shadow-inner-soft chat-markdown break-words" style="flex: 1; max-width: calc(100% - 2.5rem);">
811
  سلام! من <strong>نیلا</strong> هستم، دستیار هوشمند کافه آی. به میزتون خوش اومدید 🌸<br>
812
  چه نوشیدنی، غذا یا شیرینی‌ای می‌پسندید؟ <em>منوی امروز</em> رو می‌تونم براتون بگم. 😊
813
  </div>
814
  </div>
815
  `;
816
+ setTimeout(scrollChatToBottom, 50);
817
  }
818
 
819
+ // ============ CHAT FUNCTIONS ============
820
  async function sendCustomerMessage(e) {
821
  e.preventDefault();
822
  if (isGenerating) return;
 
867
  if (data.type === 'text') {
868
  fullText += data.content;
869
  botBubble.textContent = fullText;
870
+ scrollChatToBottom(false);
 
871
  } else if (data.type === 'draft') {
872
  currentDraft = data.items;
873
  showDraftPanel(currentDraft);
874
  } else if (data.type === 'error') {
875
  botBubble.textContent = '⚠️ ' + data.content;
876
+ scrollChatToBottom(false);
877
  }
878
  } catch (parseErr) {}
879
  }
 
882
 
883
  botBubble.textContent = '';
884
  botBubble.innerHTML = marked.parse(fullText);
885
+ scrollChatToBottom(true);
 
886
 
887
  } catch (err) {
888
  if (err.name !== 'AbortError') {
 
927
  draftItems.innerHTML = '';
928
  items.forEach(item => {
929
  draftItems.innerHTML += `
930
+ <div class="flex items-center justify-between text-[11px] md:text-xs bg-bazaar-900/70 px-2.5 py-2 rounded-lg border border-ochre/20">
931
+ <span class="text-cream font-bold flex items-center gap-2 min-w-0">
932
  <span class="w-1 h-5 bg-gradient-to-b from-rug to-ochre rounded-full flex-shrink-0"></span>
933
  <span class="truncate">${escapeHtml(item.name)}</span>
934
  </span>
 
973
 
974
  if (role === 'user') {
975
  html = `
976
+ <div class="flex justify-end gap-2 md:gap-2.5 max-w-[88%] mr-auto">
977
+ <div class="bg-gradient-to-br from-rug/20 to-rug-dark/30 border border-rug/30 text-cream text-xs md:text-sm rounded-2xl rounded-tl-none px-3 py-2 md:px-3.5 md:py-2.5 leading-relaxed shadow-inner-soft break-words" style="flex: 1; max-width: calc(100% - 2.5rem);">
978
  ${escapeHtml(content)}
979
  </div>
980
  <div class="w-7 h-7 md:w-8 md:h-8 rounded-xl bg-gradient-to-br from-ochre/30 to-rug/20 border border-ochre/40 flex items-center justify-center flex-shrink-0">
 
986
  `;
987
  } else {
988
  html = `
989
+ <div class="flex gap-2 md:gap-2.5 max-w-[88%]">
990
  <div class="w-7 h-7 md:w-8 md:h-8 rounded-xl bg-gradient-to-br from-turk/20 to-azure-700/20 border border-turk/30 flex items-center justify-center flex-shrink-0">
991
  <span class="text-ochre-light font-display text-[10px] md:text-[11px]">ن</span>
992
  </div>
 
998
  }
999
 
1000
  container.insertAdjacentHTML('beforeend', html);
1001
+ // Always scroll to bottom after adding message
1002
+ scrollChatToBottom(true);
1003
  return bubbleId;
1004
  }
1005
 
 
1007
  return String(text).replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;').replace(/'/g, '&#039;');
1008
  }
1009
 
1010
+ // Mobile keyboard handling
1011
  const chatInput = document.getElementById('chatInput');
1012
  if (chatInput) {
1013
  chatInput.addEventListener('focus', () => {
1014
+ setTimeout(scrollChatToBottom, 300);
1015
+ setTimeout(scrollChatToBottom, 600);
 
 
1016
  });
1017
  }
 
 
 
 
 
 
 
 
1018
  </script>
1019
  </body>
1020
  </html>