@geoit/ui 0.0.2 → 0.0.5

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.
Files changed (258) hide show
  1. package/AGENTS.md +12 -8
  2. package/README.md +140 -17
  3. package/ai/AGENTS.md +43 -32
  4. package/ai/README.md +36 -2
  5. package/ai/catalog.json +5585 -437
  6. package/ai/components/geo-alert.md +75 -21
  7. package/ai/components/geo-back-button.md +64 -18
  8. package/ai/components/geo-breadcrumb.md +71 -12
  9. package/ai/components/geo-button.md +90 -27
  10. package/ai/components/geo-chart.md +103 -0
  11. package/ai/components/geo-checkbox.md +67 -20
  12. package/ai/components/geo-column-picker.md +91 -18
  13. package/ai/components/geo-confirm-modal.md +92 -27
  14. package/ai/components/geo-dashboard.md +91 -0
  15. package/ai/components/geo-date-picker.md +105 -29
  16. package/ai/components/geo-date-range-picker.md +101 -28
  17. package/ai/components/geo-empty-state.md +75 -0
  18. package/ai/components/geo-feedback-form.md +97 -0
  19. package/ai/components/geo-file-picker.md +99 -26
  20. package/ai/components/geo-forgot-password.md +78 -0
  21. package/ai/components/geo-form-modal.md +111 -44
  22. package/ai/components/geo-icon.md +70 -16
  23. package/ai/components/geo-input.md +94 -29
  24. package/ai/components/geo-layout-footer.md +70 -0
  25. package/ai/components/geo-layout-header-actions.md +82 -0
  26. package/ai/components/geo-layout-header.md +89 -0
  27. package/ai/components/geo-layout-sidebar.md +86 -0
  28. package/ai/components/geo-layout.md +155 -0
  29. package/ai/components/geo-list-page.md +72 -0
  30. package/ai/components/geo-login.md +94 -0
  31. package/ai/components/geo-map-admin-filter.md +80 -0
  32. package/ai/components/geo-map-basemap-switcher.md +75 -0
  33. package/ai/components/geo-map-help.md +72 -0
  34. package/ai/components/geo-map-layer-card.md +73 -0
  35. package/ai/components/geo-map-layer-panel.md +75 -0
  36. package/ai/components/geo-map-layers-drawer.md +78 -0
  37. package/ai/components/geo-map-legend.md +74 -0
  38. package/ai/components/geo-map-locate.md +75 -0
  39. package/ai/components/geo-map-location-chip.md +71 -0
  40. package/ai/components/geo-map-measure.md +74 -0
  41. package/ai/components/geo-map-opacity.md +75 -0
  42. package/ai/components/geo-map-parcel-popup.md +79 -0
  43. package/ai/components/geo-map-search.md +83 -0
  44. package/ai/components/geo-map-shell.md +110 -0
  45. package/ai/components/geo-map-snapshot.md +75 -0
  46. package/ai/components/geo-map-swipe.md +73 -0
  47. package/ai/components/geo-map-toolbar.md +76 -0
  48. package/ai/components/geo-map-zoom.md +74 -0
  49. package/ai/components/geo-map.md +205 -0
  50. package/ai/components/geo-overlap-result.md +88 -0
  51. package/ai/components/geo-page-header.md +72 -0
  52. package/ai/components/geo-page-title.md +62 -16
  53. package/ai/components/geo-pagination.md +76 -24
  54. package/ai/components/geo-radio.md +110 -27
  55. package/ai/components/geo-row-actions.md +87 -19
  56. package/ai/components/geo-select.md +108 -28
  57. package/ai/components/geo-slider.md +70 -21
  58. package/ai/components/geo-stat-card.md +98 -0
  59. package/ai/components/geo-status-tag.md +67 -15
  60. package/ai/components/geo-step-form-layout.md +121 -38
  61. package/ai/components/geo-stepper.md +81 -19
  62. package/ai/components/geo-table-filter.md +90 -29
  63. package/ai/components/geo-table-pagination.md +70 -23
  64. package/ai/components/geo-table-toolbar.md +84 -29
  65. package/ai/components/geo-table.md +191 -59
  66. package/ai/components/geo-tabs.md +99 -27
  67. package/ai/components/geo-textarea.md +84 -23
  68. package/ai/components/geo-toast.md +138 -27
  69. package/ai/components/geo-tree.md +94 -22
  70. package/ai/components/geo-typography.md +70 -19
  71. package/ai/components/geo-upload.md +109 -39
  72. package/ai/mockup.html +1194 -0
  73. package/ai/recipes.md +132 -47
  74. package/esm2022/lib/figma/geo-alert/geo-alert.component.mjs +19 -36
  75. package/esm2022/lib/figma/geo-back-button/geo-back-button.component.mjs +14 -24
  76. package/esm2022/lib/figma/geo-breadcrumb/geo-breadcrumb.component.mjs +8 -11
  77. package/esm2022/lib/figma/geo-button/geo-button.component.mjs +30 -59
  78. package/esm2022/lib/figma/geo-chart/geo-chart.component.mjs +88 -0
  79. package/esm2022/lib/figma/geo-chart/geo-chart.types.mjs +2 -0
  80. package/esm2022/lib/figma/geo-checkbox/geo-checkbox.component.mjs +11 -22
  81. package/esm2022/lib/figma/geo-confirm-modal/geo-confirm-modal.component.mjs +22 -54
  82. package/esm2022/lib/figma/geo-dashboard/geo-dashboard.component.mjs +49 -0
  83. package/esm2022/lib/figma/geo-dashboard/geo-dashboard.types.mjs +2 -0
  84. package/esm2022/lib/figma/geo-date-picker/geo-date-picker.component.mjs +48 -78
  85. package/esm2022/lib/figma/geo-date-range-picker/geo-date-range-picker.component.mjs +47 -75
  86. package/esm2022/lib/figma/geo-empty-state/geo-empty-state.component.mjs +25 -0
  87. package/esm2022/lib/figma/geo-feedback-form/geo-feedback-form.component.mjs +75 -0
  88. package/esm2022/lib/figma/geo-feedback-form/geo-feedback-form.types.mjs +2 -0
  89. package/esm2022/lib/figma/geo-file-picker/geo-file-picker.component.mjs +59 -81
  90. package/esm2022/lib/figma/geo-forgot-password/geo-forgot-password.component.mjs +51 -0
  91. package/esm2022/lib/figma/geo-form-modal/geo-form-modal.component.mjs +45 -112
  92. package/esm2022/lib/figma/geo-icon/geo-icon.component.mjs +22 -32
  93. package/esm2022/lib/figma/geo-input/geo-input.component.mjs +41 -70
  94. package/esm2022/lib/figma/geo-layout/footer/geo-layout-footer.component.mjs +18 -0
  95. package/esm2022/lib/figma/geo-layout/geo-layout-actions.directive.mjs +15 -0
  96. package/esm2022/lib/figma/geo-layout/geo-layout.component.mjs +79 -0
  97. package/esm2022/lib/figma/geo-layout/geo-layout.types.mjs +42 -0
  98. package/esm2022/lib/figma/geo-layout/header/geo-layout-header.component.mjs +60 -0
  99. package/esm2022/lib/figma/geo-layout/header-actions/geo-layout-header-actions.component.mjs +70 -0
  100. package/esm2022/lib/figma/geo-layout/sidebar/geo-layout-sidebar.component.mjs +90 -0
  101. package/esm2022/lib/figma/geo-list-page/geo-list-page.component.mjs +22 -0
  102. package/esm2022/lib/figma/geo-login/geo-login.component.mjs +58 -0
  103. package/esm2022/lib/figma/geo-login/geo-login.types.mjs +2 -0
  104. package/esm2022/lib/figma/geo-map/chrome/geo-map-admin-filter/geo-map-admin-filter.component.mjs +52 -0
  105. package/esm2022/lib/figma/geo-map/chrome/geo-map-basemap-switcher/geo-map-basemap-switcher.component.mjs +61 -0
  106. package/esm2022/lib/figma/geo-map/chrome/geo-map-help/geo-map-help.component.mjs +26 -0
  107. package/esm2022/lib/figma/geo-map/chrome/geo-map-layer-card/geo-map-layer-card.component.mjs +24 -0
  108. package/esm2022/lib/figma/geo-map/chrome/geo-map-layer-panel/geo-map-layer-panel.component.mjs +146 -0
  109. package/esm2022/lib/figma/geo-map/chrome/geo-map-layers-drawer/geo-map-layers-drawer.component.mjs +37 -0
  110. package/esm2022/lib/figma/geo-map/chrome/geo-map-legend/geo-map-legend.component.mjs +30 -0
  111. package/esm2022/lib/figma/geo-map/chrome/geo-map-locate/geo-map-locate.component.mjs +72 -0
  112. package/esm2022/lib/figma/geo-map/chrome/geo-map-location-chip/geo-map-location-chip.component.mjs +21 -0
  113. package/esm2022/lib/figma/geo-map/chrome/geo-map-measure/geo-map-measure.component.mjs +375 -0
  114. package/esm2022/lib/figma/geo-map/chrome/geo-map-opacity/geo-map-opacity.component.mjs +94 -0
  115. package/esm2022/lib/figma/geo-map/chrome/geo-map-parcel-popup/geo-map-parcel-popup.component.mjs +136 -0
  116. package/esm2022/lib/figma/geo-map/chrome/geo-map-search/geo-map-search.component.mjs +182 -0
  117. package/esm2022/lib/figma/geo-map/chrome/geo-map-shell/geo-map-shell.component.mjs +577 -0
  118. package/esm2022/lib/figma/geo-map/chrome/geo-map-snapshot/geo-map-snapshot.component.mjs +93 -0
  119. package/esm2022/lib/figma/geo-map/chrome/geo-map-swipe/geo-map-swipe.component.mjs +129 -0
  120. package/esm2022/lib/figma/geo-map/chrome/geo-map-toolbar/geo-map-toolbar.component.mjs +64 -0
  121. package/esm2022/lib/figma/geo-map/chrome/geo-map-zoom/geo-map-zoom.component.mjs +295 -0
  122. package/esm2022/lib/figma/geo-map/geo-map-toolbar.icons.mjs +18 -0
  123. package/esm2022/lib/figma/geo-map/geo-map.component.mjs +144 -0
  124. package/esm2022/lib/figma/geo-map/geo-map.constants.mjs +497 -0
  125. package/esm2022/lib/figma/geo-map/geo-map.controller.mjs +71 -0
  126. package/esm2022/lib/figma/geo-map/geo-map.types.mjs +2 -0
  127. package/esm2022/lib/figma/geo-map/services/geo-map-layer.service.mjs +368 -0
  128. package/esm2022/lib/figma/geo-map/services/geo-map-projection.service.mjs +110 -0
  129. package/esm2022/lib/figma/geo-map/services/geo-map.service.mjs +540 -0
  130. package/esm2022/lib/figma/geo-map/utils/geo-map-fullscreen-overlay.util.mjs +47 -0
  131. package/esm2022/lib/figma/geo-map/utils/geo-map-interactions.util.mjs +30 -0
  132. package/esm2022/lib/figma/geo-overlap-result/geo-overlap-result.component.mjs +25 -0
  133. package/esm2022/lib/figma/geo-overlap-result/geo-overlap-result.types.mjs +2 -0
  134. package/esm2022/lib/figma/geo-page-header/geo-page-header.component.mjs +23 -0
  135. package/esm2022/lib/figma/geo-page-title/geo-page-title.component.mjs +20 -35
  136. package/esm2022/lib/figma/geo-pagination/geo-pagination.component.mjs +13 -43
  137. package/esm2022/lib/figma/geo-radio/geo-radio.component.mjs +32 -52
  138. package/esm2022/lib/figma/geo-select/geo-select.component.mjs +46 -72
  139. package/esm2022/lib/figma/geo-slider/geo-slider.component.mjs +12 -28
  140. package/esm2022/lib/figma/geo-stat-card/geo-stat-card.component.mjs +163 -0
  141. package/esm2022/lib/figma/geo-stat-card/geo-stat-card.types.mjs +2 -0
  142. package/esm2022/lib/figma/geo-status-tag/geo-status-tag.component.mjs +23 -27
  143. package/esm2022/lib/figma/geo-step-form-layout/geo-step-form-layout.component.mjs +39 -96
  144. package/esm2022/lib/figma/geo-stepper/geo-stepper.component.mjs +18 -33
  145. package/esm2022/lib/figma/geo-table/geo-column-picker/geo-column-picker.component.mjs +14 -24
  146. package/esm2022/lib/figma/geo-table/geo-row-actions/geo-row-actions.component.mjs +18 -36
  147. package/esm2022/lib/figma/geo-table/geo-table-filter/geo-table-filter.component.mjs +41 -98
  148. package/esm2022/lib/figma/geo-table/geo-table-pagination/geo-table-pagination.component.mjs +40 -73
  149. package/esm2022/lib/figma/geo-table/geo-table-toolbar/geo-table-toolbar.component.mjs +26 -56
  150. package/esm2022/lib/figma/geo-table/geo-table.component.mjs +110 -210
  151. package/esm2022/lib/figma/geo-tabs/geo-tabs.component.mjs +33 -63
  152. package/esm2022/lib/figma/geo-textarea/geo-textarea.component.mjs +28 -44
  153. package/esm2022/lib/figma/geo-toast/geo-toast.component.mjs +18 -39
  154. package/esm2022/lib/figma/geo-tree/geo-tree.component.mjs +12 -40
  155. package/esm2022/lib/figma/geo-typography/geo-typography.component.mjs +49 -64
  156. package/esm2022/lib/figma/geo-upload/geo-upload.component.mjs +50 -101
  157. package/esm2022/lib/figma/index.mjs +50 -1
  158. package/esm2022/lib/styles/tokens.mjs +56 -24
  159. package/fesm2022/geoit-ui.mjs +5981 -1825
  160. package/fesm2022/geoit-ui.mjs.map +1 -1
  161. package/lib/figma/geo-alert/geo-alert.component.d.ts +10 -11
  162. package/lib/figma/geo-back-button/geo-back-button.component.d.ts +6 -7
  163. package/lib/figma/geo-breadcrumb/geo-breadcrumb.component.d.ts +2 -2
  164. package/lib/figma/geo-button/geo-button.component.d.ts +21 -17
  165. package/lib/figma/geo-chart/geo-chart.component.d.ts +40 -0
  166. package/lib/figma/geo-chart/geo-chart.types.d.ts +13 -0
  167. package/lib/figma/geo-checkbox/geo-checkbox.component.d.ts +6 -7
  168. package/lib/figma/geo-confirm-modal/geo-confirm-modal.component.d.ts +15 -17
  169. package/lib/figma/geo-dashboard/geo-dashboard.component.d.ts +29 -0
  170. package/lib/figma/geo-dashboard/geo-dashboard.types.d.ts +7 -0
  171. package/lib/figma/geo-date-picker/geo-date-picker.component.d.ts +26 -21
  172. package/lib/figma/geo-date-range-picker/geo-date-range-picker.component.d.ts +25 -20
  173. package/lib/figma/geo-empty-state/geo-empty-state.component.d.ts +17 -0
  174. package/lib/figma/geo-feedback-form/geo-feedback-form.component.d.ts +36 -0
  175. package/lib/figma/geo-feedback-form/geo-feedback-form.types.d.ts +8 -0
  176. package/lib/figma/geo-file-picker/geo-file-picker.component.d.ts +23 -20
  177. package/lib/figma/geo-forgot-password/geo-forgot-password.component.d.ts +24 -0
  178. package/lib/figma/geo-form-modal/geo-form-modal.component.d.ts +33 -35
  179. package/lib/figma/geo-icon/geo-icon.component.d.ts +7 -7
  180. package/lib/figma/geo-input/geo-input.component.d.ts +23 -21
  181. package/lib/figma/geo-layout/footer/geo-layout-footer.component.d.ts +10 -0
  182. package/lib/figma/geo-layout/geo-layout-actions.directive.d.ts +6 -0
  183. package/lib/figma/geo-layout/geo-layout.component.d.ts +48 -0
  184. package/lib/figma/geo-layout/geo-layout.types.d.ts +44 -0
  185. package/lib/figma/geo-layout/header/geo-layout-header.component.d.ts +31 -0
  186. package/lib/figma/geo-layout/header-actions/geo-layout-header-actions.component.d.ts +32 -0
  187. package/lib/figma/geo-layout/sidebar/geo-layout-sidebar.component.d.ts +34 -0
  188. package/lib/figma/geo-list-page/geo-list-page.component.d.ts +16 -0
  189. package/lib/figma/geo-login/geo-login.component.d.ts +27 -0
  190. package/lib/figma/geo-login/geo-login.types.d.ts +6 -0
  191. package/lib/figma/geo-map/chrome/geo-map-admin-filter/geo-map-admin-filter.component.d.ts +28 -0
  192. package/lib/figma/geo-map/chrome/geo-map-basemap-switcher/geo-map-basemap-switcher.component.d.ts +26 -0
  193. package/lib/figma/geo-map/chrome/geo-map-help/geo-map-help.component.d.ts +20 -0
  194. package/lib/figma/geo-map/chrome/geo-map-layer-card/geo-map-layer-card.component.d.ts +15 -0
  195. package/lib/figma/geo-map/chrome/geo-map-layer-panel/geo-map-layer-panel.component.d.ts +40 -0
  196. package/lib/figma/geo-map/chrome/geo-map-layers-drawer/geo-map-layers-drawer.component.d.ts +25 -0
  197. package/lib/figma/geo-map/chrome/geo-map-legend/geo-map-legend.component.d.ts +18 -0
  198. package/lib/figma/geo-map/chrome/geo-map-locate/geo-map-locate.component.d.ts +24 -0
  199. package/lib/figma/geo-map/chrome/geo-map-location-chip/geo-map-location-chip.component.d.ts +14 -0
  200. package/lib/figma/geo-map/chrome/geo-map-measure/geo-map-measure.component.d.ts +49 -0
  201. package/lib/figma/geo-map/chrome/geo-map-opacity/geo-map-opacity.component.d.ts +30 -0
  202. package/lib/figma/geo-map/chrome/geo-map-parcel-popup/geo-map-parcel-popup.component.d.ts +44 -0
  203. package/lib/figma/geo-map/chrome/geo-map-search/geo-map-search.component.d.ts +56 -0
  204. package/lib/figma/geo-map/chrome/geo-map-shell/geo-map-shell.component.d.ts +103 -0
  205. package/lib/figma/geo-map/chrome/geo-map-snapshot/geo-map-snapshot.component.d.ts +21 -0
  206. package/lib/figma/geo-map/chrome/geo-map-swipe/geo-map-swipe.component.d.ts +33 -0
  207. package/lib/figma/geo-map/chrome/geo-map-toolbar/geo-map-toolbar.component.d.ts +30 -0
  208. package/lib/figma/geo-map/chrome/geo-map-zoom/geo-map-zoom.component.d.ts +67 -0
  209. package/lib/figma/geo-map/geo-map-toolbar.icons.d.ts +17 -0
  210. package/lib/figma/geo-map/geo-map.component.d.ts +53 -0
  211. package/lib/figma/geo-map/geo-map.constants.d.ts +73 -0
  212. package/lib/figma/geo-map/geo-map.controller.d.ts +49 -0
  213. package/lib/figma/geo-map/geo-map.types.d.ts +224 -0
  214. package/lib/figma/geo-map/services/geo-map-layer.service.d.ts +42 -0
  215. package/lib/figma/geo-map/services/geo-map-projection.service.d.ts +32 -0
  216. package/lib/figma/geo-map/services/geo-map.service.d.ts +99 -0
  217. package/lib/figma/geo-map/utils/geo-map-fullscreen-overlay.util.d.ts +13 -0
  218. package/lib/figma/geo-map/utils/geo-map-interactions.util.d.ts +9 -0
  219. package/lib/figma/geo-overlap-result/geo-overlap-result.component.d.ts +18 -0
  220. package/lib/figma/geo-overlap-result/geo-overlap-result.types.d.ts +7 -0
  221. package/lib/figma/geo-page-header/geo-page-header.component.d.ts +16 -0
  222. package/lib/figma/geo-page-title/geo-page-title.component.d.ts +9 -9
  223. package/lib/figma/geo-pagination/geo-pagination.component.d.ts +9 -14
  224. package/lib/figma/geo-radio/geo-radio.component.d.ts +17 -15
  225. package/lib/figma/geo-select/geo-select.component.d.ts +24 -19
  226. package/lib/figma/geo-slider/geo-slider.component.d.ts +7 -9
  227. package/lib/figma/geo-stat-card/geo-stat-card.component.d.ts +50 -0
  228. package/lib/figma/geo-stat-card/geo-stat-card.types.d.ts +11 -0
  229. package/lib/figma/geo-status-tag/geo-status-tag.component.d.ts +7 -7
  230. package/lib/figma/geo-step-form-layout/geo-step-form-layout.component.d.ts +27 -29
  231. package/lib/figma/geo-stepper/geo-stepper.component.d.ts +6 -8
  232. package/lib/figma/geo-table/geo-column-picker/geo-column-picker.component.d.ts +6 -7
  233. package/lib/figma/geo-table/geo-row-actions/geo-row-actions.component.d.ts +11 -12
  234. package/lib/figma/geo-table/geo-table-filter/geo-table-filter.component.d.ts +21 -28
  235. package/lib/figma/geo-table/geo-table-pagination/geo-table-pagination.component.d.ts +17 -20
  236. package/lib/figma/geo-table/geo-table-toolbar/geo-table-toolbar.component.d.ts +17 -18
  237. package/lib/figma/geo-table/geo-table.component.d.ts +58 -62
  238. package/lib/figma/geo-tabs/geo-tabs.component.d.ts +14 -17
  239. package/lib/figma/geo-textarea/geo-textarea.component.d.ts +15 -13
  240. package/lib/figma/geo-toast/geo-toast.component.d.ts +11 -12
  241. package/lib/figma/geo-tree/geo-tree.component.d.ts +8 -13
  242. package/lib/figma/geo-typography/geo-typography.component.d.ts +13 -13
  243. package/lib/figma/geo-upload/geo-upload.component.d.ts +26 -28
  244. package/lib/figma/index.d.ts +49 -0
  245. package/lib/styles/tokens.d.ts +56 -23
  246. package/package.json +4 -2
  247. package/src/lib/figma/geo-map/assets/toolbar/fullscreen.svg +8 -0
  248. package/src/lib/figma/geo-map/assets/toolbar/home.svg +3 -0
  249. package/src/lib/figma/geo-map/assets/toolbar/layers.svg +3 -0
  250. package/src/lib/figma/geo-map/assets/toolbar/measure-area.svg +12 -0
  251. package/src/lib/figma/geo-map/assets/toolbar/measure-distance.svg +5 -0
  252. package/src/lib/figma/geo-map/assets/toolbar/pan.svg +13 -0
  253. package/src/lib/figma/geo-map/assets/toolbar/search.svg +3 -0
  254. package/src/lib/figma/geo-map/assets/toolbar/zoom-in.svg +3 -0
  255. package/src/lib/figma/geo-map/assets/toolbar/zoom-out.svg +5 -0
  256. package/src/lib/styles/design-tokens.scss +108 -35
  257. package/src/lib/styles/scrollbar.scss +2 -2
  258. package/src/lib/styles/theme.scss +1 -1
