@7365admin1/layer-common 3.2.6 → 3.2.8-staging.200

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 (284) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/assets/css/primitives.css +1113 -0
  3. package/assets/css/screens.css +1097 -0
  4. package/assets/css/shell.css +258 -0
  5. package/assets/css/tokens.css +236 -0
  6. package/components/AcceptDialog.vue +17 -18
  7. package/components/AccessCard/AvailableStats.vue +24 -16
  8. package/components/AccessCardAddForm.vue +42 -42
  9. package/components/AccessCardAssignToUnitForm.vue +13 -21
  10. package/components/AccessCardDeleteDialog.vue +41 -39
  11. package/components/AccessCardDetailsDialog.vue +125 -79
  12. package/components/AccessCardPreviewDialog.vue +58 -84
  13. package/components/AccessCardQrTagging.vue +60 -63
  14. package/components/AccessCardReplaceForm.vue +27 -23
  15. package/components/AccessManagement.vue +86 -85
  16. package/components/AddEqupmentForm.vue +18 -22
  17. package/components/AddPassKeyToVisitor.vue +95 -73
  18. package/components/AppButton.vue +62 -0
  19. package/components/AppCard.vue +20 -0
  20. package/components/AppDateField.vue +49 -0
  21. package/components/AppField.vue +76 -0
  22. package/components/AppKpiTile.vue +65 -0
  23. package/components/AppSegmented.vue +38 -0
  24. package/components/AppSelect.vue +247 -0
  25. package/components/AreaChecklistHistoryLogs.vue +51 -44
  26. package/components/AreaChecklistHistoryMain.vue +14 -7
  27. package/components/AreaFormDialog.vue +71 -59
  28. package/components/AreaMain.vue +73 -107
  29. package/components/AttachmentsViewer.vue +84 -22
  30. package/components/AttendanceCheckInOutDialog.vue +85 -88
  31. package/components/AttendanceDetailsDialog.vue +57 -63
  32. package/components/AttendanceMain.vue +4 -3
  33. package/components/AttendanceMapSearchDialog.vue +42 -44
  34. package/components/AttendanceSettingsDialog.vue +79 -63
  35. package/components/Avatar/Main.vue +54 -2
  36. package/components/BillingMain.vue +26 -30
  37. package/components/BtnUploadFile.vue +53 -11
  38. package/components/BuildingForm.vue +34 -27
  39. package/components/BuildingManagement/buildings.vue +39 -39
  40. package/components/BuildingManagement/units.vue +26 -42
  41. package/components/BuildingUnitFormAdd.vue +20 -23
  42. package/components/BuildingUnitFormEdit.vue +8 -4
  43. package/components/BulletinBoardForm.vue +19 -24
  44. package/components/BulletinBoardManagement.vue +49 -57
  45. package/components/BulletinBoardView.vue +9 -6
  46. package/components/BulletinExpirationChip.vue +13 -4
  47. package/components/Button/Close.vue +2 -2
  48. package/components/CameraForm.vue +21 -22
  49. package/components/CameraMain.vue +50 -49
  50. package/components/Card/DeleteConfirmation.vue +24 -22
  51. package/components/Card/MemberInfoSummary.vue +28 -3
  52. package/components/Card/Toggle.vue +15 -3
  53. package/components/CardToolbar.vue +37 -0
  54. package/components/Carousel.vue +56 -36
  55. package/components/Chat/Bubbles.vue +43 -14
  56. package/components/Chat/Information.vue +49 -32
  57. package/components/Chat/ListCard.vue +38 -9
  58. package/components/Chat/Message.vue +41 -15
  59. package/components/Chat/Navigation.vue +27 -15
  60. package/components/Chat/SkeletonLoader.vue +9 -2
  61. package/components/ChecklistItemRow.vue +25 -1
  62. package/components/CleaningScheduleMain.vue +44 -49
  63. package/components/ClientDetailForm.vue +81 -56
  64. package/components/ClientMain.vue +92 -82
  65. package/components/ConfirmDialog.vue +14 -8
  66. package/components/Container/Standard.vue +9 -7
  67. package/components/CreateSubsciptionPlan.vue +148 -89
  68. package/components/DashboardEmptyState.vue +48 -3
  69. package/components/DashboardMain.vue +924 -676
  70. package/components/DashboardPanel.vue +84 -21
  71. package/components/DeliveryCompany.vue +34 -20
  72. package/components/Dialog/DeleteConfirmation.vue +20 -21
  73. package/components/Dialog/ReplaceAutofillPrompt.vue +19 -26
  74. package/components/Dialog/ReusablePrompt.vue +30 -29
  75. package/components/Dialog/UpdateMoreAction.vue +62 -59
  76. package/components/DocumentForm.vue +14 -21
  77. package/components/DocumentManagement.vue +162 -108
  78. package/components/DocumentViewer.vue +29 -12
  79. package/components/DrawImage.vue +29 -21
  80. package/components/EntryPass/QrTemplatePreview.vue +27 -16
  81. package/components/EntryPassInformation.vue +40 -10
  82. package/components/EntryPassMain.vue +49 -27
  83. package/components/EquipmentItemMain.vue +84 -97
  84. package/components/EquipmentManagementMain.vue +81 -103
  85. package/components/Facility/BookingSetup.vue +43 -52
  86. package/components/Feedback/Form.vue +26 -12
  87. package/components/FeedbackMain.vue +35 -49
  88. package/components/FileInput.vue +75 -58
  89. package/components/FileInputWithList.vue +59 -12
  90. package/components/FormDialog.vue +60 -21
  91. package/components/HidAccessLogDashboard.vue +512 -490
  92. package/components/HidCameraCaptureDialog.vue +216 -0
  93. package/components/HidEnabledGate.vue +67 -9
  94. package/components/HidIntercomManagement.vue +1322 -653
  95. package/components/HidQrCodeConfiguration.vue +1030 -258
  96. package/components/HidReaderForm.vue +142 -59
  97. package/components/HidReaderManagement.vue +211 -323
  98. package/components/HidServiceSettingsPanel.vue +44 -13
  99. package/components/HidUserEnrollment.vue +1185 -412
  100. package/components/HygieneUpdateMoreAction.vue +44 -44
  101. package/components/IncidentReport/Authorities.vue +30 -18
  102. package/components/IncidentReport/IncidentInformation.vue +10 -10
  103. package/components/IncidentReport/IncidentInformationDownload.vue +3 -4
  104. package/components/IncidentReport/affectedEntities.vue +41 -20
  105. package/components/Input/Date.vue +3 -0
  106. package/components/Input/DatePicker.vue +1 -2
  107. package/components/Input/DateTimePicker.vue +1 -1
  108. package/components/Input/File.vue +55 -10
  109. package/components/Input/FileV2.vue +39 -6
  110. package/components/Input/InputPhoneNumberV2.vue +2 -1
  111. package/components/Input/ListGroupSelection.vue +56 -8
  112. package/components/Input/NRICNumber.vue +1 -0
  113. package/components/Input/NewDate.vue +1 -0
  114. package/components/Input/Number.vue +1 -0
  115. package/components/Input/Password.vue +1 -0
  116. package/components/Input/PhoneNumber.vue +21 -1
  117. package/components/Input/VehicleNumber.vue +1 -0
  118. package/components/InputLabel.vue +2 -2
  119. package/components/InvitationClientForm.vue +21 -19
  120. package/components/InvitationForm.vue +15 -21
  121. package/components/InvitationMain.vue +46 -61
  122. package/components/Layout/Header.vue +263 -36
  123. package/components/Layout/NavigationDrawer.vue +300 -30
  124. package/components/ListItem.vue +33 -3
  125. package/components/LocalPagination.vue +27 -3
  126. package/components/ManageChecklistMain.vue +136 -86
  127. package/components/MemberInformation.vue +32 -16
  128. package/components/MemberMain.vue +113 -93
  129. package/components/MyAttendanceMain.vue +3 -5
  130. package/components/NavigationItem.vue +83 -3
  131. package/components/Nfc/NFCPatrolReportMain.vue +47 -33
  132. package/components/Nfc/NFCPatrolRouteForm.vue +18 -20
  133. package/components/Nfc/NFCPatrolRouteMain.vue +116 -103
  134. package/components/Nfc/NFCPatrolSettings.vue +14 -4
  135. package/components/Nfc/NFCTagForm.vue +22 -8
  136. package/components/Nfc/NFCTagMain.vue +41 -43
  137. package/components/Nfc/PatrolReport/DailyReportTab.vue +8 -1
  138. package/components/Nfc/PatrolReport/MonthlyReportTab.vue +8 -1
  139. package/components/Nfc/PatrolReport/MonthlyReportTable.vue +5 -3
  140. package/components/Nfc/PatrolReport/PatrolActivityTable.vue +26 -6
  141. package/components/Nfc/PatrolReport/PatrolReportTab.vue +8 -0
  142. package/components/Nfc/PatrolReport/PatrolRouteSummary.vue +41 -9
  143. package/components/Nfc/PatrolReport/RemarksDialog.vue +39 -9
  144. package/components/Nfc/PatrolReport/ReportEmptyState.vue +29 -9
  145. package/components/Nfc/PatrolReport/ReportFilters.vue +19 -10
  146. package/components/Nfc/PatrolReport/ReportLocationHeader.vue +32 -6
  147. package/components/Nfc/PatrolReport/SummaryReportTable.vue +28 -6
  148. package/components/NotificationSettings.vue +373 -0
  149. package/components/NumberSettingField.vue +9 -2
  150. package/components/OnlineFormConfigurationForm.vue +725 -237
  151. package/components/OnlineFormFill.vue +213 -106
  152. package/components/OnlineFormRenderPreview.vue +25 -30
  153. package/components/OnlineFormsConfiguration.vue +113 -109
  154. package/components/OrgViewDialog.vue +34 -16
  155. package/components/OvernightParkingAvailability.vue +49 -26
  156. package/components/OvernightParkingManagement.vue +78 -18
  157. package/components/PageHeader.vue +43 -0
  158. package/components/PassInformation.vue +109 -53
  159. package/components/PasswordConfirmation.vue +44 -26
  160. package/components/PeopleForm.vue +41 -20
  161. package/components/PhotoUpload.vue +110 -48
  162. package/components/PlaceholderComponent.vue +35 -19
  163. package/components/PlanActionsMenu.vue +12 -2
  164. package/components/PlanStatusBadge.vue +7 -8
  165. package/components/PlateNumberDisplay.vue +9 -6
  166. package/components/QrTemplate/PrintDialog.vue +66 -43
  167. package/components/RolePermissionFormCreate.vue +104 -79
  168. package/components/RolePermissionFormPreviewUpdate.vue +111 -109
  169. package/components/RolePermissionMain.vue +183 -81
  170. package/components/ScanVisitorQRCode.vue +99 -35
  171. package/components/ScheduleAreaMain.vue +34 -59
  172. package/components/ScheduleTaskForm.vue +61 -42
  173. package/components/ScheduleTaskMain.vue +56 -69
  174. package/components/SearchVehicleNumberUser.vue +39 -37
  175. package/components/ServiceProviderFormCreate.vue +29 -20
  176. package/components/ServiceProviderInvitationPrompt.vue +155 -0
  177. package/components/ServiceProviderMain.vue +601 -432
  178. package/components/Signature.vue +40 -34
  179. package/components/SignaturePad.vue +5 -29
  180. package/components/SiteSettings.vue +41 -11
  181. package/components/SiteSettingsWorkOrder.vue +61 -30
  182. package/components/SlideCardGroup.vue +35 -11
  183. package/components/Snackbar.vue +36 -3
  184. package/components/SpecificAttr.vue +18 -8
  185. package/components/StatusChip.vue +156 -0
  186. package/components/StockCard.vue +17 -12
  187. package/components/SubscriptionPlanTable.vue +207 -140
  188. package/components/SwitchContext.vue +201 -9
  189. package/components/TableHygiene.vue +36 -46
  190. package/components/TableList.vue +10 -10
  191. package/components/TableListSecondary.vue +105 -54
  192. package/components/TableMain.vue +241 -79
  193. package/components/TableV3.vue +61 -70
  194. package/components/TiptapEditor.vue +33 -40
  195. package/components/TiptapEditorQr.vue +5 -2
  196. package/components/Tooltip/Info.vue +69 -24
  197. package/components/UnitMain.vue +40 -60
  198. package/components/UnitPersonCard.vue +42 -13
  199. package/components/VehicleAddSelection.vue +48 -32
  200. package/components/VehicleForm.vue +112 -129
  201. package/components/VehicleManagement.vue +26 -12
  202. package/components/VehicleUpdateMoreAction.vue +59 -46
  203. package/components/VisitorDataFromScannedQRCodeForm.vue +90 -65
  204. package/components/VisitorForm.vue +774 -210
  205. package/components/VisitorFormSelection.vue +40 -37
  206. package/components/VisitorManagement.vue +239 -82
  207. package/components/VisitorPassKeyQRScanner.vue +65 -18
  208. package/components/VisitorSearchResultSummary.vue +60 -16
  209. package/components/VisitorSocketPopUp.vue +22 -14
  210. package/components/VisitorsReportPreview.vue +44 -29
  211. package/components/WorkOrder/Create.vue +26 -17
  212. package/components/WorkOrder/ListView.vue +38 -7
  213. package/components/WorkOrder/Main.vue +62 -59
  214. package/composables/useFeedback.ts +3 -3
  215. package/composables/useHidAmico.ts +269 -0
  216. package/composables/useHidNavigation.ts +2 -9
  217. package/composables/useMember.ts +3 -3
  218. package/composables/useNFCPatrolDailyReport.ts +13 -0
  219. package/composables/useNFCPatrolMonthlyReport.ts +22 -56
  220. package/composables/useNFCPatrolReport.ts +13 -0
  221. package/composables/useNotificationPreference.ts +87 -0
  222. package/composables/useOnlineFormPages.ts +2 -0
  223. package/composables/useRole.ts +22 -0
  224. package/composables/useServiceProvider.ts +3 -3
  225. package/composables/useServiceProviderInvitation.ts +145 -0
  226. package/composables/useSipWebPhone.ts +336 -0
  227. package/composables/useSubscriptionPlan.ts +62 -0
  228. package/composables/useThemePreference.ts +63 -0
  229. package/composables/useVisitor.ts +6 -1
  230. package/composables/useWebUsb.ts +127 -37
  231. package/composables/useWorkOrder.ts +17 -3
  232. package/error.vue +30 -6
  233. package/nuxt.config.ts +36 -0
  234. package/package.json +25 -4
  235. package/pages/[org]/[site]/access-mgmt/administrator/index.vue +2 -2
  236. package/pages/[org]/[site]/access-mgmt/{identity-mapping → hid-cards}/index.vue +2 -2
  237. package/pages/[org]/[site]/access-mgmt/intercom/index.vue +1 -1
  238. package/pages/notification-settings.vue +19 -0
  239. package/pages/payment-method-linked.vue +34 -10
  240. package/pages/require-customer.vue +48 -10
  241. package/pages/require-organization-membership.vue +32 -8
  242. package/pages/unauthorized.vue +29 -4
  243. package/plugins/secure-member.client.ts +21 -56
  244. package/plugins/vuetify.ts +69 -2
  245. package/types/nfc-patrol-report.ts +3 -2
  246. package/types/site.d.ts +71 -0
  247. package/types/subscription.ts +18 -11
  248. package/utils/breadcrumb.test.ts +108 -0
  249. package/utils/breadcrumb.ts +82 -0
  250. package/utils/dashboard.test.ts +118 -0
  251. package/utils/dashboard.ts +53 -0
  252. package/utils/data.test.ts +95 -0
  253. package/utils/data.ts +40 -2
  254. package/utils/hid-discover.test.ts +102 -0
  255. package/utils/list-page.test.ts +60 -0
  256. package/utils/list-page.ts +38 -0
  257. package/utils/materialSymbols.ts +363 -0
  258. package/utils/nav-sections.test.ts +190 -0
  259. package/utils/nav-sections.ts +151 -0
  260. package/utils/nfc-patrol-report.test.ts +130 -0
  261. package/utils/nfc-patrol-report.ts +101 -0
  262. package/utils/role.test.ts +69 -0
  263. package/utils/role.ts +10 -0
  264. package/utils/route-name.test.ts +85 -0
  265. package/utils/route-name.ts +24 -0
  266. package/utils/status.test.ts +110 -0
  267. package/utils/status.ts +135 -0
  268. package/utils/table-card.test.ts +84 -0
  269. package/utils/theme-aa-ledger.ts +148 -0
  270. package/utils/theme.test.ts +485 -7
  271. package/utils/theme.ts +295 -110
  272. package/.changeset/README.md +0 -8
  273. package/.changeset/config.json +0 -11
  274. package/.editorconfig +0 -12
  275. package/.github/workflows/main.yml +0 -17
  276. package/.github/workflows/publish-staging.yml +0 -47
  277. package/.github/workflows/publish.yml +0 -39
  278. package/PUBLISHING.md +0 -269
  279. package/components/HidIdentityMapping.vue +0 -975
  280. package/components/ScheduleTaskAreaFormDialog.vue +0 -144
  281. package/components/ScheduleTaskAreaUpdateMoreAction.vue +0 -109
  282. package/components/ScheduleTastTicketMain.vue +0 -182
  283. package/components/TableWithButton.vue +0 -94
  284. package/test/visitor-socket.test.mjs +0 -36
