@edmicro/olkit 2.1.8 → 2.1.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/styles/tokens.css CHANGED
@@ -1,431 +1,431 @@
1
- /*
2
- =============================================================================
3
- ÔN LUYỆN DESIGN SYSTEM - THEME TOKENS (FIGMA VARIABLES: 150 TOKENS)
4
- Phân loại theo đúng cấu trúc nhóm (Groups) trong bảng Figma Variables
5
- =============================================================================
6
- */
7
-
8
- :root {
9
- /* -------------------------------------------------------------------------
10
- -1. COLOR SCHEME — thanh cuộn, ô chọn gốc, ô nhập gốc
11
- -------------------------------------------------------------------------
12
- `color-scheme` là thứ DUY NHẤT nói cho trình duyệt biết trang đang sáng
13
- hay tối. Nó đổi màu những phần do TRÌNH DUYỆT vẽ, không phải CSS của ta:
14
- thanh cuộn, mũi tên `<select>`, nút tăng giảm `<input type=number>`, lịch
15
- của `<input type=date>`, nền ô nhập tự điền.
16
-
17
- Thiếu nó: đo /select ở chế độ tối được `color-scheme: normal`, nên thanh
18
- cuộn vẫn SÁNG trên nền tối — ba vệt trắng chói ở mép phải trang, cạnh
19
- sidebar và trong cột thuộc tính.
20
-
21
- Đặt ở `:root`/`.dark` chứ không ở `body`: thanh cuộn của trang do phần tử
22
- gốc quyết định, đặt ở `body` là không ăn.
23
- ------------------------------------------------------------------------- */
24
- color-scheme: light;
25
-
26
- /* -------------------------------------------------------------------------
27
- 0. BORDER RADIUS SCALE (Default Figma - Modern)
28
- ------------------------------------------------------------------------- */
29
- --radius-none: 0px;
30
- --radius-xxs: 2px;
31
- --radius-xs: 4px;
32
- --radius-sm: 6px;
33
- --radius: 8px;
34
- --radius-base: 12px;
35
- --radius-md: 12px;
36
- --radius-lg: 16px;
37
- --radius-xl: 24px;
38
- --radius-2xl: 24px;
39
- --radius-3xl: 32px;
40
- --radius-full: 9999px;
41
-
42
- /* -------------------------------------------------------------------------
43
- 0b. ANIMATION (timing & easing)
44
- Trước đây khai trong shared/styles/animations-vars.css nhưng file đó không
45
- ai import, mà animations.css lại dùng các biến này — nên mọi animation
46
- chạy bằng giá trị fallback, token timing vô dụng. Đưa lên :root global vì
47
- component dùng ViewEncapsulation.Emulated sẽ scope mất :root.
48
- ------------------------------------------------------------------------- */
49
- --anim-duration-fast: 150ms;
50
- --anim-duration-normal: 300ms;
51
- --anim-duration-slow: 500ms;
52
- --anim-ease-in-out: cubic-bezier(0.4, 0, 0.2, 1);
53
- --anim-ease-out: cubic-bezier(0, 0, 0.2, 1);
54
- --anim-ease-in: cubic-bezier(0.4, 0, 1, 1);
55
- --anim-linear: linear;
56
- --anim-spring: cubic-bezier(0.34, 1.56, 0.64, 1);
57
-
58
- /* -------------------------------------------------------------------------
59
- 1. COLORS / TEXT (22 Tokens)
60
- ------------------------------------------------------------------------- */
61
- --text-white: var(--color-white);
62
- --text-black: var(--color-gray-900);
63
- --text-heading: var(--color-gray-900);
64
- --text-body: var(--color-gray-600);
65
- --text-body-subtle: var(--color-gray-500);
66
-
67
- /* Brand Text */
68
- --text-brand: var(--color-brand-700);
69
- --text-brand-strong: var(--color-brand-900);
70
- --text-brand-subtle: var(--color-brand-300);
71
- /* Hai mức dưới đây KHÔNG có trong Figma Themes — mã đang viết thẳng
72
- `text-brand-800` (3 lượt) và `text-brand-100` (1 lượt). Đặt token để chúng
73
- lật được theo chế độ tối, theo đúng lối hai mức đã có ở trên. */
74
- --text-brand-medium: var(--color-brand-800);
75
- --text-brand-soft: var(--color-brand-100);
76
-
77
- /* Status Text */
78
- --text-success: var(--color-emerald-700);
79
- --text-success-strong: var(--color-emerald-900);
80
- --text-danger: var(--color-rose-600);
81
- --text-danger-strong: var(--color-rose-900);
82
- /* Cảnh báo — theo Figma colors/text/text-fg-warning*. Trước đây warning
83
- lấy orange-600 (trùng bậc với -subtle) và -strong lấy orange-700 (trùng
84
- luôn với nền bg-warning-strong), nên chữ chìm vào nền. */
85
- --text-warning: var(--color-yellow-800);
86
- --text-warning-strong: var(--color-yellow-950);
87
- --text-warning-subtle: var(--color-yellow-700);
88
- --text-info: var(--color-brand-900);
89
- --text-info-strong: var(--color-brand-900);
90
- --text-disabled: var(--color-gray-400);
91
-
92
- /* -------------------------------------------------------------------------
93
- 2. COLORS / BACKGROUND (43 Tokens)
94
- ------------------------------------------------------------------------- */
95
- --bg-primary: #ffffff;
96
- --bg-primary-soft: #ffffff;
97
- --bg-primary-medium: #ffffff;
98
- --bg-primary-strong: #ffffff;
99
-
100
- --bg-secondary: #f9fafb;
101
- --bg-secondary-soft: #f9fafb;
102
- --bg-secondary-medium: var(--color-gray-50);
103
- --bg-secondary-strong: var(--color-gray-50);
104
-
105
- /* Tertiary & Quaternary — theo Figma colors/background/bg-neutral-tertiary|quaternary */
106
- --bg-tertiary: var(--color-gray-100);
107
- --bg-tertiary-soft: var(--color-gray-100);
108
- --bg-tertiary-medium: var(--color-gray-100);
109
- --bg-quaternary: var(--color-gray-200);
110
- --bg-quaternary-medium: var(--color-gray-200);
111
-
112
- /* Brand Background */
113
- --bg-brand: var(--color-brand-700);
114
- --bg-brand-soft: var(--color-brand-100);
115
- --bg-brand-softer: var(--color-brand-50);
116
- --bg-brand-medium: var(--color-brand-200);
117
- --bg-brand-strong: var(--color-brand-800);
118
-
119
- /* --------------------------------------------------------------------------
120
- Nền thanh điều hướng ứng dụng (`ol-app-nav`).
121
-
122
- KHÔNG đổi ở chế độ tối: thanh này vốn đã tối, và Figma chốt một màu duy
123
- nhất cho cả hai chế độ. Chữ trên đó luôn trắng.
124
- -------------------------------------------------------------------------- */
125
- --bg-app-nav-from: var(--color-navy-from);
126
- --bg-app-nav-to: var(--color-navy-to);
127
- --bg-app-nav-hover: var(--color-brand-600);
128
-
129
- /* Dark Background Tokens */
130
- --bg-dark: var(--color-gray-800);
131
- --bg-dark-strong: var(--color-gray-900);
132
- --bg-disabled: var(--color-gray-100);
133
-
134
- /* Status Backgrounds */
135
- --bg-warning: var(--color-yellow-400);
136
- --bg-warning-medium: var(--color-yellow-100);
137
- --bg-warning-strong: var(--color-yellow-500);
138
- --bg-success: var(--color-emerald-700);
139
- --bg-success-soft: var(--color-emerald-50);
140
- --bg-success-strong: var(--color-emerald-800);
141
- --bg-danger: var(--color-rose-600);
142
- --bg-danger-soft: var(--color-rose-50);
143
- --bg-danger-strong: var(--color-rose-800);
144
-
145
- /* Semantic Palette Backgrounds
146
- Tám màu phụ này là NỀN ĐẶC, nên ở chế độ tối đi đậm hơn một bậc — cùng
147
- quy luật với --bg-danger (600 -> 700) và --bg-warning (400 -> 500).
148
- Giá trị tối khai trong khối .dark bên dưới. */
149
- --bg-purple: var(--color-purple-500);
150
- --bg-sky: var(--color-sky-500);
151
- --bg-teal: var(--color-teal-600);
152
- --bg-pink: var(--color-pink-600);
153
- --bg-cyan: var(--color-cyan-500);
154
- --bg-fuchsia: var(--color-fuchsia-600);
155
- --bg-indigo: var(--color-indigo-600);
156
- --bg-orange: var(--color-orange-400);
157
-
158
- /* -------------------------------------------------------------------------
159
- 3. COLORS / BORDER (25 Tokens)
160
- ------------------------------------------------------------------------- */
161
- --border-buffer: var(--color-white);
162
- --border-muted: var(--color-gray-50);
163
- --border-light-subtle: var(--color-gray-100);
164
- --border-light: var(--color-gray-100);
165
- --border-default-subtle: var(--color-gray-200);
166
- --border-default: var(--color-gray-200);
167
- --border-default-medium: var(--color-gray-200);
168
- --border-default-strong: var(--color-gray-200);
169
-
170
- /* Brand & Status Borders */
171
- --border-brand: var(--color-brand-700);
172
-
173
- /* Focus — theo Figma colors/border/border-focus và
174
- colors/background/bg-focus-ring. Trước đây code không có token này nên
175
- mọi focus ring phải viết thẳng bậc màu (ring-brand-200). */
176
- --border-focus: var(--color-brand-700);
177
- --bg-focus-ring: var(--color-brand-200);
178
- --border-brand-subtle: var(--color-brand-200);
179
- --border-brand-light: var(--color-brand-500);
180
- /* Viền nhạt cho focus ring theo Figma colors/border/border-*-subtle.
181
- Trước đây thiếu hẳn nên button phải mượn bậc primitive (emerald-300…)
182
- và ra sai màu so với thiết kế. */
183
- --border-success-subtle: var(--color-emerald-200);
184
- --border-danger-subtle: var(--color-rose-200);
185
- --border-warning-subtle: var(--color-yellow-200);
186
- --border-success: var(--color-emerald-700);
187
- --border-danger: var(--color-rose-600);
188
- --border-warning: var(--color-yellow-400);
189
- --border-info: var(--color-brand-300);
190
-
191
- /* ---- Bổ sung 20 token Figma có mà code thiếu (đối chiếu 2026-09-11) ----
192
- Figma đặt tên bg-neutral-* và text-fg-*, code bỏ tiền tố cho gọn. */
193
- --bg-white: var(--color-white);
194
- --bg-gray: var(--color-gray-300);
195
- --bg-danger-medium: var(--color-rose-100);
196
- --bg-success-medium: var(--color-emerald-100);
197
- --bg-warning-soft: var(--color-yellow-50);
198
- --bg-warning-strongest: var(--color-yellow-600);
199
-
200
- --border-dark: var(--color-gray-800);
201
- --border-dark-subtle: var(--color-gray-800);
202
- --border-light-medium: var(--color-gray-100);
203
- --border-buffer-medium: var(--color-white);
204
- --border-buffer-strong: var(--color-white);
205
- --border-buffer-gradient-secondary: var(--color-gray-50);
206
- --border-orange: var(--color-orange-400);
207
- --border-purple: var(--color-purple-500);
208
-
209
- /* Màu chữ phụ — dùng cho chart, tag, biểu tượng môn học. Không phải màu
210
- trạng thái: warning vẫn là orange. */
211
- --text-cyan: var(--color-cyan-600);
212
- --text-indigo: var(--color-indigo-600);
213
- --text-lime: var(--color-lime-600);
214
- --text-pink: var(--color-pink-600);
215
- --text-purple: var(--color-purple-600);
216
- --text-yellow: var(--color-yellow-400);
217
-
218
- /* ---- Thang xếp lớp ----
219
- Trước đây 75 lượt z-* rải rác trong thư viện, dùng chung z-50 cho modal,
220
- tooltip, toast, dropdown, popover và datepicker nên thứ tự chồng lớp phụ
221
- thuộc thứ tự render; lại còn z-999 / z-9999 / z-[100] phá thang.
222
- Đặt tên theo vai trò để thứ tự luôn xác định. Figma không có nhóm này —
223
- xếp lớp là chuyện của code, không đẩy ngược lên Figma. */
224
- --z-base: 0;
225
- --z-raised: 10;
226
- --z-sticky: 20;
227
- --z-drawer-backdrop: 30;
228
- --z-drawer: 40;
229
- --z-dropdown: 50;
230
- --z-popover: 60;
231
- --z-modal-backdrop: 70;
232
- --z-modal: 80;
233
- --z-tooltip: 90;
234
- --z-toast: 100;
235
- /* Lớp phủ tối — che nội dung phía dưới (modal, drawer, backdrop).
236
- Dùng đen ở CẢ hai chế độ: lớp phủ làm tối, không đổi theo chủ đề.
237
- Khớp Figma colors/background/bg-overlay-* (Themes, 2 mode). */
238
- --bg-overlay-subtle: rgb(0 0 0 / 0.05);
239
- --bg-overlay-soft: rgb(0 0 0 / 0.1);
240
- --bg-overlay-medium: rgb(0 0 0 / 0.2);
241
- --bg-overlay-strong: rgb(0 0 0 / 0.4);
242
- --bg-overlay-backdrop: rgb(0 0 0 / 0.5);
243
- }
244
-
245
- /* =============================================================================
246
- DARK MODE
247
- ============================================================================= */
248
- .dark {
249
- /* Xem chú thích ở `:root`. Đây là thứ làm thanh cuộn chuyển sang màu tối. */
250
- color-scheme: dark;
251
-
252
- /* 1. Colors / Text - Dark */
253
- --text-white: #ffffff;
254
- /* Theo Figma colors/text/text-black: giữ gray/900 ở CẢ light lẫn dark.
255
- Đây là cặp token "tuyệt đối" cùng với --text-white — dùng khi cần đen/trắng
256
- bất kể theme (vd chữ trên nền ảnh). Trước đây code đảo thành #FFFFFF ở dark,
257
- làm mất ý nghĩa đó. Chữ tiêu đề đổi theo theme dùng --text-heading. */
258
- --text-black: var(--color-gray-900);
259
- --text-heading: var(--color-white);
260
- /* `gray-300`, KHÔNG phải `gray-400`, cho CẢ HAI token dưới đây: trên nền
261
- `tertiary`/`quaternary` (đều là `gray-700` ở chế độ tối) thì `gray-400`
262
- chỉ cho **3,96** — dưới chuẩn 4,5 cho chữ 12px.
263
-
264
- Đo `/banner`: chip `role="banner"` 110×24px, sáng 6,10 đạt mà tối 3,96
265
- hỏng (BUG-032 §5). Chip đó thừa kế màu từ `text-body` của khung layout,
266
- KHÔNG dùng `text-body-subtle` — nên phải đổi cả hai, sửa mỗi
267
- `body-subtle` không chạm tới nó (đã thử, chip vẫn 3,96).
268
-
269
- `gray-300` đưa hai nền đó lên **7,00** và không kéo nền nào xuống:
270
- primary 12,05 · secondary 9,96 (trước là 6,82 · 5,64). */
271
- --text-body: var(--color-gray-300);
272
- /* `--text-body-subtle` đang bằng HỆT `--text-body` ở nhánh tối, tức "subtle"
273
- không còn nhạt hơn gì cả. Giữ nguyên tương quan đó ở đây; muốn tách hai
274
- bậc thì phải đo lại cả bốn nền. */
275
- --text-body-subtle: var(--color-gray-300);
276
-
277
- --text-brand: var(--color-brand-400);
278
- --text-brand-strong: var(--color-brand-300);
279
- --text-brand-subtle: var(--color-brand-300);
280
- /* Lật sáng lên ở nền tối, cùng hướng với --text-brand (700 -> 400). */
281
- --text-brand-medium: var(--color-brand-300);
282
- --text-brand-soft: var(--color-brand-900);
283
-
284
- --text-success: var(--color-emerald-600);
285
- --text-success-strong: var(--color-emerald-300);
286
- --text-danger: var(--color-rose-500);
287
- --text-danger-strong: var(--color-rose-300);
288
- --text-warning: var(--color-yellow-300);
289
- --text-warning-strong: var(--color-yellow-200);
290
- --text-warning-subtle: var(--color-yellow-400);
291
- --text-info: var(--color-brand-300);
292
- /* Trước đây dark mode thiếu hẳn token này nên rơi về brand-900 của :root
293
- — gần như đen trên nền tối. */
294
- --text-info-strong: var(--color-brand-300);
295
- --text-disabled: var(--color-gray-600);
296
-
297
- /* 2. Colors / Background - Dark */
298
- --bg-primary: var(--color-gray-950);
299
- --bg-primary-soft: var(--color-gray-900);
300
- --bg-primary-medium: var(--color-gray-800);
301
- --bg-primary-strong: var(--color-gray-700);
302
-
303
- --bg-secondary: var(--color-gray-950);
304
- --bg-secondary-soft: var(--color-gray-900);
305
- --bg-secondary-medium: var(--color-gray-800);
306
- --bg-secondary-strong: var(--color-gray-700);
307
-
308
- /* Tertiary & Quaternary — Figma Modern (dark) dùng thang gray */
309
- --bg-tertiary: var(--color-gray-800);
310
- --bg-tertiary-soft: var(--color-gray-900);
311
- --bg-tertiary-medium: var(--color-gray-700);
312
- --bg-quaternary: var(--color-gray-700);
313
- --bg-quaternary-medium: var(--color-gray-600);
314
-
315
- --bg-brand: var(--color-brand-600);
316
- --bg-brand-soft: var(--color-brand-900);
317
- --bg-brand-softer: var(--color-brand-950);
318
- --bg-brand-medium: var(--color-brand-800);
319
- --bg-brand-strong: var(--color-brand-700);
320
-
321
- --bg-dark: var(--color-gray-800);
322
- --bg-dark-strong: var(--color-gray-700);
323
- --bg-disabled: var(--color-gray-800);
324
-
325
- --bg-warning: var(--color-yellow-500);
326
- --bg-warning-medium: var(--color-yellow-900);
327
- --bg-warning-strong: var(--color-yellow-600);
328
- --bg-success: var(--color-emerald-600);
329
- --bg-success-strong: var(--color-emerald-700);
330
- --bg-success-soft: var(--color-emerald-950);
331
- --bg-danger: var(--color-rose-700);
332
- --bg-danger-strong: var(--color-rose-800);
333
- --bg-danger-soft: var(--color-rose-950);
334
-
335
- /* Semantic Palette Backgrounds - Dark
336
- Lấy thẳng từ collection "Themes" của Figma, mode `Modern (dark)`. Figma
337
- chia hai nhóm chứ không có một quy luật chung: --bg-danger và --bg-warning
338
- đi đậm hơn một bậc, còn tám màu bảng phụ dưới đây thì GIỮ NGUYÊN bậc sáng
339
- (purple, sky, cyan, orange) hoặc NHẠT ĐI một bậc (teal, pink, fuchsia,
340
- indigo) — nền đặc trên nền tối #030712 đậm thêm sẽ mất tương phản.
341
- --bg-orange bám sát nhất vì `ol-toggle` Status=Medium bind đúng
342
- colors/orange/400 ở cả hai mode. */
343
- --bg-purple: var(--color-purple-500);
344
- --bg-sky: var(--color-sky-500);
345
- --bg-teal: var(--color-teal-500);
346
- --bg-pink: var(--color-pink-500);
347
- --bg-cyan: var(--color-cyan-500);
348
- --bg-fuchsia: var(--color-fuchsia-500);
349
- --bg-indigo: var(--color-indigo-500);
350
- --bg-orange: var(--color-orange-400);
351
-
352
- /* 3. Colors / Border - Dark */
353
- --border-buffer: var(--color-gray-950);
354
- --border-muted: var(--color-gray-900);
355
- --border-light-subtle: var(--color-gray-900);
356
- --border-light: var(--color-gray-800);
357
- --border-default-subtle: var(--color-gray-900);
358
- --border-default: var(--color-gray-800);
359
- --border-default-medium: var(--color-gray-700);
360
- --border-default-strong: var(--color-gray-600);
361
-
362
- --border-brand: var(--color-brand-600);
363
- --border-focus: var(--color-brand-300);
364
- --bg-focus-ring: var(--color-brand-800);
365
- --border-brand-subtle: var(--color-brand-800);
366
- --border-brand-light: var(--color-brand-500);
367
- --border-success-subtle: var(--color-emerald-900);
368
- --border-danger-subtle: var(--color-rose-900);
369
- --border-warning-subtle: var(--color-yellow-900);
370
- --border-success: var(--color-emerald-600);
371
- --border-danger: var(--color-rose-600);
372
- --border-warning: var(--color-yellow-500);
373
- --border-info: var(--color-brand-600);
374
-
375
- /* 20 token bổ sung — giá trị mode Modern (dark) của Figma */
376
- --bg-white: var(--color-white);
377
- --bg-gray: var(--color-gray-600);
378
- --bg-danger-medium: var(--color-rose-900);
379
- --bg-success-medium: var(--color-emerald-900);
380
- --bg-warning-soft: var(--color-yellow-950);
381
- --bg-warning-strongest: var(--color-yellow-700);
382
-
383
- --border-dark: var(--color-gray-600);
384
- --border-dark-subtle: var(--color-gray-700);
385
- --border-light-medium: var(--color-gray-700);
386
- --border-buffer-medium: var(--color-gray-900);
387
- --border-buffer-strong: var(--color-gray-800);
388
- --border-buffer-gradient-secondary: var(--color-gray-950);
389
- --border-orange: var(--color-orange-400);
390
- --border-purple: var(--color-purple-500);
391
-
392
- --text-cyan: var(--color-cyan-500);
393
- --text-indigo: var(--color-indigo-500);
394
- --text-lime: var(--color-lime-500);
395
- --text-pink: var(--color-pink-500);
396
- --text-purple: var(--color-purple-500);
397
- --text-yellow: var(--color-yellow-400);
398
- }
399
-
400
- /* =============================================================================
401
- THEME: TIỂU HỌC — KHUNG, CHƯA ĐỔ GIÁ TRỊ
402
-
403
- Bốn theme phụ cũ (`minimal` · `enterprise` · `playful` · `mono`) đã gỡ
404
- 2026-09-21 theo VIỆC-029: Figma chỉ có Ôn Luyện, code có 5 theme nên 661
405
- dòng ở đây không ứng với thiết kế nào.
406
-
407
- Giữ lại đúng CƠ CHẾ `data-theme` cho theme này. Hai khối dưới đây cố ý để
408
- TRỐNG: đổi sang `tieu-hoc` lúc này thì giao diện y hệt Ôn Luyện, không vỡ
409
- gì — an toàn để ghép dần.
410
-
411
- ## Cách đổ giá trị
412
-
413
- Chỉ override TOKEN NGỮ NGHĨA (`--bg-*`, `--text-*`, `--border-*`,
414
- `--radius-*`). ĐỪNG override primitive (`--color-brand-700`) — primitive là
415
- bảng màu gốc dùng chung, sửa nó là đổi cả Ôn Luyện.
416
-
417
- Mỗi giá trị đặt ở CẢ HAI khối: thiếu khối `.dark` thì theme mới chỉ có chế
418
- độ sáng, và người dùng bật chế độ tối sẽ rơi về màu Ôn Luyện — lệch nửa
419
- vời, khó thấy hơn là hỏng hẳn.
420
-
421
- Hướng thiết kế người dùng đã nêu: "dành cho trẻ con, cần đẹp mắt" — bo góc
422
- tròn hơn, màu tươi hơn. Chưa có Figma, sẽ dựng bản nháp riêng để duyệt.
423
- ============================================================================= */
424
- [data-theme='tieu-hoc'] {
425
- /* trống — xem chú thích trên */
426
- }
427
-
428
- .dark[data-theme='tieu-hoc'],
429
- [data-theme='tieu-hoc'].dark {
430
- /* trống — xem chú thích trên */
431
- }
1
+ /*
2
+ =============================================================================
3
+ ÔN LUYỆN DESIGN SYSTEM - THEME TOKENS (FIGMA VARIABLES: 150 TOKENS)
4
+ Phân loại theo đúng cấu trúc nhóm (Groups) trong bảng Figma Variables
5
+ =============================================================================
6
+ */
7
+
8
+ :root {
9
+ /* -------------------------------------------------------------------------
10
+ -1. COLOR SCHEME — thanh cuộn, ô chọn gốc, ô nhập gốc
11
+ -------------------------------------------------------------------------
12
+ `color-scheme` là thứ DUY NHẤT nói cho trình duyệt biết trang đang sáng
13
+ hay tối. Nó đổi màu những phần do TRÌNH DUYỆT vẽ, không phải CSS của ta:
14
+ thanh cuộn, mũi tên `<select>`, nút tăng giảm `<input type=number>`, lịch
15
+ của `<input type=date>`, nền ô nhập tự điền.
16
+
17
+ Thiếu nó: đo /select ở chế độ tối được `color-scheme: normal`, nên thanh
18
+ cuộn vẫn SÁNG trên nền tối — ba vệt trắng chói ở mép phải trang, cạnh
19
+ sidebar và trong cột thuộc tính.
20
+
21
+ Đặt ở `:root`/`.dark` chứ không ở `body`: thanh cuộn của trang do phần tử
22
+ gốc quyết định, đặt ở `body` là không ăn.
23
+ ------------------------------------------------------------------------- */
24
+ color-scheme: light;
25
+
26
+ /* -------------------------------------------------------------------------
27
+ 0. BORDER RADIUS SCALE (Default Figma - Modern)
28
+ ------------------------------------------------------------------------- */
29
+ --radius-none: 0px;
30
+ --radius-xxs: 2px;
31
+ --radius-xs: 4px;
32
+ --radius-sm: 6px;
33
+ --radius: 8px;
34
+ --radius-base: 12px;
35
+ --radius-md: 12px;
36
+ --radius-lg: 16px;
37
+ --radius-xl: 24px;
38
+ --radius-2xl: 24px;
39
+ --radius-3xl: 32px;
40
+ --radius-full: 9999px;
41
+
42
+ /* -------------------------------------------------------------------------
43
+ 0b. ANIMATION (timing & easing)
44
+ Trước đây khai trong shared/styles/animations-vars.css nhưng file đó không
45
+ ai import, mà animations.css lại dùng các biến này — nên mọi animation
46
+ chạy bằng giá trị fallback, token timing vô dụng. Đưa lên :root global vì
47
+ component dùng ViewEncapsulation.Emulated sẽ scope mất :root.
48
+ ------------------------------------------------------------------------- */
49
+ --anim-duration-fast: 150ms;
50
+ --anim-duration-normal: 300ms;
51
+ --anim-duration-slow: 500ms;
52
+ --anim-ease-in-out: cubic-bezier(0.4, 0, 0.2, 1);
53
+ --anim-ease-out: cubic-bezier(0, 0, 0.2, 1);
54
+ --anim-ease-in: cubic-bezier(0.4, 0, 1, 1);
55
+ --anim-linear: linear;
56
+ --anim-spring: cubic-bezier(0.34, 1.56, 0.64, 1);
57
+
58
+ /* -------------------------------------------------------------------------
59
+ 1. COLORS / TEXT (22 Tokens)
60
+ ------------------------------------------------------------------------- */
61
+ --text-white: var(--color-white);
62
+ --text-black: var(--color-gray-900);
63
+ --text-heading: var(--color-gray-900);
64
+ --text-body: var(--color-gray-600);
65
+ --text-body-subtle: var(--color-gray-500);
66
+
67
+ /* Brand Text */
68
+ --text-brand: var(--color-brand-700);
69
+ --text-brand-strong: var(--color-brand-900);
70
+ --text-brand-subtle: var(--color-brand-300);
71
+ /* Hai mức dưới đây KHÔNG có trong Figma Themes — mã đang viết thẳng
72
+ `text-brand-800` (3 lượt) và `text-brand-100` (1 lượt). Đặt token để chúng
73
+ lật được theo chế độ tối, theo đúng lối hai mức đã có ở trên. */
74
+ --text-brand-medium: var(--color-brand-800);
75
+ --text-brand-soft: var(--color-brand-100);
76
+
77
+ /* Status Text */
78
+ --text-success: var(--color-emerald-700);
79
+ --text-success-strong: var(--color-emerald-900);
80
+ --text-danger: var(--color-rose-600);
81
+ --text-danger-strong: var(--color-rose-900);
82
+ /* Cảnh báo — theo Figma colors/text/text-fg-warning*. Trước đây warning
83
+ lấy orange-600 (trùng bậc với -subtle) và -strong lấy orange-700 (trùng
84
+ luôn với nền bg-warning-strong), nên chữ chìm vào nền. */
85
+ --text-warning: var(--color-yellow-800);
86
+ --text-warning-strong: var(--color-yellow-950);
87
+ --text-warning-subtle: var(--color-yellow-700);
88
+ --text-info: var(--color-brand-900);
89
+ --text-info-strong: var(--color-brand-900);
90
+ --text-disabled: var(--color-gray-400);
91
+
92
+ /* -------------------------------------------------------------------------
93
+ 2. COLORS / BACKGROUND (43 Tokens)
94
+ ------------------------------------------------------------------------- */
95
+ --bg-primary: #ffffff;
96
+ --bg-primary-soft: #ffffff;
97
+ --bg-primary-medium: #ffffff;
98
+ --bg-primary-strong: #ffffff;
99
+
100
+ --bg-secondary: #f9fafb;
101
+ --bg-secondary-soft: #f9fafb;
102
+ --bg-secondary-medium: var(--color-gray-50);
103
+ --bg-secondary-strong: var(--color-gray-50);
104
+
105
+ /* Tertiary & Quaternary — theo Figma colors/background/bg-neutral-tertiary|quaternary */
106
+ --bg-tertiary: var(--color-gray-100);
107
+ --bg-tertiary-soft: var(--color-gray-100);
108
+ --bg-tertiary-medium: var(--color-gray-100);
109
+ --bg-quaternary: var(--color-gray-200);
110
+ --bg-quaternary-medium: var(--color-gray-200);
111
+
112
+ /* Brand Background */
113
+ --bg-brand: var(--color-brand-700);
114
+ --bg-brand-soft: var(--color-brand-100);
115
+ --bg-brand-softer: var(--color-brand-50);
116
+ --bg-brand-medium: var(--color-brand-200);
117
+ --bg-brand-strong: var(--color-brand-800);
118
+
119
+ /* --------------------------------------------------------------------------
120
+ Nền thanh điều hướng ứng dụng (`ol-app-nav`).
121
+
122
+ KHÔNG đổi ở chế độ tối: thanh này vốn đã tối, và Figma chốt một màu duy
123
+ nhất cho cả hai chế độ. Chữ trên đó luôn trắng.
124
+ -------------------------------------------------------------------------- */
125
+ --bg-app-nav-from: var(--color-navy-from);
126
+ --bg-app-nav-to: var(--color-navy-to);
127
+ --bg-app-nav-hover: var(--color-brand-600);
128
+
129
+ /* Dark Background Tokens */
130
+ --bg-dark: var(--color-gray-800);
131
+ --bg-dark-strong: var(--color-gray-900);
132
+ --bg-disabled: var(--color-gray-100);
133
+
134
+ /* Status Backgrounds */
135
+ --bg-warning: var(--color-yellow-400);
136
+ --bg-warning-medium: var(--color-yellow-100);
137
+ --bg-warning-strong: var(--color-yellow-500);
138
+ --bg-success: var(--color-emerald-700);
139
+ --bg-success-soft: var(--color-emerald-50);
140
+ --bg-success-strong: var(--color-emerald-800);
141
+ --bg-danger: var(--color-rose-600);
142
+ --bg-danger-soft: var(--color-rose-50);
143
+ --bg-danger-strong: var(--color-rose-800);
144
+
145
+ /* Semantic Palette Backgrounds
146
+ Tám màu phụ này là NỀN ĐẶC, nên ở chế độ tối đi đậm hơn một bậc — cùng
147
+ quy luật với --bg-danger (600 -> 700) và --bg-warning (400 -> 500).
148
+ Giá trị tối khai trong khối .dark bên dưới. */
149
+ --bg-purple: var(--color-purple-500);
150
+ --bg-sky: var(--color-sky-500);
151
+ --bg-teal: var(--color-teal-600);
152
+ --bg-pink: var(--color-pink-600);
153
+ --bg-cyan: var(--color-cyan-500);
154
+ --bg-fuchsia: var(--color-fuchsia-600);
155
+ --bg-indigo: var(--color-indigo-600);
156
+ --bg-orange: var(--color-orange-400);
157
+
158
+ /* -------------------------------------------------------------------------
159
+ 3. COLORS / BORDER (25 Tokens)
160
+ ------------------------------------------------------------------------- */
161
+ --border-buffer: var(--color-white);
162
+ --border-muted: var(--color-gray-50);
163
+ --border-light-subtle: var(--color-gray-100);
164
+ --border-light: var(--color-gray-100);
165
+ --border-default-subtle: var(--color-gray-200);
166
+ --border-default: var(--color-gray-200);
167
+ --border-default-medium: var(--color-gray-200);
168
+ --border-default-strong: var(--color-gray-200);
169
+
170
+ /* Brand & Status Borders */
171
+ --border-brand: var(--color-brand-700);
172
+
173
+ /* Focus — theo Figma colors/border/border-focus và
174
+ colors/background/bg-focus-ring. Trước đây code không có token này nên
175
+ mọi focus ring phải viết thẳng bậc màu (ring-brand-200). */
176
+ --border-focus: var(--color-brand-700);
177
+ --bg-focus-ring: var(--color-brand-200);
178
+ --border-brand-subtle: var(--color-brand-200);
179
+ --border-brand-light: var(--color-brand-500);
180
+ /* Viền nhạt cho focus ring theo Figma colors/border/border-*-subtle.
181
+ Trước đây thiếu hẳn nên button phải mượn bậc primitive (emerald-300…)
182
+ và ra sai màu so với thiết kế. */
183
+ --border-success-subtle: var(--color-emerald-200);
184
+ --border-danger-subtle: var(--color-rose-200);
185
+ --border-warning-subtle: var(--color-yellow-200);
186
+ --border-success: var(--color-emerald-700);
187
+ --border-danger: var(--color-rose-600);
188
+ --border-warning: var(--color-yellow-400);
189
+ --border-info: var(--color-brand-300);
190
+
191
+ /* ---- Bổ sung 20 token Figma có mà code thiếu (đối chiếu 2026-09-11) ----
192
+ Figma đặt tên bg-neutral-* và text-fg-*, code bỏ tiền tố cho gọn. */
193
+ --bg-white: var(--color-white);
194
+ --bg-gray: var(--color-gray-300);
195
+ --bg-danger-medium: var(--color-rose-100);
196
+ --bg-success-medium: var(--color-emerald-100);
197
+ --bg-warning-soft: var(--color-yellow-50);
198
+ --bg-warning-strongest: var(--color-yellow-600);
199
+
200
+ --border-dark: var(--color-gray-800);
201
+ --border-dark-subtle: var(--color-gray-800);
202
+ --border-light-medium: var(--color-gray-100);
203
+ --border-buffer-medium: var(--color-white);
204
+ --border-buffer-strong: var(--color-white);
205
+ --border-buffer-gradient-secondary: var(--color-gray-50);
206
+ --border-orange: var(--color-orange-400);
207
+ --border-purple: var(--color-purple-500);
208
+
209
+ /* Màu chữ phụ — dùng cho chart, tag, biểu tượng môn học. Không phải màu
210
+ trạng thái: warning vẫn là orange. */
211
+ --text-cyan: var(--color-cyan-600);
212
+ --text-indigo: var(--color-indigo-600);
213
+ --text-lime: var(--color-lime-600);
214
+ --text-pink: var(--color-pink-600);
215
+ --text-purple: var(--color-purple-600);
216
+ --text-yellow: var(--color-yellow-400);
217
+
218
+ /* ---- Thang xếp lớp ----
219
+ Trước đây 75 lượt z-* rải rác trong thư viện, dùng chung z-50 cho modal,
220
+ tooltip, toast, dropdown, popover và datepicker nên thứ tự chồng lớp phụ
221
+ thuộc thứ tự render; lại còn z-999 / z-9999 / z-[100] phá thang.
222
+ Đặt tên theo vai trò để thứ tự luôn xác định. Figma không có nhóm này —
223
+ xếp lớp là chuyện của code, không đẩy ngược lên Figma. */
224
+ --z-base: 0;
225
+ --z-raised: 10;
226
+ --z-sticky: 20;
227
+ --z-drawer-backdrop: 30;
228
+ --z-drawer: 40;
229
+ --z-dropdown: 50;
230
+ --z-popover: 60;
231
+ --z-modal-backdrop: 70;
232
+ --z-modal: 80;
233
+ --z-tooltip: 90;
234
+ --z-toast: 100;
235
+ /* Lớp phủ tối — che nội dung phía dưới (modal, drawer, backdrop).
236
+ Dùng đen ở CẢ hai chế độ: lớp phủ làm tối, không đổi theo chủ đề.
237
+ Khớp Figma colors/background/bg-overlay-* (Themes, 2 mode). */
238
+ --bg-overlay-subtle: rgb(0 0 0 / 0.05);
239
+ --bg-overlay-soft: rgb(0 0 0 / 0.1);
240
+ --bg-overlay-medium: rgb(0 0 0 / 0.2);
241
+ --bg-overlay-strong: rgb(0 0 0 / 0.4);
242
+ --bg-overlay-backdrop: rgb(0 0 0 / 0.5);
243
+ }
244
+
245
+ /* =============================================================================
246
+ DARK MODE
247
+ ============================================================================= */
248
+ .dark {
249
+ /* Xem chú thích ở `:root`. Đây là thứ làm thanh cuộn chuyển sang màu tối. */
250
+ color-scheme: dark;
251
+
252
+ /* 1. Colors / Text - Dark */
253
+ --text-white: #ffffff;
254
+ /* Theo Figma colors/text/text-black: giữ gray/900 ở CẢ light lẫn dark.
255
+ Đây là cặp token "tuyệt đối" cùng với --text-white — dùng khi cần đen/trắng
256
+ bất kể theme (vd chữ trên nền ảnh). Trước đây code đảo thành #FFFFFF ở dark,
257
+ làm mất ý nghĩa đó. Chữ tiêu đề đổi theo theme dùng --text-heading. */
258
+ --text-black: var(--color-gray-900);
259
+ --text-heading: var(--color-white);
260
+ /* `gray-300`, KHÔNG phải `gray-400`, cho CẢ HAI token dưới đây: trên nền
261
+ `tertiary`/`quaternary` (đều là `gray-700` ở chế độ tối) thì `gray-400`
262
+ chỉ cho **3,96** — dưới chuẩn 4,5 cho chữ 12px.
263
+
264
+ Đo `/banner`: chip `role="banner"` 110×24px, sáng 6,10 đạt mà tối 3,96
265
+ hỏng (BUG-032 §5). Chip đó thừa kế màu từ `text-body` của khung layout,
266
+ KHÔNG dùng `text-body-subtle` — nên phải đổi cả hai, sửa mỗi
267
+ `body-subtle` không chạm tới nó (đã thử, chip vẫn 3,96).
268
+
269
+ `gray-300` đưa hai nền đó lên **7,00** và không kéo nền nào xuống:
270
+ primary 12,05 · secondary 9,96 (trước là 6,82 · 5,64). */
271
+ --text-body: var(--color-gray-300);
272
+ /* `--text-body-subtle` đang bằng HỆT `--text-body` ở nhánh tối, tức "subtle"
273
+ không còn nhạt hơn gì cả. Giữ nguyên tương quan đó ở đây; muốn tách hai
274
+ bậc thì phải đo lại cả bốn nền. */
275
+ --text-body-subtle: var(--color-gray-300);
276
+
277
+ --text-brand: var(--color-brand-400);
278
+ --text-brand-strong: var(--color-brand-300);
279
+ --text-brand-subtle: var(--color-brand-300);
280
+ /* Lật sáng lên ở nền tối, cùng hướng với --text-brand (700 -> 400). */
281
+ --text-brand-medium: var(--color-brand-300);
282
+ --text-brand-soft: var(--color-brand-900);
283
+
284
+ --text-success: var(--color-emerald-600);
285
+ --text-success-strong: var(--color-emerald-300);
286
+ --text-danger: var(--color-rose-500);
287
+ --text-danger-strong: var(--color-rose-300);
288
+ --text-warning: var(--color-yellow-300);
289
+ --text-warning-strong: var(--color-yellow-200);
290
+ --text-warning-subtle: var(--color-yellow-400);
291
+ --text-info: var(--color-brand-300);
292
+ /* Trước đây dark mode thiếu hẳn token này nên rơi về brand-900 của :root
293
+ — gần như đen trên nền tối. */
294
+ --text-info-strong: var(--color-brand-300);
295
+ --text-disabled: var(--color-gray-600);
296
+
297
+ /* 2. Colors / Background - Dark */
298
+ --bg-primary: var(--color-gray-950);
299
+ --bg-primary-soft: var(--color-gray-900);
300
+ --bg-primary-medium: var(--color-gray-800);
301
+ --bg-primary-strong: var(--color-gray-700);
302
+
303
+ --bg-secondary: var(--color-gray-950);
304
+ --bg-secondary-soft: var(--color-gray-900);
305
+ --bg-secondary-medium: var(--color-gray-800);
306
+ --bg-secondary-strong: var(--color-gray-700);
307
+
308
+ /* Tertiary & Quaternary — Figma Modern (dark) dùng thang gray */
309
+ --bg-tertiary: var(--color-gray-800);
310
+ --bg-tertiary-soft: var(--color-gray-900);
311
+ --bg-tertiary-medium: var(--color-gray-700);
312
+ --bg-quaternary: var(--color-gray-700);
313
+ --bg-quaternary-medium: var(--color-gray-600);
314
+
315
+ --bg-brand: var(--color-brand-600);
316
+ --bg-brand-soft: var(--color-brand-900);
317
+ --bg-brand-softer: var(--color-brand-950);
318
+ --bg-brand-medium: var(--color-brand-800);
319
+ --bg-brand-strong: var(--color-brand-700);
320
+
321
+ --bg-dark: var(--color-gray-800);
322
+ --bg-dark-strong: var(--color-gray-700);
323
+ --bg-disabled: var(--color-gray-800);
324
+
325
+ --bg-warning: var(--color-yellow-500);
326
+ --bg-warning-medium: var(--color-yellow-900);
327
+ --bg-warning-strong: var(--color-yellow-600);
328
+ --bg-success: var(--color-emerald-600);
329
+ --bg-success-strong: var(--color-emerald-700);
330
+ --bg-success-soft: var(--color-emerald-950);
331
+ --bg-danger: var(--color-rose-700);
332
+ --bg-danger-strong: var(--color-rose-800);
333
+ --bg-danger-soft: var(--color-rose-950);
334
+
335
+ /* Semantic Palette Backgrounds - Dark
336
+ Lấy thẳng từ collection "Themes" của Figma, mode `Modern (dark)`. Figma
337
+ chia hai nhóm chứ không có một quy luật chung: --bg-danger và --bg-warning
338
+ đi đậm hơn một bậc, còn tám màu bảng phụ dưới đây thì GIỮ NGUYÊN bậc sáng
339
+ (purple, sky, cyan, orange) hoặc NHẠT ĐI một bậc (teal, pink, fuchsia,
340
+ indigo) — nền đặc trên nền tối #030712 đậm thêm sẽ mất tương phản.
341
+ --bg-orange bám sát nhất vì `ol-toggle` Status=Medium bind đúng
342
+ colors/orange/400 ở cả hai mode. */
343
+ --bg-purple: var(--color-purple-500);
344
+ --bg-sky: var(--color-sky-500);
345
+ --bg-teal: var(--color-teal-500);
346
+ --bg-pink: var(--color-pink-500);
347
+ --bg-cyan: var(--color-cyan-500);
348
+ --bg-fuchsia: var(--color-fuchsia-500);
349
+ --bg-indigo: var(--color-indigo-500);
350
+ --bg-orange: var(--color-orange-400);
351
+
352
+ /* 3. Colors / Border - Dark */
353
+ --border-buffer: var(--color-gray-950);
354
+ --border-muted: var(--color-gray-900);
355
+ --border-light-subtle: var(--color-gray-900);
356
+ --border-light: var(--color-gray-800);
357
+ --border-default-subtle: var(--color-gray-900);
358
+ --border-default: var(--color-gray-800);
359
+ --border-default-medium: var(--color-gray-700);
360
+ --border-default-strong: var(--color-gray-600);
361
+
362
+ --border-brand: var(--color-brand-600);
363
+ --border-focus: var(--color-brand-300);
364
+ --bg-focus-ring: var(--color-brand-800);
365
+ --border-brand-subtle: var(--color-brand-800);
366
+ --border-brand-light: var(--color-brand-500);
367
+ --border-success-subtle: var(--color-emerald-900);
368
+ --border-danger-subtle: var(--color-rose-900);
369
+ --border-warning-subtle: var(--color-yellow-900);
370
+ --border-success: var(--color-emerald-600);
371
+ --border-danger: var(--color-rose-600);
372
+ --border-warning: var(--color-yellow-500);
373
+ --border-info: var(--color-brand-600);
374
+
375
+ /* 20 token bổ sung — giá trị mode Modern (dark) của Figma */
376
+ --bg-white: var(--color-white);
377
+ --bg-gray: var(--color-gray-600);
378
+ --bg-danger-medium: var(--color-rose-900);
379
+ --bg-success-medium: var(--color-emerald-900);
380
+ --bg-warning-soft: var(--color-yellow-950);
381
+ --bg-warning-strongest: var(--color-yellow-700);
382
+
383
+ --border-dark: var(--color-gray-600);
384
+ --border-dark-subtle: var(--color-gray-700);
385
+ --border-light-medium: var(--color-gray-700);
386
+ --border-buffer-medium: var(--color-gray-900);
387
+ --border-buffer-strong: var(--color-gray-800);
388
+ --border-buffer-gradient-secondary: var(--color-gray-950);
389
+ --border-orange: var(--color-orange-400);
390
+ --border-purple: var(--color-purple-500);
391
+
392
+ --text-cyan: var(--color-cyan-500);
393
+ --text-indigo: var(--color-indigo-500);
394
+ --text-lime: var(--color-lime-500);
395
+ --text-pink: var(--color-pink-500);
396
+ --text-purple: var(--color-purple-500);
397
+ --text-yellow: var(--color-yellow-400);
398
+ }
399
+
400
+ /* =============================================================================
401
+ THEME: TIỂU HỌC — KHUNG, CHƯA ĐỔ GIÁ TRỊ
402
+
403
+ Bốn theme phụ cũ (`minimal` · `enterprise` · `playful` · `mono`) đã gỡ
404
+ 2026-09-21 theo VIỆC-029: Figma chỉ có Ôn Luyện, code có 5 theme nên 661
405
+ dòng ở đây không ứng với thiết kế nào.
406
+
407
+ Giữ lại đúng CƠ CHẾ `data-theme` cho theme này. Hai khối dưới đây cố ý để
408
+ TRỐNG: đổi sang `tieu-hoc` lúc này thì giao diện y hệt Ôn Luyện, không vỡ
409
+ gì — an toàn để ghép dần.
410
+
411
+ ## Cách đổ giá trị
412
+
413
+ Chỉ override TOKEN NGỮ NGHĨA (`--bg-*`, `--text-*`, `--border-*`,
414
+ `--radius-*`). ĐỪNG override primitive (`--color-brand-700`) — primitive là
415
+ bảng màu gốc dùng chung, sửa nó là đổi cả Ôn Luyện.
416
+
417
+ Mỗi giá trị đặt ở CẢ HAI khối: thiếu khối `.dark` thì theme mới chỉ có chế
418
+ độ sáng, và người dùng bật chế độ tối sẽ rơi về màu Ôn Luyện — lệch nửa
419
+ vời, khó thấy hơn là hỏng hẳn.
420
+
421
+ Hướng thiết kế người dùng đã nêu: "dành cho trẻ con, cần đẹp mắt" — bo góc
422
+ tròn hơn, màu tươi hơn. Chưa có Figma, sẽ dựng bản nháp riêng để duyệt.
423
+ ============================================================================= */
424
+ [data-theme='tieu-hoc'] {
425
+ /* trống — xem chú thích trên */
426
+ }
427
+
428
+ .dark[data-theme='tieu-hoc'],
429
+ [data-theme='tieu-hoc'].dark {
430
+ /* trống — xem chú thích trên */
431
+ }