package/ai/mockup.html ADDED
@@ -0,0 +1,1194 @@
1
+ <!DOCTYPE html>
2
+ <html lang="vi">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
6
+ <title>@geoit/ui — Component mockup (design tokens)</title>
7
+ <!-- Generated by tools/generate-mockup.js — do not edit ai/mockup.html by hand -->
8
+ <!-- 2026-08-24T03:07:52.146Z -->
9
+ <link rel="preconnect" href="https://fonts.googleapis.com" />
10
+ <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
11
+ <link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet" />
12
+ <style>
13
+ /* —— GEO design tokens (injected from design-tokens.scss) —— */
14
+ :root {
15
+ /* ——— Primary (brand) ——— */
16
+ --geo-color-primary-default: #9a4828;
17
+ --geo-color-primary-hover: #7d3a20;
18
+ --geo-color-primary-light: #b5643f;
19
+ --geo-color-primary-dark: #2c1810;
20
+ --geo-color-primary-background: #faf6f2;
21
+ --geo-color-primary-background-alt: #f4efe9;
22
+ --geo-color-primary-border: #e7dfd6;
23
+ --geo-color-primary-surface-light: #f7e8e0;
24
+ --geo-color-primary-secondary-hover: #faf6f2;
25
+
26
+ /* Soft primary fills (active menu, icon hover, focus rings) */
27
+ --geo-color-primary-soft: color-mix(
28
+ in srgb,
29
+ var(--geo-color-primary-default) 6%,
30
+ transparent
31
+ );
32
+ --geo-color-primary-soft-hover: color-mix(
33
+ in srgb,
34
+ var(--geo-color-primary-default) 8%,
35
+ transparent
36
+ );
37
+ --geo-color-primary-soft-active: color-mix(
38
+ in srgb,
39
+ var(--geo-color-primary-default) 10%,
40
+ transparent
41
+ );
42
+ --geo-color-primary-soft-strong: color-mix(
43
+ in srgb,
44
+ var(--geo-color-primary-default) 14%,
45
+ transparent
46
+ );
47
+ --geo-color-primary-focus-ring: color-mix(
48
+ in srgb,
49
+ var(--geo-color-primary-default) 18%,
50
+ transparent
51
+ );
52
+
53
+ /* ——— Neutral (slightly warm, pairs with brand) ——— */
54
+ --geo-color-neutral-900: #16141f;
55
+ --geo-color-neutral-800: #23212a;
56
+ --geo-color-neutral-700: #3d3a45;
57
+ --geo-color-neutral-600: #565360;
58
+ --geo-color-neutral-500: #6f6b78;
59
+ --geo-color-neutral-400: #9894a0;
60
+ --geo-color-neutral-300: #cdc9d2;
61
+ --geo-color-neutral-200: #e6e3ea;
62
+ --geo-color-neutral-100: #f4f3f6;
63
+ --geo-color-neutral-50: #faf9fb;
64
+ --geo-color-neutral-white: #ffffff;
65
+ --geo-color-neutral-disabled-text: #8f8c96;
66
+
67
+ /* ——— Semantic surfaces ——— */
68
+ --geo-color-surface-page: var(--geo-color-neutral-100);
69
+ --geo-color-surface-elevated: var(--geo-color-neutral-white);
70
+ --geo-color-surface-header: color-mix(
71
+ in srgb,
72
+ var(--geo-color-neutral-white) 92%,
73
+ transparent
74
+ );
75
+ --geo-color-surface-muted: var(--geo-color-neutral-100);
76
+ --geo-color-surface-subtle: var(--geo-color-neutral-50);
77
+ --geo-color-border-default: var(--geo-color-neutral-200);
78
+ --geo-color-border-strong: var(--geo-color-neutral-300);
79
+ --geo-color-border-subtle: color-mix(
80
+ in srgb,
81
+ var(--geo-color-neutral-200) 70%,
82
+ transparent
83
+ );
84
+
85
+ /* ——— Status ——— */
86
+ --geo-color-success-dark: #166534;
87
+ --geo-color-success-default: #16a34a;
88
+ --geo-color-success-light: #dcfce7;
89
+
90
+ --geo-color-error-dark: #991b1b;
91
+ --geo-color-error-default: #dc2626;
92
+ --geo-color-error-light: #fee2e2;
93
+
94
+ --geo-color-warning-dark: #92400e;
95
+ --geo-color-warning-default: #d97706;
96
+ --geo-color-warning-light: #fef3c7;
97
+
98
+ --geo-color-info-dark: #1e40af;
99
+ --geo-color-info-default: #2563eb;
100
+ --geo-color-info-light: #dbeafe;
101
+
102
+ --geo-color-teal-dark: #0f766e;
103
+ --geo-color-teal-default: #0d9488;
104
+ --geo-color-teal-light: #ccfbf1;
105
+
106
+ /* ——— Shadows (tint toward neutral, not pure black) ——— */
107
+ --geo-shadow-xs: 0 1px 2px
108
+ color-mix(in srgb, var(--geo-color-neutral-900) 5%, transparent);
109
+ --geo-shadow-sm: 0 2px 8px
110
+ color-mix(in srgb, var(--geo-color-neutral-900) 6%, transparent);
111
+ --geo-shadow-md:
112
+ 0 8px 24px color-mix(in srgb, var(--geo-color-neutral-900) 8%, transparent),
113
+ 0 2px 6px color-mix(in srgb, var(--geo-color-neutral-900) 4%, transparent);
114
+ --geo-shadow-lg:
115
+ 0 12px 32px color-mix(in srgb, var(--geo-color-neutral-900) 10%, transparent),
116
+ 0 2px 8px color-mix(in srgb, var(--geo-color-neutral-900) 4%, transparent);
117
+ --geo-shadow-drawer: 8px 0 24px
118
+ color-mix(in srgb, var(--geo-color-neutral-900) 8%, transparent);
119
+
120
+ /* ——— Semantic aliases (legacy-friendly) ——— */
121
+ --color-primary: var(--geo-color-primary-default);
122
+ --color-primary-hover: var(--geo-color-primary-hover);
123
+ --color-primary-dark: var(--geo-color-primary-dark);
124
+ --color-primary-light: var(--geo-color-primary-light);
125
+ --color-primary-surface: var(--geo-color-primary-surface-light);
126
+ --color-primary-surface-hover: var(--geo-color-primary-background);
127
+ --color-primary-secondary-hover: var(--geo-color-primary-secondary-hover);
128
+ --color-primary-border: var(--geo-color-primary-border);
129
+ --color-primary-background: var(--geo-color-primary-background);
130
+ --color-primary-background-alt: var(--geo-color-primary-background-alt);
131
+ --color-primary-alpha-6: var(--geo-color-primary-soft);
132
+ --color-primary-alpha-8: var(--geo-color-primary-soft-hover);
133
+ --color-primary-alpha-10: var(--geo-color-primary-soft-active);
134
+ --color-primary-alpha-12: var(--geo-color-primary-soft-strong);
135
+
136
+ --color-ink: var(--geo-color-neutral-900);
137
+ --color-ink-strong: var(--geo-color-neutral-900);
138
+ --color-ink-body: var(--geo-color-neutral-700);
139
+ --color-ink-muted: var(--geo-color-neutral-500);
140
+ --color-ink-subtle: var(--geo-color-neutral-400);
141
+ --color-disabled-text: var(--geo-color-neutral-disabled-text);
142
+
143
+ --color-surface-white: var(--geo-color-neutral-white);
144
+ --color-surface-muted: var(--geo-color-neutral-100);
145
+ --color-surface-border: var(--geo-color-neutral-200);
146
+ --color-surface-divider: var(--geo-color-neutral-100);
147
+ --color-surface-header: var(--geo-color-surface-header);
148
+ --color-border: var(--geo-color-neutral-300);
149
+ --color-border-subtle: var(--geo-color-primary-border);
150
+
151
+ --color-success: var(--geo-color-success-default);
152
+ --color-success-dark: var(--geo-color-success-dark);
153
+ --color-success-light: var(--geo-color-success-light);
154
+
155
+ --color-error: var(--geo-color-error-default);
156
+ --color-error-dark: var(--geo-color-error-dark);
157
+ --color-error-light: var(--geo-color-error-light);
158
+ --color-danger: var(--geo-color-error-default);
159
+ --color-danger-dark: var(--geo-color-error-dark);
160
+ --color-danger-light: var(--geo-color-error-light);
161
+
162
+ --color-warning: var(--geo-color-warning-default);
163
+ --color-warning-dark: var(--geo-color-warning-dark);
164
+ --color-warning-light: var(--geo-color-warning-light);
165
+
166
+ --color-info: var(--geo-color-info-default);
167
+ --color-info-dark: var(--geo-color-info-dark);
168
+ --color-info-light: var(--geo-color-info-light);
169
+
170
+ --color-teal: var(--geo-color-teal-default);
171
+ --color-teal-dark: var(--geo-color-teal-dark);
172
+ --color-teal-light: var(--geo-color-teal-light);
173
+
174
+ /* ——— Radius scale (layout-aligned) ———
175
+ * Controls/buttons → --geo-radius (8px)
176
+ * Icon btns / chips → --geo-radius-md (10px)
177
+ * Cards / user chip → --geo-radius-lg (12px)
178
+ * Popovers → --geo-radius-xl (14px)
179
+ */
180
+ --geo-radius-xs: 4px;
181
+ --geo-radius-sm: 6px;
182
+ --geo-radius: 8px;
183
+ --geo-radius-md: 10px;
184
+ --geo-radius-lg: 12px;
185
+ --geo-radius-xl: 14px;
186
+ --geo-radius-2xl: 16px;
187
+ --geo-radius-full: 999px;
188
+ --geo-control-height: 40px;
189
+
190
+ /* ——— Typography — Inter + type scale ——— */
191
+ --geo-font-family: 'Inter', system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;
192
+ --geo-font-weight-regular: 400;
193
+ --geo-font-weight-medium: 500;
194
+ --geo-font-weight-semibold: 600;
195
+ --geo-font-weight-bold: 700;
196
+
197
+ --geo-font-size-h1: 28px;
198
+ --geo-line-height-h1: 36px;
199
+ --geo-font-size-h2: 24px;
200
+ --geo-line-height-h2: 32px;
201
+ --geo-font-size-h3: 20px;
202
+ --geo-line-height-h3: 28px;
203
+ --geo-font-size-h4: 16px;
204
+ --geo-line-height-h4: 24px;
205
+ --geo-font-size-subtitle: 14px;
206
+ --geo-line-height-subtitle: 20px;
207
+ --geo-font-size-body: 14px;
208
+ --geo-line-height-body: 20px;
209
+ --geo-font-size-body-small: 13px;
210
+ --geo-line-height-body-small: 18px;
211
+ --geo-font-size-caption: 12px;
212
+ --geo-line-height-caption: 16px;
213
+ --geo-font-size-overline: 11px;
214
+ --geo-line-height-overline: 16px;
215
+ --geo-font-size-tiny: 10px;
216
+ --geo-line-height-tiny: 14px;
217
+
218
+ /* Legacy size aliases */
219
+ --geo-font-size-sm: var(--geo-font-size-body-small);
220
+ --geo-font-size-md: var(--geo-font-size-body);
221
+ --geo-font-size-lg: var(--geo-font-size-h4);
222
+
223
+ }
224
+
225
+ * { box-sizing: border-box; }
226
+ html { scroll-behavior: smooth; }
227
+ body {
228
+ margin: 0;
229
+ font-family: var(--geo-font-family);
230
+ font-size: var(--geo-font-size-body);
231
+ line-height: var(--geo-line-height-body);
232
+ color: var(--geo-color-neutral-900);
233
+ background:
234
+ radial-gradient(1200px 600px at 10% -10%, color-mix(in srgb, var(--geo-color-primary-default) 10%, transparent), transparent 60%),
235
+ linear-gradient(180deg, var(--geo-color-primary-background) 0%, var(--geo-color-neutral-100) 28%, var(--geo-color-neutral-100) 100%);
236
+ min-height: 100vh;
237
+ }
238
+
239
+ /* —— Page chrome —— */
240
+ .page {
241
+ display: grid;
242
+ grid-template-columns: 240px 1fr;
243
+ min-height: 100vh;
244
+ }
245
+ .nav {
246
+ position: sticky;
247
+ top: 0;
248
+ height: 100vh;
249
+ overflow: auto;
250
+ padding: 24px 16px;
251
+ background: color-mix(in srgb, var(--geo-color-neutral-white) 88%, transparent);
252
+ backdrop-filter: blur(10px);
253
+ border-right: 1px solid var(--geo-color-primary-border);
254
+ }
255
+ .nav__brand {
256
+ font-size: var(--geo-font-size-h4);
257
+ font-weight: var(--geo-font-weight-bold);
258
+ color: var(--geo-color-primary-default);
259
+ margin: 0 0 4px;
260
+ }
261
+ .nav__sub {
262
+ font-size: var(--geo-font-size-caption);
263
+ color: var(--geo-color-neutral-500);
264
+ margin: 0 0 20px;
265
+ }
266
+ .nav a {
267
+ display: block;
268
+ padding: 6px 10px;
269
+ border-radius: var(--geo-radius);
270
+ color: var(--geo-color-neutral-700);
271
+ text-decoration: none;
272
+ font-size: var(--geo-font-size-body-small);
273
+ }
274
+ .nav a:hover {
275
+ background: var(--geo-color-primary-surface-light);
276
+ color: var(--geo-color-primary-default);
277
+ }
278
+ .main { padding: 32px 40px 80px; max-width: 1100px; }
279
+ .hero { margin-bottom: 32px; }
280
+ .hero h1 {
281
+ margin: 0 0 8px;
282
+ font-size: var(--geo-font-size-h1);
283
+ line-height: var(--geo-line-height-h1);
284
+ font-weight: var(--geo-font-weight-bold);
285
+ }
286
+ .hero p {
287
+ margin: 0;
288
+ color: var(--geo-color-neutral-500);
289
+ max-width: 62ch;
290
+ }
291
+ .section {
292
+ margin-bottom: 40px;
293
+ scroll-margin-top: 24px;
294
+ }
295
+ .section__head {
296
+ display: flex;
297
+ align-items: baseline;
298
+ justify-content: space-between;
299
+ gap: 12px;
300
+ margin-bottom: 16px;
301
+ padding-bottom: 10px;
302
+ border-bottom: 1px solid var(--geo-color-neutral-200);
303
+ }
304
+ .section__head h2 {
305
+ margin: 0;
306
+ font-size: var(--geo-font-size-h3);
307
+ line-height: var(--geo-line-height-h3);
308
+ }
309
+ .section__head code {
310
+ font-size: var(--geo-font-size-caption);
311
+ color: var(--geo-color-primary-default);
312
+ background: var(--geo-color-primary-surface-light);
313
+ padding: 2px 8px;
314
+ border-radius: 999px;
315
+ }
316
+ .row { display: flex; flex-wrap: wrap; gap: 12px; align-items: center; }
317
+ .stack { display: flex; flex-direction: column; gap: 12px; }
318
+ .grid-2 {
319
+ display: grid;
320
+ grid-template-columns: 1fr 1fr;
321
+ gap: 16px;
322
+ }
323
+ @media (max-width: 900px) {
324
+ .page { grid-template-columns: 1fr; }
325
+ .nav { position: relative; height: auto; border-right: none; border-bottom: 1px solid var(--geo-color-primary-border); }
326
+ .grid-2 { grid-template-columns: 1fr; }
327
+ .main { padding: 24px 16px 64px; }
328
+ }
329
+ .panel {
330
+ background: var(--geo-color-neutral-white);
331
+ border: 1px solid var(--geo-color-neutral-200);
332
+ border-radius: var(--geo-radius);
333
+ padding: 20px;
334
+ }
335
+ .note {
336
+ font-size: var(--geo-font-size-caption);
337
+ color: var(--geo-color-neutral-500);
338
+ margin-top: 10px;
339
+ }
340
+
341
+ /* —— Tokens swatches —— */
342
+ .swatches { display: flex; flex-wrap: wrap; gap: 10px; }
343
+ .swatch {
344
+ width: 88px;
345
+ border-radius: var(--geo-radius);
346
+ overflow: hidden;
347
+ border: 1px solid var(--geo-color-neutral-200);
348
+ background: var(--geo-color-neutral-white);
349
+ }
350
+ .swatch__chip { height: 40px; }
351
+ .swatch__meta { padding: 6px 8px; font-size: 10px; color: var(--geo-color-neutral-500); }
352
+
353
+ /* —— Typography —— */
354
+ .typo-h1 { font-size: var(--geo-font-size-h1); line-height: var(--geo-line-height-h1); font-weight: 700; margin: 0; }
355
+ .typo-h2 { font-size: var(--geo-font-size-h2); line-height: var(--geo-line-height-h2); font-weight: 700; margin: 0; }
356
+ .typo-h3 { font-size: var(--geo-font-size-h3); line-height: var(--geo-line-height-h3); font-weight: 700; margin: 0; }
357
+ .typo-h4 { font-size: var(--geo-font-size-h4); line-height: var(--geo-line-height-h4); font-weight: 700; margin: 0; }
358
+ .typo-body { font-size: var(--geo-font-size-body); line-height: var(--geo-line-height-body); margin: 0; }
359
+ .typo-caption { font-size: var(--geo-font-size-caption); line-height: var(--geo-line-height-caption); margin: 0; }
360
+ .typo-secondary { color: var(--geo-color-neutral-500); }
361
+ .typo-primary { color: var(--geo-color-primary-default); }
362
+ .typo-danger { color: var(--geo-color-error-default); }
363
+ .typo-success { color: var(--geo-color-success-dark); }
364
+
365
+ /* —— geo-page-title —— */
366
+ .geo-page-title { display: flex; flex-direction: column; align-items: flex-start; gap: 8px; }
367
+ .geo-page-title--uppercase { text-transform: uppercase; letter-spacing: 0.02em; }
368
+ .geo-page-title__accent {
369
+ width: 56px; height: 4px; border-radius: 2px;
370
+ background: var(--geo-color-primary-default);
371
+ }
372
+
373
+ /* —— geo-breadcrumb —— */
374
+ .geo-breadcrumb { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; font-size: 14px; }
375
+ .geo-breadcrumb a { color: var(--geo-color-neutral-500); text-decoration: none; }
376
+ .geo-breadcrumb a:hover { color: var(--geo-color-primary-default); }
377
+ .geo-breadcrumb__sep { color: var(--geo-color-neutral-300); }
378
+ .geo-breadcrumb__current { color: var(--geo-color-primary-default); font-weight: 500; }
379
+
380
+ /* —— geo-back-button —— */
381
+ .geo-back-button {
382
+ display: inline-flex; align-items: center; gap: 8px;
383
+ height: 32px; padding: 0 8px; border: none; background: transparent;
384
+ color: var(--geo-color-neutral-700); cursor: pointer; border-radius: var(--geo-radius);
385
+ font-family: inherit; font-size: 14px;
386
+ }
387
+ .geo-back-button:hover { background: var(--geo-color-neutral-100); color: var(--geo-color-primary-default); }
388
+
389
+ /* —— geo-button —— */
390
+ .geo-button {
391
+ display: inline-flex; align-items: center; justify-content: center; gap: 6px;
392
+ height: var(--geo-control-height); min-height: var(--geo-control-height);
393
+ padding: 0 16px; border-radius: var(--geo-radius); border: 1px solid transparent;
394
+ font-size: var(--geo-font-size-body-small); font-weight: 500; font-family: inherit;
395
+ cursor: pointer; white-space: nowrap;
396
+ transition: background-color .15s, border-color .15s, color .15s;
397
+ --geo-btn-tone: var(--geo-color-primary-default);
398
+ --geo-btn-tone-dark: var(--geo-color-primary-hover);
399
+ --geo-btn-tone-surface: var(--geo-color-primary-surface-light);
400
+ --geo-btn-secondary-hover: var(--geo-color-primary-secondary-hover);
401
+ }
402
+ .geo-button--brand { --geo-btn-tone: var(--geo-color-primary-default); --geo-btn-tone-dark: var(--geo-color-primary-hover); --geo-btn-tone-surface: var(--geo-color-primary-surface-light); --geo-btn-secondary-hover: var(--geo-color-primary-secondary-hover); }
403
+ .geo-button--danger { --geo-btn-tone: var(--geo-color-error-default); --geo-btn-tone-dark: var(--geo-color-error-dark); --geo-btn-tone-surface: var(--geo-color-error-light); --geo-btn-secondary-hover: var(--geo-color-error-light); }
404
+ .geo-button--warning { --geo-btn-tone: var(--geo-color-warning-default); --geo-btn-tone-dark: var(--geo-color-warning-dark); --geo-btn-tone-surface: var(--geo-color-warning-light); --geo-btn-secondary-hover: var(--geo-color-warning-light); }
405
+ .geo-button--success { --geo-btn-tone: var(--geo-color-success-default); --geo-btn-tone-dark: var(--geo-color-success-dark); --geo-btn-tone-surface: var(--geo-color-success-light); --geo-btn-secondary-hover: var(--geo-color-success-light); }
406
+ .geo-button--primary { background: var(--geo-btn-tone); border-color: var(--geo-btn-tone); color: #fff; }
407
+ .geo-button--primary:hover { background: var(--geo-btn-tone-dark); border-color: var(--geo-btn-tone-dark); }
408
+ .geo-button--secondary { background: #fff; border-color: var(--geo-btn-tone); color: var(--geo-btn-tone); }
409
+ .geo-button--secondary:hover { background: var(--geo-btn-secondary-hover); }
410
+ .geo-button--tertiary { background: transparent; border-color: transparent; color: var(--geo-btn-tone); }
411
+ .geo-button--tertiary:hover { background: var(--geo-btn-tone-surface); }
412
+ .geo-button:disabled { background: var(--geo-color-neutral-300); border-color: var(--geo-color-neutral-300); color: var(--geo-color-neutral-disabled-text); cursor: not-allowed; }
413
+ .geo-button--icon-only { width: var(--geo-control-height); min-width: var(--geo-control-height); padding: 0; }
414
+ .geo-button__icon { width: 16px; height: 16px; display: inline-flex; }
415
+
416
+ /* —— Form field —— */
417
+ .geo-field { display: flex; flex-direction: column; gap: 8px; width: 100%; }
418
+ .geo-field__label { display: inline-flex; gap: 4px; font-size: 14px; }
419
+ .geo-field__req { color: var(--geo-color-error-default); }
420
+ .geo-field__control {
421
+ display: flex; align-items: center; gap: 10px;
422
+ min-height: 40px; height: 40px; padding: 8px;
423
+ border: 1px solid var(--geo-color-neutral-300); border-radius: var(--geo-radius);
424
+ background: transparent; transition: border-color .15s, box-shadow .15s;
425
+ }
426
+ .geo-field__control:hover { border-color: var(--geo-color-primary-default); }
427
+ .geo-field__control:focus-within {
428
+ border-color: var(--geo-color-primary-default);
429
+ box-shadow: 0 0 0 2px color-mix(in srgb, var(--geo-color-primary-default) 12%, transparent);
430
+ }
431
+ .geo-field__control--error { border-color: var(--geo-color-error-default) !important; }
432
+ .geo-field__control input,
433
+ .geo-field__control select,
434
+ .geo-field__control textarea {
435
+ flex: 1; border: none; outline: none; background: transparent;
436
+ font: inherit; color: inherit; width: 100%; min-width: 0;
437
+ }
438
+ .geo-field__control textarea { height: auto; min-height: 88px; resize: vertical; padding: 4px 0; }
439
+ .geo-field__control--textarea { height: auto; align-items: flex-start; }
440
+ .geo-field__error { font-size: 12px; color: var(--geo-color-error-default); }
441
+ .geo-field__hint { font-size: 12px; color: var(--geo-color-neutral-500); }
442
+
443
+ /* —— checkbox / radio —— */
444
+ .geo-check, .geo-radio {
445
+ display: inline-flex; align-items: center; gap: 8px;
446
+ font-size: 14px; cursor: pointer; user-select: none;
447
+ }
448
+ .geo-check input, .geo-radio input { accent-color: var(--geo-color-primary-default); width: 16px; height: 16px; }
449
+ .geo-radio-group { display: flex; gap: 16px; flex-wrap: wrap; }
450
+ .geo-radio-group--vertical { flex-direction: column; gap: 10px; }
451
+ .geo-radio-btn {
452
+ display: inline-flex; align-items: center; justify-content: center;
453
+ height: 32px; padding: 0 14px; border: 1px solid var(--geo-color-neutral-300);
454
+ border-radius: var(--geo-radius); cursor: pointer; font-size: 13px;
455
+ }
456
+ .geo-radio-btn:has(input:checked) {
457
+ border-color: var(--geo-color-primary-default);
458
+ color: var(--geo-color-primary-default);
459
+ background: var(--geo-color-primary-surface-light);
460
+ }
461
+ .geo-radio-btn input { position: absolute; opacity: 0; pointer-events: none; }
462
+
463
+ /* —— status tag —— */
464
+ .geo-status-tag {
465
+ display: inline-flex; align-items: center; gap: 6px;
466
+ min-height: 24px; padding: 4px 12px; border: 1px solid transparent;
467
+ border-radius: 999px; font-size: var(--geo-font-size-caption);
468
+ font-weight: 500; line-height: var(--geo-line-height-caption);
469
+ }
470
+ .geo-status-tag__dot { width: 6px; height: 6px; border-radius: 50%; background: currentColor; }
471
+ .geo-status-tag--success { background: var(--geo-color-success-light); border-color: color-mix(in srgb, var(--geo-color-success-default) 45%, var(--geo-color-success-light)); color: var(--geo-color-success-dark); }
472
+ .geo-status-tag--error { background: var(--geo-color-error-light); border-color: color-mix(in srgb, var(--geo-color-error-default) 45%, var(--geo-color-error-light)); color: var(--geo-color-error-dark); }
473
+ .geo-status-tag--warning { background: var(--geo-color-warning-light); border-color: color-mix(in srgb, var(--geo-color-warning-default) 45%, var(--geo-color-warning-light)); color: var(--geo-color-warning-dark); }
474
+ .geo-status-tag--info { background: var(--geo-color-info-light); border-color: color-mix(in srgb, var(--geo-color-info-default) 45%, var(--geo-color-info-light)); color: var(--geo-color-info-dark); }
475
+ .geo-status-tag--primary { background: var(--geo-color-primary-surface-light); border-color: color-mix(in srgb, var(--geo-color-primary-default) 35%, var(--geo-color-primary-surface-light)); color: var(--geo-color-primary-default); }
476
+ .geo-status-tag--teal { background: var(--geo-color-teal-light); border-color: color-mix(in srgb, var(--geo-color-teal-default) 45%, var(--geo-color-teal-light)); color: var(--geo-color-teal-dark); }
477
+ .geo-status-tag--neutral { background: var(--geo-color-neutral-100); border-color: var(--geo-color-neutral-300); color: var(--geo-color-neutral-700); }
478
+
479
+ /* —— alert —— */
480
+ .geo-alert {
481
+ display: flex; align-items: flex-start; justify-content: space-between; gap: 9px;
482
+ width: 100%; padding: 16px; border: 1px solid transparent; border-radius: var(--geo-radius);
483
+ }
484
+ .geo-alert__main { display: flex; gap: 8px; flex: 1; min-width: 0; }
485
+ .geo-alert__icon { width: 24px; height: 24px; flex-shrink: 0; font-size: 18px; line-height: 24px; text-align: center; }
486
+ .geo-alert__title { margin: 0; font-size: 16px; line-height: 24px; font-weight: 700; }
487
+ .geo-alert__message { margin: 0; font-size: 16px; line-height: 24px; font-weight: 400; }
488
+ .geo-alert__close { border: none; background: transparent; cursor: pointer; width: 24px; height: 24px; color: inherit; opacity: .7; }
489
+ .geo-alert--success { background: var(--geo-color-success-light); border-color: var(--geo-color-success-default); color: var(--geo-color-success-dark); }
490
+ .geo-alert--error { background: var(--geo-color-error-light); border-color: var(--geo-color-error-default); color: var(--geo-color-error-dark); }
491
+ .geo-alert--warning { background: var(--geo-color-warning-light); border-color: var(--geo-color-warning-default); color: var(--geo-color-warning-dark); }
492
+ .geo-alert--info { background: var(--geo-color-info-light); border-color: var(--geo-color-info-default); color: var(--geo-color-info-dark); }
493
+
494
+ /* —— toast (notification mock) —— */
495
+ .geo-toast {
496
+ width: 360px; max-width: 100%;
497
+ background: #fff; border-radius: var(--geo-radius);
498
+ box-shadow: 0 6px 16px rgba(17,24,39,.12);
499
+ border: 1px solid var(--geo-color-neutral-200);
500
+ padding: 14px 16px; display: flex; gap: 10px; align-items: flex-start;
501
+ }
502
+ .geo-toast__dot { width: 8px; height: 8px; border-radius: 50%; margin-top: 6px; flex-shrink: 0; }
503
+ .geo-toast__title { font-weight: 600; margin: 0 0 2px; }
504
+ .geo-toast__msg { margin: 0; color: var(--geo-color-neutral-500); font-size: 13px; }
505
+
506
+ /* —— stepper —— */
507
+ .geo-stepper { display: flex; justify-content: center; width: 100%; }
508
+ .geo-stepper__list { display: flex; align-items: center; list-style: none; margin: 0; padding: 0; }
509
+ .geo-stepper__item { display: flex; align-items: center; }
510
+ .geo-stepper__connector { width: 48px; height: 1px; margin: 0 16px; background: var(--geo-color-neutral-300); }
511
+ .geo-stepper__connector--done { background: var(--geo-color-success-default); }
512
+ .geo-stepper__btn {
513
+ display: inline-flex; align-items: center; gap: 10px;
514
+ border: none; background: transparent; cursor: default; font: inherit; padding: 0;
515
+ }
516
+ .geo-stepper__circle {
517
+ width: 32px; height: 32px; border-radius: 50%;
518
+ display: inline-flex; align-items: center; justify-content: center;
519
+ border: 1.5px solid var(--geo-color-neutral-300);
520
+ color: var(--geo-color-neutral-500); font-size: 13px; font-weight: 600;
521
+ background: #fff;
522
+ }
523
+ .geo-stepper__label { font-size: 14px; color: var(--geo-color-neutral-500); white-space: nowrap; }
524
+ .geo-stepper__item--active .geo-stepper__circle {
525
+ background: var(--geo-color-primary-default); border-color: var(--geo-color-primary-default); color: #fff;
526
+ }
527
+ .geo-stepper__item--active .geo-stepper__label { color: var(--geo-color-primary-default); font-weight: 600; }
528
+ .geo-stepper__item--done .geo-stepper__circle {
529
+ background: var(--geo-color-success-default); border-color: var(--geo-color-success-default); color: #fff;
530
+ }
531
+ .geo-stepper__item--done .geo-stepper__label { color: var(--geo-color-neutral-700); }
532
+
533
+ /* —— tabs —— */
534
+ .geo-tabs__nav {
535
+ display: flex; gap: 24px; border-bottom: 1px solid var(--geo-color-neutral-200);
536
+ margin-bottom: 16px;
537
+ }
538
+ .geo-tabs__tab {
539
+ position: relative; border: none; background: transparent; cursor: pointer;
540
+ padding: 10px 0; font: inherit; color: var(--geo-color-neutral-500);
541
+ }
542
+ .geo-tabs__tab--active { color: var(--geo-color-primary-default); font-weight: 600; }
543
+ .geo-tabs__tab--active::after {
544
+ content: ''; position: absolute; left: 0; right: 0; bottom: -1px; height: 2px;
545
+ background: var(--geo-color-primary-default); border-radius: 1px;
546
+ }
547
+
548
+ /* —— table —— */
549
+ .geo-table { width: 100%; border-collapse: collapse; font-size: 14px; }
550
+ .geo-table th, .geo-table td {
551
+ padding: 12px 16px; text-align: left;
552
+ border-bottom: 1px solid var(--geo-color-neutral-200);
553
+ }
554
+ .geo-table th {
555
+ background: var(--geo-color-neutral-100);
556
+ font-weight: 600; color: var(--geo-color-neutral-700);
557
+ font-size: 13px;
558
+ }
559
+ .geo-table tr:hover td { background: var(--geo-color-primary-background); }
560
+ .geo-table-toolbar {
561
+ display: flex; align-items: center; justify-content: space-between; gap: 12px;
562
+ margin-bottom: 12px; flex-wrap: wrap;
563
+ }
564
+ .geo-table-toolbar__count { color: var(--geo-color-neutral-500); font-size: 13px; }
565
+ .geo-pagination {
566
+ display: flex; align-items: center; justify-content: flex-end; gap: 6px; margin-top: 16px;
567
+ }
568
+ .geo-pagination button {
569
+ min-width: 32px; height: 32px; border-radius: var(--geo-radius);
570
+ border: 1px solid var(--geo-color-neutral-300); background: #fff;
571
+ cursor: pointer; font: inherit;
572
+ }
573
+ .geo-pagination button.is-active {
574
+ border-color: var(--geo-color-primary-default);
575
+ color: var(--geo-color-primary-default); font-weight: 600;
576
+ }
577
+
578
+ /* —— slider —— */
579
+ .geo-slider { width: 100%; accent-color: var(--geo-color-primary-default); }
580
+
581
+ /* —— upload —— */
582
+ .geo-upload {
583
+ border: 1px dashed var(--geo-color-neutral-300);
584
+ border-radius: var(--geo-radius);
585
+ padding: 28px 16px; text-align: center;
586
+ background: var(--geo-color-primary-background);
587
+ color: var(--geo-color-neutral-700);
588
+ }
589
+ .geo-upload strong { color: var(--geo-color-primary-default); cursor: pointer; }
590
+ .geo-upload__hint { margin-top: 8px; font-size: 12px; color: var(--geo-color-neutral-500); }
591
+ .geo-file-picker {
592
+ display: flex; align-items: center; gap: 10px;
593
+ border: 1px solid var(--geo-color-neutral-300); border-radius: var(--geo-radius);
594
+ padding: 6px 8px; min-height: 40px;
595
+ }
596
+ .geo-file-picker__name { flex: 1; color: var(--geo-color-neutral-500); font-size: 13px; }
597
+
598
+ /* —— modal mock —— */
599
+ .modal-stage {
600
+ position: relative; min-height: 420px;
601
+ background: color-mix(in srgb, var(--geo-color-neutral-900) 35%, transparent);
602
+ border-radius: var(--geo-radius); padding: 24px;
603
+ display: flex; align-items: center; justify-content: center;
604
+ }
605
+ .geo-form-modal {
606
+ width: min(720px, 100%);
607
+ background: #fff; border-radius: var(--geo-radius);
608
+ box-shadow: 0 8px 24px rgba(17,24,39,.12); overflow: hidden;
609
+ }
610
+ .geo-form-modal__header {
611
+ position: relative; display: flex; align-items: center; justify-content: space-between;
612
+ gap: 16px; padding: 24px 24px 16px;
613
+ }
614
+ .geo-form-modal__header::after {
615
+ content: ''; position: absolute; left: 24px; right: 24px; bottom: 0; height: 1px;
616
+ background: var(--geo-color-primary-default);
617
+ }
618
+ .geo-form-modal__title {
619
+ margin: 0; font-size: 16px; font-weight: 700; text-transform: uppercase; letter-spacing: .02em;
620
+ }
621
+ .geo-form-modal__body { padding: 24px; display: grid; gap: 16px; }
622
+ .geo-form-modal__footer {
623
+ position: relative; display: flex; justify-content: flex-end; gap: 12px;
624
+ padding: 16px 24px 24px;
625
+ }
626
+ .geo-form-modal__footer::before {
627
+ content: ''; position: absolute; left: 24px; right: 24px; top: 0; height: 1px;
628
+ background: var(--geo-color-primary-default);
629
+ }
630
+ .geo-confirm {
631
+ width: min(445px, 100%); background: #fff; border-radius: var(--geo-radius);
632
+ box-shadow: 0 8px 24px rgba(17,24,39,.12); padding: 24px;
633
+ }
634
+ .geo-confirm h3 { margin: 0 0 8px; font-size: 16px; }
635
+ .geo-confirm p { margin: 0 0 8px; color: var(--geo-color-neutral-700); }
636
+ .geo-confirm__desc { color: var(--geo-color-neutral-500); font-size: 13px; margin-bottom: 20px !important; }
637
+ .geo-confirm__actions { display: flex; justify-content: flex-end; gap: 10px; }
638
+ .geo-confirm mark {
639
+ background: var(--geo-color-primary-surface-light);
640
+ color: var(--geo-color-primary-default); padding: 0 4px; border-radius: 3px;
641
+ }
642
+
643
+ /* —— tree —— */
644
+ .geo-tree { list-style: none; margin: 0; padding: 0; }
645
+ .geo-tree ul { list-style: none; margin: 4px 0 0; padding-left: 20px; }
646
+ .geo-tree li { padding: 4px 0; }
647
+ .geo-tree label { display: inline-flex; gap: 8px; align-items: center; cursor: pointer; }
648
+ .geo-tree input { accent-color: var(--geo-color-primary-default); }
649
+
650
+ /* —— icon —— */
651
+ .geo-icon {
652
+ display: inline-flex; width: 1em; height: 1em; align-items: center; justify-content: center;
653
+ color: var(--geo-color-primary-default); font-style: normal;
654
+ }
655
+ .geo-icon--md { font-size: 20px; }
656
+ .geo-icon--lg { font-size: 28px; }
657
+ </style>
658
+ </head>
659
+ <body>
660
+ <div class="page">
661
+ <aside class="nav">
662
+ <p class="nav__brand">@geoit/ui</p>
663
+ <p class="nav__sub">Static mockup · design tokens</p>
664
+ <a href="#tokens">Tokens</a>
665
+ <a href="#typography">Typography</a>
666
+ <a href="#navigation">Navigation</a>
667
+ <a href="#button">Button</a>
668
+ <a href="#forms">Forms</a>
669
+ <a href="#status">Status / Alert</a>
670
+ <a href="#toast">Toast</a>
671
+ <a href="#stepper">Stepper</a>
672
+ <a href="#tabs">Tabs</a>
673
+ <a href="#table">Table</a>
674
+ <a href="#upload">Upload</a>
675
+ <a href="#modal">Form modal</a>
676
+ <a href="#confirm">Confirm modal</a>
677
+ <a href="#tree">Tree</a>
678
+ <a href="#recipe">Recipe page</a>
679
+ </aside>
680
+
681
+ <main class="main">
682
+ <header class="hero">
683
+ <h1>GEO UI component mockup</h1>
684
+ <p>
685
+ HTML tĩnh mô phỏng visual của các <code>geo-*</code> trong <code>ai/components</code>,
686
+ dùng đúng CSS variables từ <code>design-tokens.scss</code>.
687
+ Tokens được inject tự động khi <code>npm run ai:docs</code> / <code>npm run build</code>.
688
+ <br /><span class="typo-caption typo-secondary">Generated 2026-08-24T03:07:52.146Z · source: projects/geo-ui/src/lib/styles/design-tokens.scss · 66 component docs in ai/components</span>
689
+ </p>
690
+ </header>
691
+
692
+ <!-- TOKENS -->
693
+ <section class="section" id="tokens">
694
+ <div class="section__head">
695
+ <h2>Design tokens</h2>
696
+ <code>design-tokens.scss</code>
697
+ </div>
698
+ <div class="panel">
699
+ <div class="swatches">
700
+ <div class="swatch"><div class="swatch__chip" style="background:var(--geo-color-primary-default)"></div><div class="swatch__meta">primary default</div></div>
701
+ <div class="swatch"><div class="swatch__chip" style="background:var(--geo-color-primary-hover)"></div><div class="swatch__meta">primary hover</div></div>
702
+ <div class="swatch"><div class="swatch__chip" style="background:var(--geo-color-primary-surface-light)"></div><div class="swatch__meta">primary surface light</div></div>
703
+ <div class="swatch"><div class="swatch__chip" style="background:var(--geo-color-success-default)"></div><div class="swatch__meta">success default</div></div>
704
+ <div class="swatch"><div class="swatch__chip" style="background:var(--geo-color-error-default)"></div><div class="swatch__meta">error default</div></div>
705
+ <div class="swatch"><div class="swatch__chip" style="background:var(--geo-color-warning-default)"></div><div class="swatch__meta">warning default</div></div>
706
+ <div class="swatch"><div class="swatch__chip" style="background:var(--geo-color-info-default)"></div><div class="swatch__meta">info default</div></div>
707
+ <div class="swatch"><div class="swatch__chip" style="background:var(--geo-color-teal-default)"></div><div class="swatch__meta">teal default</div></div>
708
+ </div>
709
+ <p class="note">Radius mặc định <strong>8px</strong> · control height <strong>40px</strong> · font Inter</p>
710
+ </div>
711
+ </section>
712
+
713
+ <!-- TYPOGRAPHY -->
714
+ <section class="section" id="typography">
715
+ <div class="section__head">
716
+ <h2>geo-typography</h2>
717
+ <code>ai/components/geo-typography.md</code>
718
+ </div>
719
+ <div class="panel stack">
720
+ <p class="typo-h1">H1 — Tiêu đề lớn 28/36</p>
721
+ <p class="typo-h2">H2 — Tiêu đề 24/32</p>
722
+ <p class="typo-h3">H3 — Tiêu đề 20/28</p>
723
+ <p class="typo-h4">H4 — Tiêu đề 16/24</p>
724
+ <p class="typo-body">Body — Nội dung chính 14/20</p>
725
+ <p class="typo-body typo-secondary">Body secondary — mô tả phụ</p>
726
+ <p class="typo-caption typo-danger">Caption danger — trường bắt buộc</p>
727
+ <p class="typo-body typo-success">Success text</p>
728
+ </div>
729
+ </section>
730
+
731
+ <!-- NAVIGATION -->
732
+ <section class="section" id="navigation">
733
+ <div class="section__head">
734
+ <h2>Breadcrumb · Page title · Back</h2>
735
+ <code>geo-breadcrumb / geo-page-title / geo-back-button</code>
736
+ </div>
737
+ <div class="panel stack">
738
+ <button class="geo-back-button" type="button">← Quay lại</button>
739
+ <nav class="geo-breadcrumb" aria-label="Breadcrumb">
740
+ <a href="#">Trang chủ</a>
741
+ <span class="geo-breadcrumb__sep">/</span>
742
+ <a href="#">Tra cứu hồ sơ</a>
743
+ <span class="geo-breadcrumb__sep">/</span>
744
+ <span class="geo-breadcrumb__current">Xem chi tiết hồ sơ</span>
745
+ </nav>
746
+ <div class="geo-page-title geo-page-title--uppercase">
747
+ <div class="typo-h3">Thông tin chi tiết hồ sơ</div>
748
+ <span class="geo-page-title__accent"></span>
749
+ </div>
750
+ </div>
751
+ </section>
752
+
753
+ <!-- BUTTON -->
754
+ <section class="section" id="button">
755
+ <div class="section__head">
756
+ <h2>geo-button</h2>
757
+ <code>ai/components/geo-button.md</code>
758
+ </div>
759
+ <div class="panel stack">
760
+ <div class="row">
761
+ <button class="geo-button geo-button--primary geo-button--brand" type="button">Primary brand</button>
762
+ <button class="geo-button geo-button--secondary geo-button--brand" type="button">Secondary</button>
763
+ <button class="geo-button geo-button--tertiary geo-button--brand" type="button">Tertiary</button>
764
+ <button class="geo-button geo-button--primary geo-button--brand" type="button" disabled>Disabled</button>
765
+ </div>
766
+ <div class="row">
767
+ <button class="geo-button geo-button--primary geo-button--danger" type="button">Danger</button>
768
+ <button class="geo-button geo-button--primary geo-button--warning" type="button">Warning</button>
769
+ <button class="geo-button geo-button--primary geo-button--success" type="button">Success</button>
770
+ <button class="geo-button geo-button--primary geo-button--brand" type="button">
771
+ <span class="geo-button__icon">+</span><span>Thêm mới</span>
772
+ </button>
773
+ <button class="geo-button geo-button--primary geo-button--brand" type="button">
774
+ <span>Tiếp theo</span><span class="geo-button__icon">→</span>
775
+ </button>
776
+ <button class="geo-button geo-button--secondary geo-button--brand geo-button--icon-only" type="button" title="Cài đặt">⚙</button>
777
+ </div>
778
+ </div>
779
+ </section>
780
+
781
+ <!-- FORMS -->
782
+ <section class="section" id="forms">
783
+ <div class="section__head">
784
+ <h2>Form controls</h2>
785
+ <code>geo-input · select · textarea · checkbox · radio · date · slider</code>
786
+ </div>
787
+ <div class="panel">
788
+ <div class="grid-2">
789
+ <label class="geo-field">
790
+ <span class="geo-field__label">Họ tên <span class="geo-field__req">*</span></span>
791
+ <span class="geo-field__control"><input placeholder="Nhập họ tên" value="Nguyễn Văn A" /></span>
792
+ </label>
793
+ <label class="geo-field">
794
+ <span class="geo-field__label">Từ khóa</span>
795
+ <span class="geo-field__control">
796
+ <span aria-hidden="true">⌕</span>
797
+ <input placeholder="Nhập từ khóa" />
798
+ </span>
799
+ </label>
800
+ <label class="geo-field">
801
+ <span class="geo-field__label">Trạng thái</span>
802
+ <span class="geo-field__control">
803
+ <select>
804
+ <option>Chọn giá trị</option>
805
+ <option selected>Đã duyệt</option>
806
+ <option>Từ chối</option>
807
+ </select>
808
+ </span>
809
+ </label>
810
+ <label class="geo-field">
811
+ <span class="geo-field__label">Ngày cấp</span>
812
+ <span class="geo-field__control"><input type="date" value="2026-07-27" /></span>
813
+ </label>
814
+ <label class="geo-field" style="grid-column: 1 / -1">
815
+ <span class="geo-field__label">Ghi chú</span>
816
+ <span class="geo-field__control geo-field__control--textarea">
817
+ <textarea rows="3" placeholder="Nhập mô tả">Nội dung ghi chú mẫu.</textarea>
818
+ </span>
819
+ </label>
820
+ <label class="geo-field geo-field__control--error" style="grid-column: 1 / -1">
821
+ <span class="geo-field__label">Mã hồ sơ <span class="geo-field__req">*</span></span>
822
+ <span class="geo-field__control geo-field__control--error"><input value="" placeholder="Bắt buộc" /></span>
823
+ <span class="geo-field__error">Vui lòng nhập mã hồ sơ</span>
824
+ </label>
825
+ </div>
826
+ <div class="stack" style="margin-top:16px">
827
+ <label class="geo-check"><input type="checkbox" checked /> Tôi đồng ý điều khoản</label>
828
+ <div class="geo-radio-group">
829
+ <label class="geo-radio"><input type="radio" name="st" checked /> Hoạt động</label>
830
+ <label class="geo-radio"><input type="radio" name="st" /> Ngừng</label>
831
+ </div>
832
+ <div class="geo-radio-group">
833
+ <label class="geo-radio-btn"><input type="radio" name="kind" checked /> Cá nhân</label>
834
+ <label class="geo-radio-btn"><input type="radio" name="kind" /> Tổ chức</label>
835
+ <label class="geo-radio-btn"><input type="radio" name="kind" /> Khác</label>
836
+ </div>
837
+ <label class="geo-field">
838
+ <span class="geo-field__label">Mức độ hoàn thành — geo-slider</span>
839
+ <input class="geo-slider" type="range" min="0" max="100" value="65" />
840
+ </label>
841
+ </div>
842
+ </div>
843
+ </section>
844
+
845
+ <!-- STATUS / ALERT -->
846
+ <section class="section" id="status">
847
+ <div class="section__head">
848
+ <h2>geo-status-tag · geo-alert</h2>
849
+ <code>ai/components/geo-status-tag.md · geo-alert.md</code>
850
+ </div>
851
+ <div class="panel stack">
852
+ <div class="row">
853
+ <span class="geo-status-tag geo-status-tag--success"><span class="geo-status-tag__dot"></span>Đã duyệt</span>
854
+ <span class="geo-status-tag geo-status-tag--error"><span class="geo-status-tag__dot"></span>Từ chối</span>
855
+ <span class="geo-status-tag geo-status-tag--warning"><span class="geo-status-tag__dot"></span>Chờ xử lý</span>
856
+ <span class="geo-status-tag geo-status-tag--info"><span class="geo-status-tag__dot"></span>Đang xử lý</span>
857
+ <span class="geo-status-tag geo-status-tag--primary"><span class="geo-status-tag__dot"></span>Đang mượn</span>
858
+ <span class="geo-status-tag geo-status-tag--teal"><span class="geo-status-tag__dot"></span>Trả kết quả</span>
859
+ <span class="geo-status-tag geo-status-tag--neutral"><span class="geo-status-tag__dot"></span>Nháp</span>
860
+ </div>
861
+ <div class="geo-alert geo-alert--success">
862
+ <div class="geo-alert__main">
863
+ <span class="geo-alert__icon">✓</span>
864
+ <div>
865
+ <p class="geo-alert__title">Thành công!</p>
866
+ <p class="geo-alert__message">Đã lưu hồ sơ.</p>
867
+ </div>
868
+ </div>
869
+ <button class="geo-alert__close" type="button" aria-label="Đóng">×</button>
870
+ </div>
871
+ <div class="geo-alert geo-alert--warning">
872
+ <div class="geo-alert__main">
873
+ <span class="geo-alert__icon">!</span>
874
+ <div>
875
+ <p class="geo-alert__title">Cảnh báo!</p>
876
+ <p class="geo-alert__message">Dữ liệu chưa được lưu.</p>
877
+ </div>
878
+ </div>
879
+ <button class="geo-alert__close" type="button">×</button>
880
+ </div>
881
+ <div class="geo-alert geo-alert--error">
882
+ <div class="geo-alert__main">
883
+ <span class="geo-alert__icon">✕</span>
884
+ <div>
885
+ <p class="geo-alert__title">Lỗi!</p>
886
+ <p class="geo-alert__message">Không thể kết nối máy chủ.</p>
887
+ </div>
888
+ </div>
889
+ <button class="geo-alert__close" type="button">×</button>
890
+ </div>
891
+ <div class="geo-alert geo-alert--info">
892
+ <div class="geo-alert__main">
893
+ <span class="geo-alert__icon">i</span>
894
+ <div>
895
+ <p class="geo-alert__title">Thông tin!</p>
896
+ <p class="geo-alert__message">Vui lòng kiểm tra lại thông tin hồ sơ.</p>
897
+ </div>
898
+ </div>
899
+ <button class="geo-alert__close" type="button">×</button>
900
+ </div>
901
+ </div>
902
+ </section>
903
+
904
+ <!-- TOAST -->
905
+ <section class="section" id="toast">
906
+ <div class="section__head">
907
+ <h2>GeoToastService / geo-toast</h2>
908
+ <code>ai/components/geo-toast.md</code>
909
+ </div>
910
+ <div class="panel">
911
+ <div class="row" style="align-items:stretch">
912
+ <div class="geo-toast">
913
+ <span class="geo-toast__dot" style="background:var(--geo-color-success-default)"></span>
914
+ <div>
915
+ <p class="geo-toast__title">Thành công!</p>
916
+ <p class="geo-toast__msg">Đã lưu hồ sơ.</p>
917
+ </div>
918
+ </div>
919
+ <div class="geo-toast">
920
+ <span class="geo-toast__dot" style="background:var(--geo-color-error-default)"></span>
921
+ <div>
922
+ <p class="geo-toast__title">Thất bại!</p>
923
+ <p class="geo-toast__msg">Không thể lưu.</p>
924
+ </div>
925
+ </div>
926
+ </div>
927
+ <p class="note">Runtime: ưu tiên <code>this.toast.success(title, message)</code> — mock chỉ minh họa visual.</p>
928
+ </div>
929
+ </section>
930
+
931
+ <!-- STEPPER -->
932
+ <section class="section" id="stepper">
933
+ <div class="section__head">
934
+ <h2>geo-stepper</h2>
935
+ <code>ai/components/geo-stepper.md</code>
936
+ </div>
937
+ <div class="panel">
938
+ <div class="geo-stepper">
939
+ <ol class="geo-stepper__list">
940
+ <li class="geo-stepper__item geo-stepper__item--done">
941
+ <span class="geo-stepper__btn"><span class="geo-stepper__circle">✓</span><span class="geo-stepper__label">1. Thông tin</span></span>
942
+ </li>
943
+ <li class="geo-stepper__connector geo-stepper__connector--done" aria-hidden="true"></li>
944
+ <li class="geo-stepper__item geo-stepper__item--active">
945
+ <span class="geo-stepper__btn"><span class="geo-stepper__circle">2</span><span class="geo-stepper__label">2. Xác nhận</span></span>
946
+ </li>
947
+ <li class="geo-stepper__connector" aria-hidden="true"></li>
948
+ <li class="geo-stepper__item">
949
+ <span class="geo-stepper__btn"><span class="geo-stepper__circle">3</span><span class="geo-stepper__label">3. Hoàn tất</span></span>
950
+ </li>
951
+ </ol>
952
+ </div>
953
+ <p class="note">Active = primary · Completed = success + check · Connector 48px</p>
954
+ </div>
955
+ </section>
956
+
957
+ <!-- TABS -->
958
+ <section class="section" id="tabs">
959
+ <div class="section__head">
960
+ <h2>geo-tabs</h2>
961
+ <code>ai/components/geo-tabs.md</code>
962
+ </div>
963
+ <div class="panel">
964
+ <div class="geo-tabs__nav">
965
+ <button class="geo-tabs__tab geo-tabs__tab--active" type="button">Thông tin</button>
966
+ <button class="geo-tabs__tab" type="button">Tệp đính kèm</button>
967
+ <button class="geo-tabs__tab" type="button">Lịch sử</button>
968
+ </div>
969
+ <p class="typo-body typo-secondary">Nội dung tab “Thông tin” — ink bar primary.</p>
970
+ </div>
971
+ </section>
972
+
973
+ <!-- TABLE -->
974
+ <section class="section" id="table">
975
+ <div class="section__head">
976
+ <h2>geo-table + toolbar</h2>
977
+ <code>ai/components/geo-table.md</code>
978
+ </div>
979
+ <div class="panel">
980
+ <div class="geo-table-toolbar">
981
+ <span class="geo-table-toolbar__count">Kết quả tìm kiếm (128)</span>
982
+ <div class="row">
983
+ <button class="geo-button geo-button--secondary geo-button--danger" type="button">Xóa</button>
984
+ <button class="geo-button geo-button--secondary geo-button--brand" type="button">Xuất</button>
985
+ <button class="geo-button geo-button--primary geo-button--brand" type="button"><span class="geo-button__icon">+</span>Thêm mới</button>
986
+ </div>
987
+ </div>
988
+ <div style="overflow:auto">
989
+ <table class="geo-table">
990
+ <thead>
991
+ <tr>
992
+ <th style="width:48px"><input type="checkbox" /></th>
993
+ <th style="width:64px">STT</th>
994
+ <th>Mã</th>
995
+ <th>Tên</th>
996
+ <th>Trạng thái</th>
997
+ <th style="width:96px">Thao tác</th>
998
+ </tr>
999
+ </thead>
1000
+ <tbody>
1001
+ <tr>
1002
+ <td><input type="checkbox" /></td>
1003
+ <td>1</td>
1004
+ <td>HS-001</td>
1005
+ <td>Hồ sơ khai thác khoáng sản</td>
1006
+ <td><span class="geo-status-tag geo-status-tag--success"><span class="geo-status-tag__dot"></span>Đã duyệt</span></td>
1007
+ <td>
1008
+ <button class="geo-button geo-button--tertiary geo-button--brand geo-button--icon-only" type="button">✎</button>
1009
+ <button class="geo-button geo-button--tertiary geo-button--danger geo-button--icon-only" type="button">🗑</button>
1010
+ </td>
1011
+ </tr>
1012
+ <tr>
1013
+ <td><input type="checkbox" checked /></td>
1014
+ <td>2</td>
1015
+ <td>HS-002</td>
1016
+ <td>Phiếu đăng ký mượn tài liệu</td>
1017
+ <td><span class="geo-status-tag geo-status-tag--info"><span class="geo-status-tag__dot"></span>Đang xử lý</span></td>
1018
+ <td>
1019
+ <button class="geo-button geo-button--tertiary geo-button--brand geo-button--icon-only" type="button">✎</button>
1020
+ <button class="geo-button geo-button--tertiary geo-button--danger geo-button--icon-only" type="button">🗑</button>
1021
+ </td>
1022
+ </tr>
1023
+ <tr>
1024
+ <td><input type="checkbox" /></td>
1025
+ <td>3</td>
1026
+ <td>HS-003</td>
1027
+ <td>Yêu cầu điều chỉnh thông tin</td>
1028
+ <td><span class="geo-status-tag geo-status-tag--warning"><span class="geo-status-tag__dot"></span>Chờ xử lý</span></td>
1029
+ <td>
1030
+ <button class="geo-button geo-button--tertiary geo-button--brand geo-button--icon-only" type="button">✎</button>
1031
+ <button class="geo-button geo-button--tertiary geo-button--danger geo-button--icon-only" type="button">🗑</button>
1032
+ </td>
1033
+ </tr>
1034
+ </tbody>
1035
+ </table>
1036
+ </div>
1037
+ <div class="geo-pagination">
1038
+ <button type="button">‹</button>
1039
+ <button class="is-active" type="button">1</button>
1040
+ <button type="button">2</button>
1041
+ <button type="button">3</button>
1042
+ <button type="button">›</button>
1043
+ </div>
1044
+ </div>
1045
+ </section>
1046
+
1047
+ <!-- UPLOAD -->
1048
+ <section class="section" id="upload">
1049
+ <div class="section__head">
1050
+ <h2>geo-upload · geo-file-picker</h2>
1051
+ <code>ai/components/geo-upload.md</code>
1052
+ </div>
1053
+ <div class="panel stack">
1054
+ <div class="geo-upload">
1055
+ Kéo thả ảnh hoặc <strong>Chọn file</strong> để tải lên
1056
+ <div class="geo-upload__hint">PNG/JPG/SVG · tối đa 1MB</div>
1057
+ </div>
1058
+ <div class="geo-file-picker">
1059
+ <button class="geo-button geo-button--secondary geo-button--brand" type="button">Chọn file</button>
1060
+ <span class="geo-file-picker__name">ho-so.pdf</span>
1061
+ </div>
1062
+ </div>
1063
+ </section>
1064
+
1065
+ <!-- FORM MODAL -->
1066
+ <section class="section" id="modal">
1067
+ <div class="section__head">
1068
+ <h2>geo-form-modal (+ stepper)</h2>
1069
+ <code>ai/components/geo-form-modal.md</code>
1070
+ </div>
1071
+ <div class="modal-stage">
1072
+ <div class="geo-form-modal" role="dialog" aria-labelledby="modal-title">
1073
+ <div class="geo-form-modal__header">
1074
+ <h3 class="geo-form-modal__title" id="modal-title">Thêm mới danh mục</h3>
1075
+ <button class="geo-button geo-button--tertiary geo-button--brand geo-button--icon-only" type="button" aria-label="Đóng">×</button>
1076
+ </div>
1077
+ <div class="geo-form-modal__body">
1078
+ <div class="geo-stepper">
1079
+ <ol class="geo-stepper__list">
1080
+ <li class="geo-stepper__item geo-stepper__item--active">
1081
+ <span class="geo-stepper__btn"><span class="geo-stepper__circle">1</span><span class="geo-stepper__label">1. Thông tin</span></span>
1082
+ </li>
1083
+ <li class="geo-stepper__connector"></li>
1084
+ <li class="geo-stepper__item">
1085
+ <span class="geo-stepper__btn"><span class="geo-stepper__circle">2</span><span class="geo-stepper__label">2. Xác nhận</span></span>
1086
+ </li>
1087
+ </ol>
1088
+ </div>
1089
+ <div class="grid-2">
1090
+ <label class="geo-field">
1091
+ <span class="geo-field__label">Mã <span class="geo-field__req">*</span></span>
1092
+ <span class="geo-field__control"><input value="DM-01" /></span>
1093
+ </label>
1094
+ <label class="geo-field">
1095
+ <span class="geo-field__label">Tên <span class="geo-field__req">*</span></span>
1096
+ <span class="geo-field__control"><input value="Danh mục mẫu" /></span>
1097
+ </label>
1098
+ </div>
1099
+ </div>
1100
+ <div class="geo-form-modal__footer">
1101
+ <button class="geo-button geo-button--secondary geo-button--brand" type="button">Hủy bỏ</button>
1102
+ <button class="geo-button geo-button--primary geo-button--brand" type="button">Tiếp theo →</button>
1103
+ </div>
1104
+ </div>
1105
+ </div>
1106
+ <p class="note">Header/footer divider primary inset 24px — khớp geo-form-modal SCSS.</p>
1107
+ </section>
1108
+
1109
+ <!-- CONFIRM -->
1110
+ <section class="section" id="confirm">
1111
+ <div class="section__head">
1112
+ <h2>geo-confirm-modal</h2>
1113
+ <code>ai/components/geo-confirm-modal.md</code>
1114
+ </div>
1115
+ <div class="modal-stage" style="min-height:280px">
1116
+ <div class="geo-confirm" role="alertdialog">
1117
+ <h3>Xác nhận xoá</h3>
1118
+ <p>Bạn sắp xoá hồ sơ <mark>HS-2024-001</mark></p>
1119
+ <p class="geo-confirm__desc">Hành động không thể hoàn tác, bạn chắc chắn muốn thực hiện?</p>
1120
+ <div class="geo-confirm__actions">
1121
+ <button class="geo-button geo-button--secondary geo-button--brand" type="button">Hủy</button>
1122
+ <button class="geo-button geo-button--primary geo-button--danger" type="button">Xóa</button>
1123
+ </div>
1124
+ </div>
1125
+ </div>
1126
+ </section>
1127
+
1128
+ <!-- TREE -->
1129
+ <section class="section" id="tree">
1130
+ <div class="section__head">
1131
+ <h2>geo-tree</h2>
1132
+ <code>ai/components/geo-tree.md</code>
1133
+ </div>
1134
+ <div class="panel">
1135
+ <ul class="geo-tree">
1136
+ <li>
1137
+ <label><input type="checkbox" checked /> Sở Tài nguyên</label>
1138
+ <ul>
1139
+ <li><label><input type="checkbox" checked /> Phòng Khoáng sản</label></li>
1140
+ <li><label><input type="checkbox" /> Phòng Địa chất</label></li>
1141
+ </ul>
1142
+ </li>
1143
+ <li>
1144
+ <label><input type="checkbox" /> Chi cục Kiểm soát</label>
1145
+ <ul>
1146
+ <li><label><input type="checkbox" /> Tổ thanh tra</label></li>
1147
+ </ul>
1148
+ </li>
1149
+ </ul>
1150
+ </div>
1151
+ </section>
1152
+
1153
+ <!-- RECIPE COMPOSITION -->
1154
+ <section class="section" id="recipe">
1155
+ <div class="section__head">
1156
+ <h2>Recipe — list page composition</h2>
1157
+ <code>ai/recipes.md</code>
1158
+ </div>
1159
+ <div class="panel stack">
1160
+ <nav class="geo-breadcrumb">
1161
+ <a href="#">Trang chủ</a>
1162
+ <span class="geo-breadcrumb__sep">/</span>
1163
+ <span class="geo-breadcrumb__current">Danh sách hồ sơ</span>
1164
+ </nav>
1165
+ <div class="geo-page-title geo-page-title--uppercase">
1166
+ <div class="typo-h3">Danh sách hồ sơ</div>
1167
+ <span class="geo-page-title__accent"></span>
1168
+ </div>
1169
+ <div class="geo-alert geo-alert--info">
1170
+ <div class="geo-alert__main">
1171
+ <span class="geo-alert__icon">i</span>
1172
+ <div>
1173
+ <p class="geo-alert__title">Thông tin!</p>
1174
+ <p class="geo-alert__message">Dùng geo-table-filter + toolbar + table theo recipes.</p>
1175
+ </div>
1176
+ </div>
1177
+ </div>
1178
+ <div class="geo-table-toolbar">
1179
+ <span class="geo-table-toolbar__count">Kết quả tìm kiếm (3)</span>
1180
+ <button class="geo-button geo-button--primary geo-button--brand" type="button">+ Thêm mới</button>
1181
+ </div>
1182
+ <table class="geo-table">
1183
+ <thead><tr><th>Mã</th><th>Tên</th><th>Trạng thái</th></tr></thead>
1184
+ <tbody>
1185
+ <tr><td>HS-001</td><td>Hồ sơ A</td><td><span class="geo-status-tag geo-status-tag--success"><span class="geo-status-tag__dot"></span>Đã duyệt</span></td></tr>
1186
+ <tr><td>HS-002</td><td>Hồ sơ B</td><td><span class="geo-status-tag geo-status-tag--primary"><span class="geo-status-tag__dot"></span>Đang mượn</span></td></tr>
1187
+ </tbody>
1188
+ </table>
1189
+ </div>
1190
+ </section>
1191
+ </main>
1192
+ </div>
1193
+ </body>
1194
+ </html>