@@ -632,7 +632,7 @@ onUnmounted(() => {
632
632
  .page-wrap {
633
633
  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
634
634
  font-size: 14px;
635
- color: #111827;
635
+ color: var(--text);
636
636
  background: transparent;
637
637
  }
638
638
 
@@ -643,17 +643,21 @@ onUnmounted(() => {
643
643
  gap: 12px;
644
644
  padding: 12px 0;
645
645
  background: transparent;
646
+ /* The title, the 260px search and the invite button do not fit a phone on
647
+ one line, and without this the whole page scrolled sideways. */
648
+ flex-wrap: wrap;
646
649
  }
647
650
  .topbar-right {
648
651
  margin-left: auto;
649
652
  display: flex;
650
653
  align-items: center;
651
654
  gap: 12px;
655
+ flex-wrap: wrap;
652
656
  }
653
657
  .btn-invite {
654
- background: #fff;
655
- color: #111827;
656
- border: 1px solid #D1D5DB;
658
+ background: var(--card);
659
+ color: var(--text);
660
+ border: 1px solid var(--border);
657
661
  border-radius: 24px;
658
662
  padding: 10px 22px;
659
663
  font-size: 14px;
@@ -662,26 +666,27 @@ onUnmounted(() => {
662
666
  white-space: nowrap;
663
667
  transition: background 0.15s;
664
668
  }
665
- .btn-invite:hover { background: #F9FAFB; }
669
+ .btn-invite:hover { background: var(--hover); }
666
670
 
667
671
  .search-wrap {
668
672
  position: relative;
669
673
  width: 260px;
674
+ max-width: 100%;
670
675
  flex-shrink: 0;
671
676
  }
672
677
  .search-input {
673
678
  width: 100%;
674
679
  height: 36px;
675
- border: 1px solid #E5E7EB;
680
+ border: 1px solid var(--border);
676
681
  border-radius: 8px;
677
682
  padding: 0 34px 0 12px;
678
683
  font-size: 13px;
679
- color: #111827;
680
- background: #fff;
684
+ color: var(--text);
685
+ background: var(--card);
681
686
  outline: none;
682
687
  }
683
- .search-input:focus { border-color: #9CA3AF; }
684
- .search-input::placeholder { color: #9CA3AF; }
688
+ .search-input:focus { border-color: var(--muted); }
689
+ .search-input::placeholder { color: var(--muted); }
685
690
  .search-icon {
686
691
  position: absolute;
687
692
  right: 12px;
@@ -698,18 +703,25 @@ onUnmounted(() => {
698
703
  transform: translateY(-50%);
699
704
  border: none;
700
705
  background: transparent;
701
- color: #9CA3AF;
706
+ color: var(--muted);
702
707
  font-size: 16px;
703
708
  cursor: pointer;
704
709
  line-height: 1;
705
710
  padding: 0;
706
711
  }
707
- .clear-btn:hover { color: #374151; }
712
+ .clear-btn:hover { color: var(--text2); }
708
713
 
709
714
  .filter-wrap {
710
715
  display: flex;
711
716
  gap: 10px;
712
- flex-shrink: 0;
717
+ /* Three filters do not fit a phone beside the search box. `flex-shrink: 0`
718
+ kept this row at its 463px content width, so it never wrapped and the
719
+ whole page scrolled sideways at 360. */
720
+ flex-wrap: wrap;
721
+ min-width: 0;
722
+ }
723
+ .filter-wrap > * {
724
+ max-width: 100%;
713
725
  }
714
726
  .filter-field {
715
727
  position: relative;
@@ -721,8 +733,8 @@ onUnmounted(() => {
721
733
  top: -8px;
722
734
  left: 9px;
723
735
  font-size: 10px;
724
- color: #6B7280;
725
- background: #fff;
736
+ color: var(--muted);
737
+ background: var(--card);
726
738
  padding: 0 3px;
727
739
  pointer-events: none;
728
740
  z-index: 1;
@@ -730,18 +742,18 @@ onUnmounted(() => {
730
742
  }
731
743
  .filter-field select {
732
744
  height: 36px;
733
- border: 1px solid #E5E7EB;
745
+ border: 1px solid var(--border);
734
746
  border-radius: 8px;
735
747
  padding: 0 28px 0 10px;
736
748
  font-size: 13px;
737
- color: #111827;
738
- background: #fff;
749
+ color: var(--text);
750
+ background: var(--card);
739
751
  appearance: none;
740
752
  cursor: pointer;
741
753
  outline: none;
742
754
  min-width: 110px;
743
755
  }
744
- .filter-field select:focus { border-color: #9CA3AF; }
756
+ .filter-field select:focus { border-color: var(--muted); }
745
757
  .chevron {
746
758
  position: absolute;
747
759
  right: 9px;
@@ -755,8 +767,8 @@ onUnmounted(() => {
755
767
  /* ===== TABLE CARD ===== */
756
768
  .table-card {
757
769
  margin: 12px 0 0 0;
758
- background: #fff;
759
- border: 1px solid #E5E7EB;
770
+ background: var(--card);
771
+ border: 1px solid var(--border);
760
772
  border-radius: 10px;
761
773
  overflow: hidden;
762
774
  }
@@ -767,8 +779,8 @@ onUnmounted(() => {
767
779
  align-items: center;
768
780
  justify-content: space-between;
769
781
  padding: 6px 12px;
770
- background: #fff;
771
- border-bottom: 1px solid #F3F4F6;
782
+ background: var(--card);
783
+ border-bottom: 1px solid var(--hover);
772
784
  }
773
785
  .toolbar-left { display: flex; align-items: center; }
774
786
  .toolbar-right { display: flex; align-items: center; gap: 6px; }
@@ -777,7 +789,7 @@ onUnmounted(() => {
777
789
  background: none;
778
790
  border: none;
779
791
  cursor: pointer;
780
- color: #6B7280;
792
+ color: var(--muted);
781
793
  width: 28px;
782
794
  height: 28px;
783
795
  border-radius: 6px;
@@ -786,14 +798,14 @@ onUnmounted(() => {
786
798
  justify-content: center;
787
799
  transition: background 0.15s;
788
800
  }
789
- .refresh-btn:hover { background: #F3F4F6; }
801
+ .refresh-btn:hover { background: var(--hover); }
790
802
  .refresh-btn.spinning svg { animation: spin 0.8s linear infinite; }
791
803
  @keyframes spin { to { transform: rotate(360deg); } }
792
804
 
793
- .page-range-text { font-size: 12px; color: #6B7280; }
805
+ .page-range-text { font-size: 12px; color: var(--muted); }
794
806
  .page-btn {
795
807
  background: none;
796
- border: 1px solid #E5E7EB;
808
+ border: 1px solid var(--border);
797
809
  border-radius: 5px;
798
810
  width: 24px;
799
811
  height: 24px;
@@ -801,22 +813,22 @@ onUnmounted(() => {
801
813
  align-items: center;
802
814
  justify-content: center;
803
815
  cursor: pointer;
804
- color: #374151;
816
+ color: var(--text2);
805
817
  transition: background 0.1s;
806
818
  }
807
- .page-btn:hover:not(:disabled) { background: #F3F4F6; }
819
+ .page-btn:hover:not(:disabled) { background: var(--hover); }
808
820
  .page-btn:disabled { opacity: 0.35; cursor: not-allowed; }
809
821
 
810
822
  /* ===== TABS ===== */
811
823
  .tabs-row {
812
824
  display: flex;
813
- border-bottom: 1px solid #E5E7EB;
825
+ border-bottom: 1px solid var(--border);
814
826
  padding: 0 16px;
815
827
  }
816
828
  .tab {
817
829
  padding: 10px 14px;
818
830
  font-size: 13px;
819
- color: #6B7280;
831
+ color: var(--muted);
820
832
  background: none;
821
833
  border: none;
822
834
  border-bottom: 2px solid transparent;
@@ -824,15 +836,15 @@ onUnmounted(() => {
824
836
  margin-bottom: -1px;
825
837
  transition: color 0.15s, border-color 0.15s;
826
838
  }
827
- .tab:hover { color: #374151; }
828
- .tab.active { color: #111827; border-bottom-color: #111827; font-weight: 500; }
839
+ .tab:hover { color: var(--text2); }
840
+ .tab.active { color: var(--text); border-bottom-color: var(--text); font-weight: 500; }
829
841
 
830
842
  /* ===== LOADING BAR ===== */
831
- .loading-bar { height: 2px; background: #F3F4F6; overflow: hidden; }
843
+ .loading-bar { height: 2px; background: var(--hover); overflow: hidden; }
832
844
  .loading-bar-fill {
833
845
  height: 100%;
834
846
  width: 35%;
835
- background: #6B7280;
847
+ background: var(--muted);
836
848
  animation: slide 1.1s ease-in-out infinite;
837
849
  }
838
850
  @keyframes slide {
@@ -843,39 +855,37 @@ onUnmounted(() => {
843
855
  /* ===== TABLE ===== */
844
856
  .table-scroll { overflow-x: auto; }
845
857
  table { width: 100%; border-collapse: collapse; font-size: 13px; }
858
+ /* `.table-card thead th` / `tbody td` in screens.css state the design's table
859
+ header and cell with `!important`; the padding, font, colour and background
860
+ this block used to set never applied. Only what still applies is kept. */
846
861
  thead th {
847
- padding: 10px 16px;
848
862
  text-align: left;
849
- font-weight: 600;
850
- font-size: 13px;
851
- color: #374151;
852
- border-bottom: 1px solid #E5E7EB;
863
+ border-bottom: 1px solid var(--border);
853
864
  white-space: nowrap;
854
- background: #fff;
855
865
  }
856
- tbody tr { border-bottom: 1px solid #F3F4F6; transition: background 0.1s; }
866
+ tbody tr { border-bottom: 1px solid var(--hover); transition: background 0.1s; }
857
867
  tbody tr:last-child { border-bottom: none; }
858
- tbody tr:hover { background: #FAFAFA; }
859
- tbody td { padding: 14px 16px; vertical-align: middle; }
868
+ tbody tr:hover { background: var(--thead); }
869
+ tbody td { vertical-align: middle; }
860
870
 
861
- .empty { text-align: center; color: #9CA3AF; padding: 48px 0 !important; }
862
- .td-name { font-weight: 500; color: #111827; }
863
- .td-muted { color: #6B7280; font-size: 13px; }
871
+ .empty { text-align: center; color: var(--muted); padding: 48px 0 !important; }
872
+ .td-name { font-weight: 500; color: var(--text); }
873
+ .td-muted { color: var(--muted); font-size: 13px; }
864
874
 
865
875
  .sites-badge {
866
876
  display: inline-block;
867
- background: #F3F4F6;
877
+ background: var(--hover);
868
878
  border-radius: 20px;
869
879
  padding: 3px 12px;
870
880
  font-size: 12px;
871
- color: #374151;
881
+ color: var(--text2);
872
882
  }
873
883
  .date-cell {
874
884
  display: inline-flex;
875
885
  align-items: center;
876
886
  gap: 5px;
877
887
  font-size: 13px;
878
- color: #374151;
888
+ color: var(--text2);
879
889
  }
880
890
 
881
891
  /* ===== STATUS CHIPS ===== */
@@ -889,12 +899,12 @@ tbody td { padding: 14px 16px; vertical-align: middle; }
889
899
  font-weight: 500;
890
900
  }
891
901
  .status-chip::before { content: ''; width: 6px; height: 6px; border-radius: 50%; flex-shrink: 0; }
892
- .status-chip.active { background: #D1FAE5; color: #065F46; }
893
- .status-chip.active::before { background: #10B981; }
894
- .status-chip.suspended { background: #FEE2E2; color: #991B1B; }
895
- .status-chip.suspended::before { background: #EF4444; }
896
- .status-chip.pending { background: #FEF9C3; color: #854D0E; }
897
- .status-chip.pending::before { background: #EAB308; }
902
+ .status-chip.active { background: var(--ok-bg); color: var(--ok); }
903
+ .status-chip.active::before { background: currentColor; }
904
+ .status-chip.suspended { background: var(--err-bg); color: var(--err); }
905
+ .status-chip.suspended::before { background: currentColor; }
906
+ .status-chip.pending { background: var(--warn-bg); color: var(--warn); }
907
+ .status-chip.pending::before { background: currentColor; }
898
908
 
899
909
  /* ===== ACTION MENU ===== */
900
910
  .action-wrap { position: relative; }
@@ -907,16 +917,16 @@ tbody td { padding: 14px 16px; vertical-align: middle; }
907
917
  border-radius: 6px;
908
918
  padding: 6px 8px;
909
919
  cursor: pointer;
910
- color: #9CA3AF;
920
+ color: var(--muted);
911
921
  transition: background 0.15s;
912
922
  }
913
- .dots-btn:hover { background: #F3F4F6; color: #374151; }
923
+ .dots-btn:hover { background: var(--hover); color: var(--text2); }
914
924
  .dots-btn span { display: block; width: 4px; height: 4px; border-radius: 50%; background: currentColor; }
915
925
 
916
926
  .dropdown {
917
927
  position: fixed;
918
- background: #fff;
919
- border: 1px solid #E5E7EB;
928
+ background: var(--card);
929
+ border: 1px solid var(--border);
920
930
  border-radius: 8px;
921
931
  box-shadow: 0 4px 12px rgba(0,0,0,0.08);
922
932
  min-width: 130px;
@@ -932,12 +942,12 @@ tbody td { padding: 14px 16px; vertical-align: middle; }
932
942
  background: none;
933
943
  border: none;
934
944
  cursor: pointer;
935
- color: #374151;
945
+ color: var(--text2);
936
946
  transition: background 0.1s;
937
947
  }
938
- .dd-item:hover { background: #F9FAFB; }
939
- .dd-item.danger { color: #DC2626; }
940
- .dd-item.danger:hover { background: #FEF2F2; }
948
+ .dd-item:hover { background: var(--hover); }
949
+ .dd-item.danger { color: var(--err); }
950
+ .dd-item.danger:hover { background: var(--err-bg); }
941
951
 
942
952
  .cancel-btn {
943
953
  display: inline-flex;
@@ -945,27 +955,27 @@ tbody td { padding: 14px 16px; vertical-align: middle; }
945
955
  gap: 6px;
946
956
  padding: 5px 12px;
947
957
  font-size: 12px;
948
- color: #DC2626;
949
- background: #FEF2F2;
950
- border: 1px solid #FECACA;
958
+ color: var(--err);
959
+ background: var(--err-bg);
960
+ border: 1px solid var(--err-bg);
951
961
  border-radius: 6px;
952
962
  cursor: pointer;
953
963
  transition: background 0.15s;
954
964
  }
955
- .cancel-btn:hover { background: #FEE2E2; }
965
+ .cancel-btn:hover { background: var(--err-bg); }
956
966
  .cancel-btn:disabled { opacity: 0.5; cursor: not-allowed; }
957
967
  .spinner {
958
968
  display: inline-block;
959
969
  width: 11px;
960
970
  height: 11px;
961
- border: 1.5px solid #FECACA;
962
- border-top-color: #DC2626;
971
+ border: 1.5px solid var(--err-bg);
972
+ border-top-color: var(--err);
963
973
  border-radius: 50%;
964
974
  animation: spin 0.7s linear infinite;
965
975
  }
966
976
  .spinner-light {
967
977
  border: 1.5px solid rgba(255,255,255,0.5);
968
- border-top-color: #fff;
978
+ border-top-color: var(--card);
969
979
  }
970
980
 
971
981
  .client-detail {
@@ -982,7 +992,7 @@ tbody td { padding: 14px 16px; vertical-align: middle; }
982
992
  z-index: 1000;
983
993
  }
984
994
  .dialog-box {
985
- background: #fff;
995
+ background: var(--card);
986
996
  border-radius: 12px;
987
997
  max-width: 500px;
988
998
  width: 90%;
@@ -992,7 +1002,7 @@ tbody td { padding: 14px 16px; vertical-align: middle; }
992
1002
 
993
1003
  /* ===== SUSPEND CONFIRMATION DIALOG ===== */
994
1004
  .confirm-box {
995
- background: #fff;
1005
+ background: var(--card);
996
1006
  border-radius: 12px;
997
1007
  max-width: 380px;
998
1008
  width: 90%;
@@ -1002,12 +1012,12 @@ tbody td { padding: 14px 16px; vertical-align: middle; }
1002
1012
  .confirm-title {
1003
1013
  font-size: 16px;
1004
1014
  font-weight: 600;
1005
- color: #111827;
1015
+ color: var(--text);
1006
1016
  margin-bottom: 8px;
1007
1017
  }
1008
1018
  .confirm-text {
1009
1019
  font-size: 13.5px;
1010
- color: #4B5563;
1020
+ color: var(--text2);
1011
1021
  line-height: 1.5;
1012
1022
  margin-bottom: 20px;
1013
1023
  }
@@ -1020,14 +1030,14 @@ tbody td { padding: 14px 16px; vertical-align: middle; }
1020
1030
  padding: 8px 16px;
1021
1031
  font-size: 13px;
1022
1032
  font-weight: 500;
1023
- border: 1px solid #D1D5DB;
1033
+ border: 1px solid var(--border);
1024
1034
  border-radius: 8px;
1025
- background: #fff;
1026
- color: #374151;
1035
+ background: var(--card);
1036
+ color: var(--text2);
1027
1037
  cursor: pointer;
1028
1038
  transition: background 0.15s;
1029
1039
  }
1030
- .btn-cancel:hover { background: #F9FAFB; }
1040
+ .btn-cancel:hover { background: var(--hover); }
1031
1041
  .btn-confirm-danger {
1032
1042
  display: inline-flex;
1033
1043
  align-items: center;
@@ -1039,11 +1049,11 @@ tbody td { padding: 14px 16px; vertical-align: middle; }
1039
1049
  font-weight: 500;
1040
1050
  border: none;
1041
1051
  border-radius: 8px;
1042
- background: #DC2626;
1043
- color: #fff;
1052
+ background: var(--err);
1053
+ color: var(--card);
1044
1054
  cursor: pointer;
1045
1055
  transition: background 0.15s;
1046
1056
  }
1047
- .btn-confirm-danger:hover:not(:disabled) { background: #B91C1C; }
1057
+ .btn-confirm-danger:hover:not(:disabled) { background: var(--err); }
1048
1058
  .btn-confirm-danger:disabled { opacity: 0.7; cursor: not-allowed; }
1049
1059
  </style>
@@ -1,36 +1,42 @@
1
1
  <template>
2
- <v-dialog v-model="dialog" max-width="400" persistent>
3
- <v-card class="rounded-xl pa-6" elevation="2">
2
+ <!-- 520px is the handoff's `--modal-w`; the card was `rounded-xl` (24px) on a
3
+ Material elevation, where the design draws a 16px corner and its own
4
+ modal shadow. -->
5
+ <v-dialog v-model="dialog" max-width="520" persistent>
6
+ <v-card class="screen-modal pa-6">
4
7
  <!-- Close Button -->
5
8
  <v-btn
6
9
  icon
7
10
  variant="text"
8
11
  size="small"
9
- class="position-absolute"
12
+ class="screen-modal__close position-absolute"
10
13
  style="top: 8px; right: 8px"
11
14
  @click="closeDialog"
12
15
  >
13
16
  <v-icon>mdi-close</v-icon>
14
17
  </v-btn>
15
18
 
16
- <v-card-text class="text-center">
19
+ <v-card-text class="screen-modal__body text-center">
17
20
  <v-row v-if="imageSrc" justify="center" class="py-10">
18
21
  <v-img height="120" :src="imageSrc" alt="Dialog Image" contain />
19
22
  </v-row>
20
23
 
21
- <!-- Title Slot -->
22
- <div class="text-h6 font-weight-medium mb-2">
24
+ <!-- Title Slot. The handoff's 17px/800 modal title belongs to a
25
+ bordered header row this dialog does not draw - a centred title
26
+ inside the body is a case it is silent on, so it takes the
27
+ established `.screen-card-title` primitive. -->
28
+ <div class="screen-card-title mb-2">
23
29
  <slot name="title"></slot>
24
30
  </div>
25
31
 
26
32
  <!-- Description Slot -->
27
- <div class="text-body-1 mb-4">
33
+ <div class="mb-4">
28
34
  <slot name="description"></slot>
29
35
  </div>
30
36
  </v-card-text>
31
37
 
32
38
  <!-- Footer Slot -->
33
- <v-card-actions>
39
+ <v-card-actions class="screen-modal__footer">
34
40
  <slot name="footer"></slot>
35
41
  </v-card-actions>
36
42
  </v-card>
@@ -1,15 +1,17 @@
1
1
  <template>
2
2
  <v-row no-gutters>
3
+ <!--
4
+ The same Back link and the same page title as `SpecificAttr.vue`, which
5
+ is the other half of this pair - it was already on `PageHeader` and this
6
+ one was still on `text-h5 font-weight-medium`, Vuetify's 24px/500 Roboto
7
+ rather than the design's 22px/800. `.screen-back` is stated once in
8
+ `screens.css` with the design gap written out next to it.
9
+ -->
3
10
  <v-col cols="12">
4
- <span
5
- class="font-weight-medium text-subtitle-1 text-decoration-underline cursor-pointer"
6
- @click="emit('back')"
7
- >
8
- Back
9
- </span>
11
+ <span class="screen-back" @click="emit('back')"> Back </span>
10
12
  </v-col>
11
13
  <v-col cols="12">
12
- <span class="text-h5 font-weight-medium">{{ props.title }}</span>
14
+ <PageHeader :title="props.title" />
13
15
  </v-col>
14
16
 
15
17
  <v-col cols="12" class="mt-4">