Tiệm Trà Mơ Ước là game mô phỏng quán trà sữa Việt chơi trên điện thoại: buổi sáng nhập hàng và đặt giá, từ 11:00 đến 22:00 tự tay pha cho từng khách, cuối ngày xem sổ rồi nâng cấp quán. Giao diện trông như một quầy trà vẽ tay: mái hiên sọc hồng trắng, bảng phấn xanh, quầy gỗ, nền kem sữa, chữ tròn Baloo 2 và nút nổi như đồ chơi gỗ. Hệ thống này dùng để dựng lại game hoặc làm màn mới mà vẫn ra đúng cái tiệm đó. Các minigame chưa dựng thành component nằm trong `docs/minigames-todo.md`. ## Giọng văn - Gọi người chơi là "bạn". Lời nhắn của dev xưng "mình", linh vật xưng "tớ", khách nói kiểu đời thường: "Cho mình 1 ly trà sữa size L nha". - Câu ngắn, nói thẳng điều vừa xảy ra hoặc việc cần làm: "Đã đổi tên quán", "Két không đủ tiền", "Đã nấu xong, sẵn sàng mở cửa". - Lỗi nói rõ lý do và cách gỡ: "Đang nợ, trả xong mới nâng cấp được", "Không đủ tiền, bớt số lượng lại nhé". - Viết hoa chữ đầu câu và tên riêng (Tiệm Trà Mơ Ước, Thần Mèo Karin, Tà Tưa Bank). Tên địa điểm trên nút viết hoa từng chữ: "Vào Quầy", "Xuống Phố". Nút còn lại là động từ + đối tượng: "Mở cửa ngày 2", "Nộp thuế", "Nhập 10". - Tiền luôn qua `TTMU.formatMoney`: 950đ, 25k, 237,5k, 1,25tr, −5k (dấu phẩy thập phân, dấu trừ "−"). Giờ 24h "11:10", ngày "Ngày 2". Sao ★☆ luôn đi kèm điểm bằng chữ: "4,6 · 23 đánh giá". - Emoji là một phần nhãn ở đúng những chỗ game dùng: 🧋 Vào Quầy, 📣 Xin Phước, 🛵 3 xe, 🏮 biển tên, 🔒 chưa mở. Icon chức năng dùng PNG nhóm Icons. Không rải emoji để trang trí. ## Màu - Năm theme. Bốn theme lấy từ game: `kem` Kem sữa (mặc định), `nau` Nâu cà phê, `socola` Sô cô la, `dem` Đêm dịu. Theme thứ năm `hc` Tương phản cao là theme do design system thêm vào, đạt ngưỡng tương phản AAA cho chữ (SC 1.4.6) và 3:1 cho viền, focus, đồ hoạ (SC 1.4.11) trên các preview, kể cả các trạng thái mở bằng JS có `data-audit-click`; đây không phải theme của game gốc. Đổi bằng `data-theme` trên `` hoặc `TTMU.setTheme(id)`. Token chia ba nhóm theo cách chúng đổi theo theme: - Đổi ở cả năm theme: `bg`, `panel`, `line`, `fill-muted` (bằng `line` ở bốn theme gốc), `ink`, `soft`, `pink`, `pink-d`, `focus-ring`, `art-tint` và ba bóng `shadow-press`, `shadow-press-down`, `shadow-ring-pink`. - Bốn theme gốc giữ giá trị của game, riêng `hc` có giá trị khác: màu đậm hơn hoặc sáng hơn cho `mint`, `warn`, `gold`, `gold-lit`, `link`, `fresh-1-ink`, `fresh-3-ink`, `toast-alert`, `street`, `street-hi`, `street-line`, `coach`, `coach-d`, `want`, `target`, `patience`, `pour-low`, `pour-high`, `stage-soft`, `stage-muted`, `stage-accent`, `stage-track`, `stage-fill`, `stage-pink`, `stage-pink-d`, `bin-label-bg`, `fill-tabs`, `toast-success`, `toast-warn`, `toast-info`, `toast-reward`, `timer-ok`, `timer-soon`, `timer-overdue`, `urgent-title`; độ đục `alpha-tab-idle`, `alpha-chalk-group`, `alpha-chalk-sub`, `alpha-chalk-extra`, `alpha-ledger-zero`, `alpha-empty-hint`, `alpha-sign-hint`, `alpha-veil`, `alpha-splash-version` (ở bốn theme gốc là số hiện có của game, ở `hc` thường là 1); bóng `shadow-coach`, `shadow-want`, `shadow-pick` đổi màu theo token tương ứng, còn `shadow-tab-on`, `shadow-edge`, `shadow-edge-top`, `shadow-edge-bottom`, `shadow-on`, `shadow-fill-edge` là `none` ở bốn theme gốc và chỉ có hình ở `hc`. - Cố định ở cả năm theme: `on-pink` và `on-fill` (trắng), `counter`, `counter-top`, `chalk`, `chalk-ink`, `sign-paper`, `sign-ink`, `awning-white`, `fresh-1-bg`, `fresh-3-bg`, `scrim`, `stage-ground`, `stage-paper`, `stage-ink`, `outline`, `outline-soft`, `wood-dark`, `bin-badge`, `pour-mid`, `urgent-bg`, `urgent-sub`, `urgent-bar-from`, `urgent-bar-to`, `shadow-sign`, `shadow-board`, `shadow-modal`, `shadow-toast`, `shadow-street`. - `fill-muted` là nền trung tính cho rãnh thanh tiến độ, badge muted, dải tab, ô số: những chỗ trước đây lấy `line` làm nền. Ở bốn theme gốc nó bằng `line` (không đổi màu nào của game); ở `hc` là `#eee5db`, tách khỏi `line` vì `line` ở `hc` là viền đậm (5.55:1 trên `panel`) không hợp làm nền cho chữ. Viết CSS mới thì dùng `fill-muted` cho nền, `line` cho viền. - Trang dùng `bg`, khối nổi (pane, card, modal, thẻ khách) dùng `panel`. Control đặt trên `panel` lấy nền `bg` (ô nhập, nút nhỏ, ô KPI): `line` trên `panel` chỉ 1.35:1, nên phải đổi nền thì control mới tách khỏi card. - Chữ nội dung dùng `ink`, nhãn và metadata dùng `soft`. `ink` đạt từ 9.49:1 và `soft` từ 5.52:1 trên `bg` và `panel` ở mọi theme. - `pink` dành cho một hành động chính mỗi màn (Mở cửa, Nộp thuế) và lựa chọn đang bật. `pink-d` là cạnh 3D dưới nút chính và chữ nhấn (tên quán trên HUD, từ khoá món trong lời khách, tên khách đơn online). Game giữ `pink-d` cho chữ nhấn ở mọi theme (Đêm dịu 2.93:1); muốn đạt chuẩn thì ghi đè bằng `pink`. - Trạng thái: `mint` là tốt, đủ, đúng món; `warn` là thiếu, lỗ, nguy hiểm; `gold` là sao, mục tiêu, sự kiện trong ngày. Luôn kèm chữ hoặc icon ✓ ⚠, vì `mint` và `gold` không đủ tương phản để đứng một mình. - Đồ vật trong tiệm có màu riêng, không dùng làm màu UI chung: `counter` và `counter-top` (quầy gỗ, khung bảng phấn), `chalk` và `chalk-ink` (bảng phấn), `sign-paper` và `sign-ink` (biển tên), `pink` xen `awning-white` (mái hiên). - Tranh vẽ có bảng màu riêng: `stage-*`, `outline`, `outline-soft`, `wood-dark`, `bin-badge`, `bin-label-bg`, `patience`, `pour-low`, `pour-mid`, `pour-high`, `target`, `want` chỉ dùng trên sân khấu quầy pha và splash. Ảnh tranh (`assets/`) không đổi theo theme, nhưng ở `hc` màu dựng bằng CSS trên sân khấu đổi để chữ và đồ hoạ đạt chuẩn: `stage-soft`, `stage-muted`, `stage-accent`, `stage-track`, `stage-fill`, `stage-pink`, `stage-pink-d`, `patience`, `target`, `want`, `pour-low`, `pour-high`, nền `bin-label-bg` dưới nhãn FOAM MATCHA, và lớp phủ Hết đục hẳn (`alpha-veil`); phủ `art-tint` qua `.tt-stage__tint` để hoà với theme. - Màu một việc: `street` và `street-hi` cho nút Xuống Phố, `coach` cho hướng dẫn chơi, `link` cho phản hồi của chủ quán, `toast-alert` cho thông báo phạt, `scrim` cho nền sau modal. - Token thêm cho thông báo và cảnh báo (nền đậm hơn màu trạng thái để chữ `on-fill` đạt AA ở bốn theme gốc, trừ `timer-soon` chỉ 3.19:1 vì giữ đúng màu cam của game: trạng thái "sắp hết" do chữ "Sắp hết" và icon ⚠ mang, không dựa vào màu; `hc` đậm hơn, đạt AAA): `toast-success`, `toast-warn`, `toast-info`, `toast-reward` (nền các tone của Toast), `timer-ok`, `timer-soon`, `timer-overdue` (ba mức của Countdown), `urgent-bg`, `urgent-title`, `urgent-sub`, `urgent-bar-from`, `urgent-bar-to` (UrgentAlert). Không có trong game gốc dưới dạng token: là bổ sung của design system, ghi nguồn trong README từng component. ## Chữ - Một họ chữ: Baloo 2 (Google Fonts, weight 500/600/700/800), đủ dấu tiếng Việt. Không dùng weight 400 vì game không tải. - Thứ bậc bằng độ đậm: 800 cho tiêu đề, tiền két, nút chính, nhãn trên tranh; 700 cho tên món, nút, tab; 500 cho văn bản và ghi chú. - Thang chữ giao diện tính bằng rem: `display` 2rem → `title` 1.45rem → `board-title` 1.35rem → `money` 1.3rem → `section`/`item-name` 1rem → `body` .92rem → `note` .82rem → `sub`/`button-sm` .78rem → `label` .72rem → `badge` .7rem → `micro` .66rem. `button-lg` 1.1rem cho nút chính, `stat` 2.4rem cho điểm đánh giá lớn. - Thang sân khấu tính bằng px trên khung 768: `stage-title` 72px, `stage-say` 24px, `stage-tag` 19px, `stage-badge` 16px; sân khấu được scale nên chữ vẫn vừa màn. - Tiền, số lượng, giờ và cột sổ sách dùng `.tt-num` (tabular-nums). ## Bố cục và khoảng cách - Thiết kế cho điện thoại dọc: một cột tối đa 560px ở giữa màn. Màn chuẩn bị xếp từ trên xuống: HUD, mái hiên, biển tên, bảng phấn, dải tab, pane, thanh Mở cửa cố định ở đáy. - Lề ngang 12px (`space-12`) cho bảng phấn, dải tab và pane. Pane chừa `space-openbar` (90px) phía dưới để thanh Mở cửa không che nội dung. - Khe trong nhóm nút `space-4`, giữa các ô `space-6`, giữa các khối `space-8` đến `space-12`. Giá trị lẻ của nguồn (5px, 7px, 9px) được giữ nguyên. - Quầy pha và splash là sân khấu 768×1376 vẽ theo toạ độ tranh, scale bằng `TTMU.fitStage`; vùng chạm là nút trong suốt đặt khớp vật trong tranh. - Thanh cố định trên cùng cộng `env(safe-area-inset-top)`, thanh dưới cùng cộng `env(safe-area-inset-bottom)`. ## Viền, bo góc, bóng - Viền 2px `line` cho hầu hết control và card; 3px `counter` cho biển tên; 8px `counter` cho khung bảng phấn; viền đứt `line` cho ô trống. - Bo góc tăng theo cỡ vật: `radius-6` tag → `radius-10` nút nhỏ, chip, ô nhập → `radius-12` nút vừa, callout → `radius-14` card → `radius-16` nút lớn, pane → `radius-20` modal → `radius-24` toast; `radius-round` cho nút HUD và avatar. - Bóng phẳng lệch dọc như đồ chơi gỗ: `shadow-press` dưới nút chính (nhấn thì lún 3px và đổi sang `shadow-press-down`), `shadow-sign` và `shadow-board` cho biển tên và bảng phấn. Bóng nhoè chủ yếu cho lớp nổi: `shadow-modal`, `shadow-toast`; ngoại lệ có chủ ý là `shadow-street` (quầng cam nút Xuống Phố), bong bóng linh vật (`tt-bubble--mascot`, bóng nhoè theo `ink`), biển ở cửa tiệm (`tt-signboard__plate--door`, bóng nhoè kèm quầng `gold`), bóng đổ `drop-shadow` của ảnh linh vật, huy hiệu `tt-mascot__badge`, nút `tt-urgent__confirm` (bóng `warn` nhoè) và marker `tt-shipper-pin` (ảnh và bong bóng). Card thường không có bóng. ## Hình ảnh và icon - Tranh vẽ tay pastel, nét nâu, bóng mềm (nhóm Scenes, Sprites). Không chèn ảnh chụp hay hình vector phẳng. - Icon là 37 PNG vẽ tay (nhóm Icons, tên `ic_*`), hiển thị bằng `` cỡ 18–30px. Ảnh nhiều màu nên không tô lại bằng CSS; bảng nghĩa của từng icon nằm trong README của nhóm. - Sticker (nhóm Stickers) để trang trí splash, ô trống và tiêu đề; tối đa 2–3 cái một màn. Avatars là 50 mặt thú tròn cho thương hiệu quán, bạn bè và nhân viên; Shippers là 6 nhân vật chạy xe: chỉ `6.png` (Shipper Thỏ Vàng) là shipper trên bản đồ giao hàng, `1.png`–`5.png` là khách đi dạo phố. - Mascot (nhóm Mascot) là một ảnh `cathead.png`, đầu mèo dùng trong component Mascot; không có ảnh Thần Mèo Karin (nhân vật có bản quyền). Atlas mặt nằm ở nhóm Sprites: `faces.webp` (khách, 3 cột tâm trạng bình thường / vui / giận × 9 hàng, ô 225×220) cho Character và `ship.webp` (shipper, 3 cột × 2 hàng, ô 225×220) cho ShipperBadge; cắt bằng `background-position` qua `--tt-col` / `--tt-row`, không scale lệch tỉ lệ. - Huy hiệu tâm trạng của Character là PNG, không dùng emoji: vui = `assets/Stickers/stk_heart.png`, giận = `assets/Icons/ic_angry.png`, bình thường không có huy hiệu; trạng thái luôn có thêm chữ `tt-sr-only` để không chỉ dựa vào hình. - Minigame (nhóm Minigame) là 7 PNG chibi pastel của Bầu Cua: 6 linh vật (bầu, cua, tôm, cá, gà, nai) và bát úp trên đĩa xóc, dùng trong BauCuaBoard và DiceBowl; đặt trên nền sáng cố định (`die-face`), xem README của nhóm. - Logo là app icon ly trà sữa trên nền `pink` (nhóm Logo). Trong giao diện, tên quán luôn set bằng chữ Baloo 2 800; không có logo chữ riêng. ## Chuyển động - Nút nổi dùng lò xo `cubic-bezier(.34,1.56,.64,1)` .18s (phóng 1.08 khi hover, 0.94 khi nhấn); nút chính lún 3px khi nhấn. - Khách giận lắc `tt-shake` .3s; khay khách đang gọi nhịp `tt-pulse` 1.4s; coachmark có vòng `tt-ring` 1.1s. Base còn có sẵn keyframes `tt-slide-in` (.6s, khách mới trượt vào) và `tt-bob` (2.2s, mặt khách nhún) để gắn khi dựng màn; hai keyframes này chưa gắn vào lớp component nào. Toast hiện và ẩn bằng opacity .25s. - Chuyển động của vật thể trong minigame (nhấc bát .45s, mờ .35s; lắc bát .12s lặp; nhịp ô trúng .6s lặp) theo thời lượng của game, vượt mức .25s (ngoại lệ trong `docs/conventions.md`). Mọi animation tắt khi người chơi bật `prefers-reduced-motion` (đã có trong `.tt-app`). ## Trạng thái tương tác - Focus bàn phím: vòng 3px `focus-ring`, offset 2px, trên mọi control. - Đang chọn: nền `pink` + chữ `on-pink` (trang của pager), viền `pink` + nền pink 16% (chip), hoặc `shadow-ring-pink` (ô chọn theme). Ở `hc` thêm dấu hiệu không dựa vào sắc độ: `shadow-on` (vòng pink trong, thành dải 4px) cho chip và ô cỡ ly, `shadow-tab-on` (vạch pink trên đầu) cho tab. - Disabled: độ mờ .4 với nút nhỏ, .6 với nút lớn, con trỏ not-allowed. Hết hàng và chưa mở khoá dùng lớp phủ chữ "Hết" hoặc icon `ic_lock`, không chỉ làm mờ. - Nhấn: nút lún xuống, thẻ khách thu nhỏ .97. ## Khả năng tiếp cận Các cặp màu gốc dưới chuẩn WCAG được giữ nguyên ở bốn theme của game để không đổi nhận diện; ai cần đạt chuẩn thì dùng theme `hc` (xem mục Theme Tương phản cao bên dưới, không có cặp nào trong bảng này áp dụng cho `hc`). Số liệu tính bằng `node scripts/contrast.js` từ `tokens.json`; mỗi ô liệt kê theo thứ tự Kem sữa · Nâu cà phê · Sô cô la · Đêm dịu (cột `hc` có trong output của script). Bảng ghi cách dùng an toàn và hướng sửa nếu cần đạt chuẩn: | Cặp màu | Tỉ lệ (kem · nau · socola · dem) | Dùng an toàn | Hướng sửa | |---|---|---|---| | `on-pink` trên `pink` | 2.86 · 4.96 · 8.90 · 2.27 | Nhãn nút chính luôn 800, từ 1.1rem | `ink` trên `pink` (5.12) ở Kem sữa, `bg` trên `pink` (6.60) ở Đêm dịu | | `mint` làm chữ trên `panel` / `bg` | panel 2.78 · 2.48 · 2.27 · 4.26; bg 2.63 · 2.10 · 1.69 · 5.18 | Luôn kèm ✓ và chữ đậm; ba theme sáng không đủ 3:1 | Dùng `ink` cho chữ, `mint` cho icon và viền | | `warn` làm chữ trên `panel` / `bg` | panel 3.54 · 3.16 · 2.89 · 3.35; bg 3.35 · 2.67 · 2.15 · 4.06 | Chữ đậm từ 19px hoặc kèm icon | `fresh-1-ink` (4.63 trên `fresh-1-bg`) | | Sao `gold` trên `panel` / `bg` (HUD) | panel 1.79 · 1.59 · 1.46 · 6.64; bg 1.69 · 1.35 · 1.08 · 8.05 | Luôn kèm điểm bằng chữ; sao `aria-hidden` | Không cần sửa nếu luôn có số | | `pink-d` làm chữ (tên quán HUD, từ khoá lời khách, khách online) | bg 4.22 · 6.45 · 7.51 · 3.55; panel 4.46 · 7.64 · 10.11 · 2.93 | Game giữ `pink-d` ở mọi theme; Kem sữa chỉ nên dùng chữ đậm | Ghi đè bằng `pink` ở Đêm dịu (5.44 trên `panel`) | | `pink` làm chữ ("Đơn online", nhãn nhấn) | panel 2.76 · 4.26 · 6.99 · 5.44 | Kem sữa: chỉ chữ đậm kèm viền `pink` của thẻ | `pink-d` ở Kem sữa (4.46) | | `link` làm chữ (phản hồi chủ quán, thanh doanh thu) | panel 4.40 · 3.92 · 3.59 · 2.70 | Chữ đi kèm nhãn "Chủ quán:"; thanh doanh thu có số bên cạnh | `ink` cho chữ, `link` cho viền hoặc thanh | | `soft` trên `line` (badge muted, số đơn online, nút ✕ dialog) | 4.42 · 3.79 · 3.29 · 4.48 | Chữ đậm, ngắn hoặc có icon; ✕ có `aria-label` | `ink` trên `line` (từ 5.66) | | Tab chưa chọn (`ink` độ đục .72 trên nền dải tab) | 5.20 · 4.38 · 4.16 · 5.08 | Chữ 700; tab chọn đã tương phản đủ | Bỏ `opacity` nếu cần ≥ 4.5:1 | | `.tt-empty__hint` (`soft` độ đục .8) | trên `bg` 3.69 · 3.77 · 3.71 · 5.80; trên `panel` 3.84 · 4.24 · 4.57 · 4.94 | Chữ gợi ý phụ, ý chính nằm ở dòng trên | Bỏ `opacity` (khi đó `soft` ≥ 5.52) | | `on-fill` trên `coach`, `street`, `mint`, `target`, `stage-pink` | cố định 2.57–3.68 | Chữ đậm từ 19px hoặc số ngắn | Chữ `ink` trên nền nhạt | | `on-fill` trên `stage-track` (% loading của splash) | cố định 1.67 | Chữ % nằm giữa thanh nên phần chưa tô khó đọc; chỉ coi là số phụ, trạng thái chính nằm ở `tt-splash__message` | `stage-ink` trên `stage-track` (6.90) khi thanh chưa tô; `on-fill` trên `stage-ink` (11.49) khi đã tô | | `line` làm viền control | 1.35–2.26 trên `panel` | Control có nền `bg` khác `panel` | Viền `soft` cho control quan trọng | - Chữ trên tranh quầy dùng `stage-ink` cố định (8.23:1 trên `bin-badge`, 9.08 trên `stage-ground`) và vòng focus trên sân khấu dùng `outline` (9.48 trên `stage-ground`, 11.53 trên `stage-paper`) để không phụ thuộc theme; ngoài sân khấu `focus-ring` đạt từ 3:1 trên `bg` và `panel` ở cả bốn theme. - Hai nhãn do hệ thống thêm (`tt-badge--promo`, `tt-dialog__badge`) dùng cặp `fresh-3-ink` / `fresh-3-bg` và `fresh-1-ink` / `fresh-1-bg`: nền cố định ở mọi theme, chữ giữ 4.74 và 4.63 ở bốn theme gốc, còn ở `hc` chữ đậm hơn (9.22 và 9.06). - Hành động là `