# PourGauge
Đồng hồ rót trà ở quầy: giữ tay để rót, thả khi mức trà tới vạch xanh ở khoảng 80%.
## Khi nào dùng
- Rót trà từ hũ vào ly: nhấn giữ hũ (hoặc nút "Nhấn giữ để rót") rồi thả đúng cửa sổ đích.
- Chỉ hiển thị mức (không rót) thì dùng `tt-progress`; gauge này luôn có cửa sổ đích.
## Biến thể
| Biến thể | Lớp | Dùng khi |
|---|---|---|
| Cỡ sân khấu | `tt-pour` | Rộng 170px như game (`.q3gauge`) |
| Rộng hết khung | `tt-pour tt-pour--fluid` | Preview, màn nhỏ hoặc khi cần thanh lớn hơn |
## Cấu trúc
```html
```
`__track` là rãnh `wood-dark` (JS thêm `role="progressbar"`), `__level` là mức trà (gradient `pour-low` → `pour-mid` 60% → `pour-high` 80%; bốn theme gốc: `pour-low` = `warn`, `pour-high` = `target`), `__target` là cửa sổ đích viền 3px `on-fill`. Nút giữ dùng lại `tt-button`; có thể thay bằng chính hũ trà của quầy qua `opts.hold`.
## Trạng thái
| Trạng thái | Hiệu ứng |
|---|---|
| `is-pouring` | Đang giữ tay; nút có `aria-pressed="true"` |
| `is-hit` | Thả trong cửa sổ đích: chữ kết quả `mint` |
| `is-miss` | Thả ngoài cửa sổ hoặc tràn: chữ kết quả `warn` |
## Hành vi JS
`TTMU.pourGauge(root, opts)` → `{ fill, pouring, target, setTarget([lo, hi]), reset(), destroy() }` hoặc `null` nếu đã gắn.
```js
TTMU.pourGauge(el, {
target: [0.74, 0.86], // mặc định: left 74% + width 12% của .q3ok
speed: 0.54, // mức đầy mỗi giây (tick() của game)
onStop: function (r) { /* r = { fill, hit, spill } */ }
});
```
- `pointerdown` bắt đầu rót; `pointerup`, `pointerleave`, `pointercancel`, `blur` (nút, cửa sổ, tab ẩn) dừng. Space hoặc Enter giữ cũng rót, thả phím thì dừng.
- Cập nhật bằng `requestAnimationFrame` theo thời gian thật (mỗi khung tối đa 100ms); mức đầy tối đa 1.02, trên 1.0 là tràn (`spill`).
- Rót tiếp từ mức hiện có (như ly đang đầy dở); `reset()` để về 0. `hit` = không tràn và `fill` nằm trong `[lo, hi]`.
- Chữ kết quả đổi bằng `opts.labels` (`idle`, `pouring`, `hit`, `low`, `high`, `spill`).
## Token sử dụng
`wood-dark`, `pour-low`, `pour-mid`, `pour-high` (gradient mức trà), `on-fill`, `mint` (trúng), `warn` (trượt), `soft`, `radius-6`, `space-10`; nút dùng `pink` qua Button.
## Khả năng tiếp cận
- Rãnh là `role="progressbar"` (`aria-valuenow` = phần trăm mức trà); kết quả đọc qua vùng `role="status"`.
- Bàn phím: Tab tới nút, giữ Space/Enter để rót. Kết quả trúng/trượt luôn có chữ, không chỉ màu.
- Nút có `touch-action: none`, chặn menu giữ lâu và chọn chữ để thao tác chạm không bị cuộn trang.
## Nên / Không nên
| Nên | Không nên |
|---|---|
| Đặt `target` đúng cửa sổ vạch xanh đang hiển thị | Để cửa sổ CSS khác với `target` trong JS |
| Gọi `reset()` khi đổ ly hoặc lấy ly mới | Gắn lại `pourGauge` lên cùng phần tử mà không `destroy()` |
## Nguồn
`.q3gauge`, `.q3lv`, `.q3ok` — css/style.css dòng 648–650; rót ở `tick()` trong js/game.js dòng 7619 (0,54 mỗi giây, kẹp 1,02, tràn khi quá 1).
- Chấm điểm ở `sealServe()`: lệch quá 0,14 so với 0,8 (tức ngoài 0,66–0,94) hoặc tràn thì khách bị trừ sao; vạch xanh 0,74–0,86 là vùng ngắm lý tưởng nên `hit` chặt hơn mức bị phạt.
- Cửa sổ đích: viền `#fff` đổi `on-fill`, rãnh `#5b3f25` đổi `wood-dark`, gradient `#e2574c/#f4b73a/#5aae86` đổi `pour-low/pour-mid/pour-high` (bốn theme gốc: `warn/pour-mid/target`, nên màu giữ nguyên; ở `hc` hai đầu sáng hơn để đạt 3:1 trên gỗ).
- Nút "Nhấn giữ để rót" và nhãn kết quả là phần thêm của DS (game rót bằng cách giữ chính hũ trà).