@samanhappy/mcphub 1.0.8 → 1.0.9

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 (69) hide show
  1. package/dist/betterAuth.js +10 -0
  2. package/dist/betterAuth.js.map +1 -1
  3. package/dist/controllers/activityController.js +9 -1
  4. package/dist/controllers/activityController.js.map +1 -1
  5. package/dist/dao/ActivityDao.js +5 -0
  6. package/dist/dao/ActivityDao.js.map +1 -1
  7. package/dist/db/entities/Activity.js +5 -0
  8. package/dist/db/entities/Activity.js.map +1 -1
  9. package/dist/db/repositories/ActivityRepository.js +15 -0
  10. package/dist/db/repositories/ActivityRepository.js.map +1 -1
  11. package/dist/services/activityLoggingService.js +1 -0
  12. package/dist/services/activityLoggingService.js.map +1 -1
  13. package/dist/services/betterAuthConfig.js +2 -0
  14. package/dist/services/betterAuthConfig.js.map +1 -1
  15. package/dist/services/mcpService.js +6 -0
  16. package/dist/services/mcpService.js.map +1 -1
  17. package/dist/services/requestContextService.js +15 -0
  18. package/dist/services/requestContextService.js.map +1 -1
  19. package/dist/services/sseService.js +2 -0
  20. package/dist/services/sseService.js.map +1 -1
  21. package/frontend/dist/assets/ActivityPage-DrwHdeQ1.js +2 -0
  22. package/frontend/dist/assets/ActivityPage-DrwHdeQ1.js.map +1 -0
  23. package/frontend/dist/assets/{Dashboard-Iq4lJkw-.js → Dashboard-C6l7But8.js} +2 -2
  24. package/frontend/dist/assets/{Dashboard-Iq4lJkw-.js.map → Dashboard-C6l7But8.js.map} +1 -1
  25. package/frontend/dist/assets/{EndpointCopy-BSQygOcu.js → EndpointCopy-Doi0lGZI.js} +2 -2
  26. package/frontend/dist/assets/{EndpointCopy-BSQygOcu.js.map → EndpointCopy-Doi0lGZI.js.map} +1 -1
  27. package/frontend/dist/assets/{GroupsPage-B_nc_tkn.js → GroupsPage-Bx3Yi-md.js} +2 -2
  28. package/frontend/dist/assets/{GroupsPage-B_nc_tkn.js.map → GroupsPage-Bx3Yi-md.js.map} +1 -1
  29. package/frontend/dist/assets/LoginPage-C3p_yHJd.js +2 -0
  30. package/frontend/dist/assets/LoginPage-C3p_yHJd.js.map +1 -0
  31. package/frontend/dist/assets/{LogsPage-CgwQu0Zh.js → LogsPage-Z8Iueeij.js} +2 -2
  32. package/frontend/dist/assets/{LogsPage-CgwQu0Zh.js.map → LogsPage-Z8Iueeij.js.map} +1 -1
  33. package/frontend/dist/assets/{MarketPage-BX7TZNUO.js → MarketPage-BvEPL_eq.js} +2 -2
  34. package/frontend/dist/assets/{MarketPage-BX7TZNUO.js.map → MarketPage-BvEPL_eq.js.map} +1 -1
  35. package/frontend/dist/assets/{PromptsPage-Ban8sC8u.js → PromptsPage-BYoNsubQ.js} +2 -2
  36. package/frontend/dist/assets/{PromptsPage-Ban8sC8u.js.map → PromptsPage-BYoNsubQ.js.map} +1 -1
  37. package/frontend/dist/assets/{ResourcesPage-RBUlnQMZ.js → ResourcesPage-BipHAbTQ.js} +2 -2
  38. package/frontend/dist/assets/{ResourcesPage-RBUlnQMZ.js.map → ResourcesPage-BipHAbTQ.js.map} +1 -1
  39. package/frontend/dist/assets/{ServersPage-GbDb7jmE.js → ServersPage-Da24Dkfs.js} +4 -4
  40. package/frontend/dist/assets/{ServersPage-GbDb7jmE.js.map → ServersPage-Da24Dkfs.js.map} +1 -1
  41. package/frontend/dist/assets/SettingsPage-BiTd0EBn.js +12 -0
  42. package/frontend/dist/assets/SettingsPage-BiTd0EBn.js.map +1 -0
  43. package/frontend/dist/assets/{StatusDot-CnuxXTsd.js → StatusDot-C-kTn-AA.js} +2 -2
  44. package/frontend/dist/assets/{StatusDot-CnuxXTsd.js.map → StatusDot-C-kTn-AA.js.map} +1 -1
  45. package/frontend/dist/assets/{ToggleGroup-9TIHUIkU.js → ToggleGroup-B4fP-TVG.js} +2 -2
  46. package/frontend/dist/assets/{ToggleGroup-9TIHUIkU.js.map → ToggleGroup-B4fP-TVG.js.map} +1 -1
  47. package/frontend/dist/assets/{UsersPage-B8zPaI6u.js → UsersPage-MDtzW9-F.js} +2 -2
  48. package/frontend/dist/assets/{UsersPage-B8zPaI6u.js.map → UsersPage-MDtzW9-F.js.map} +1 -1
  49. package/frontend/dist/assets/index-aFFPxLwH.css +1 -0
  50. package/frontend/dist/assets/index-otG7s0Ro.js +3 -0
  51. package/frontend/dist/assets/index-otG7s0Ro.js.map +1 -0
  52. package/frontend/dist/assets/{resourceService-C_tjomqu.js → resourceService-b5_G4mIW.js} +2 -2
  53. package/frontend/dist/assets/{resourceService-C_tjomqu.js.map → resourceService-b5_G4mIW.js.map} +1 -1
  54. package/frontend/dist/assets/{useServerData-BX2-qyGg.js → useServerData-B_sSO_jj.js} +2 -2
  55. package/frontend/dist/assets/{useServerData-BX2-qyGg.js.map → useServerData-B_sSO_jj.js.map} +1 -1
  56. package/frontend/dist/assets/useSettingsData-BE6ZnRFg.js +2 -0
  57. package/frontend/dist/assets/{useSettingsData-CN236NdG.js.map → useSettingsData-BE6ZnRFg.js.map} +1 -1
  58. package/frontend/dist/index.html +2 -2
  59. package/package.json +1 -1
  60. package/frontend/dist/assets/ActivityPage-CjUx2EbK.js +0 -2
  61. package/frontend/dist/assets/ActivityPage-CjUx2EbK.js.map +0 -1
  62. package/frontend/dist/assets/LoginPage-DdxxHO3c.js +0 -2
  63. package/frontend/dist/assets/LoginPage-DdxxHO3c.js.map +0 -1
  64. package/frontend/dist/assets/SettingsPage-eqjVV7ZP.js +0 -12
  65. package/frontend/dist/assets/SettingsPage-eqjVV7ZP.js.map +0 -1
  66. package/frontend/dist/assets/index-9Vmc8uCD.js +0 -3
  67. package/frontend/dist/assets/index-9Vmc8uCD.js.map +0 -1
  68. package/frontend/dist/assets/index-KKZS7IbJ.css +0 -1
  69. package/frontend/dist/assets/useSettingsData-CN236NdG.js +0 -2
@@ -1,2 +1,2 @@
1
- import{j as s}from"./framework-vendor-BUhDPOUZ.js";import{m as u}from"./index-9Vmc8uCD.js";import{u as d}from"./i18n-vendor-Kbr87Ofu.js";const l={connected:"ok",connecting:"warn",oauth_required:"warn",disconnected:"err"},h={connected:"status.online",connecting:"status.connecting",oauth_required:"status.oauthRequired",disconnected:"status.offline"},i=({kind:e,label:r,className:o,onClick:t,title:n})=>s.jsxs("span",{className:u("hub-status",e,t?"cursor-pointer hover:opacity-80":"",o),onClick:t,title:n,children:[s.jsx("span",{className:"hub-dot"}),r!=null&&s.jsx("span",{className:"hub-status-label",children:r})]}),j=({status:e,enabled:r,onAuthClick:o,className:t})=>{const{t:n}=d();if(r===!1)return s.jsx(i,{kind:"muted",label:n("server.disable")||"Disabled",className:t});const c=l[e]??"muted",a=e==="oauth_required";return s.jsx(i,{kind:c,label:s.jsxs(s.Fragment,{children:[a&&s.jsx("span",{"aria-hidden":!0,children:"🔐"}),s.jsx("span",{children:n(h[e]||e)})]}),onClick:a&&o?o:void 0,title:a?n("status.clickToAuthorize"):void 0,className:t})};export{j as S,i as a};
2
- //# sourceMappingURL=StatusDot-CnuxXTsd.js.map
1
+ import{j as s}from"./framework-vendor-BUhDPOUZ.js";import{m as u}from"./index-otG7s0Ro.js";import{u as d}from"./i18n-vendor-Kbr87Ofu.js";const l={connected:"ok",connecting:"warn",oauth_required:"warn",disconnected:"err"},h={connected:"status.online",connecting:"status.connecting",oauth_required:"status.oauthRequired",disconnected:"status.offline"},i=({kind:e,label:r,className:o,onClick:t,title:n})=>s.jsxs("span",{className:u("hub-status",e,t?"cursor-pointer hover:opacity-80":"",o),onClick:t,title:n,children:[s.jsx("span",{className:"hub-dot"}),r!=null&&s.jsx("span",{className:"hub-status-label",children:r})]}),j=({status:e,enabled:r,onAuthClick:o,className:t})=>{const{t:n}=d();if(r===!1)return s.jsx(i,{kind:"muted",label:n("server.disable")||"Disabled",className:t});const c=l[e]??"muted",a=e==="oauth_required";return s.jsx(i,{kind:c,label:s.jsxs(s.Fragment,{children:[a&&s.jsx("span",{"aria-hidden":!0,children:"🔐"}),s.jsx("span",{children:n(h[e]||e)})]}),onClick:a&&o?o:void 0,title:a?n("status.clickToAuthorize"):void 0,className:t})};export{j as S,i as a};
2
+ //# sourceMappingURL=StatusDot-C-kTn-AA.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"StatusDot-CnuxXTsd.js","sources":["../../src/components/ui/StatusDot.tsx"],"sourcesContent":["import React from 'react';\nimport { useTranslation } from 'react-i18next';\nimport type { ServerStatus } from '@/types';\nimport { cn } from '@/utils/cn';\n\nexport type DotKind = 'ok' | 'warn' | 'err' | 'muted';\n\nconst STATUS_TO_KIND: Record<ServerStatus, DotKind> = {\n connected: 'ok',\n connecting: 'warn',\n oauth_required: 'warn',\n disconnected: 'err',\n};\n\nconst STATUS_TO_KEY: Record<ServerStatus, string> = {\n connected: 'status.online',\n connecting: 'status.connecting',\n oauth_required: 'status.oauthRequired',\n disconnected: 'status.offline',\n};\n\ninterface StatusDotProps {\n kind: DotKind;\n label?: React.ReactNode;\n className?: string;\n onClick?: (e: React.MouseEvent) => void;\n title?: string;\n}\n\nexport const StatusDot: React.FC<StatusDotProps> = ({ kind, label, className, onClick, title }) => (\n <span\n className={cn('hub-status', kind, onClick ? 'cursor-pointer hover:opacity-80' : '', className)}\n onClick={onClick}\n title={title}\n >\n <span className=\"hub-dot\" />\n {label != null && <span className=\"hub-status-label\">{label}</span>}\n </span>\n);\n\ninterface ServerStatusDotProps {\n status: ServerStatus;\n enabled?: boolean;\n onAuthClick?: (e: React.MouseEvent) => void;\n className?: string;\n}\n\nexport const ServerStatusDot: React.FC<ServerStatusDotProps> = ({\n status,\n enabled,\n onAuthClick,\n className,\n}) => {\n const { t } = useTranslation();\n if (enabled === false) {\n return <StatusDot kind=\"muted\" label={t('server.disable') || 'Disabled'} className={className} />;\n }\n const kind = STATUS_TO_KIND[status] ?? 'muted';\n const isOAuth = status === 'oauth_required';\n return (\n <StatusDot\n kind={kind}\n label={\n <>\n {isOAuth && <span aria-hidden>🔐</span>}\n <span>{t(STATUS_TO_KEY[status] || status)}</span>\n </>\n }\n onClick={isOAuth && onAuthClick ? onAuthClick : undefined}\n title={isOAuth ? t('status.clickToAuthorize') : undefined}\n className={className}\n />\n );\n};\n"],"names":["STATUS_TO_KIND","STATUS_TO_KEY","StatusDot","kind","label","className","onClick","title","jsxs","cn","jsx","ServerStatusDot","status","enabled","onAuthClick","t","useTranslation","isOAuth","Fragment"],"mappings":"yIAOA,MAAMA,EAAgD,CACpD,UAAW,KACX,WAAY,OACZ,eAAgB,OAChB,aAAc,KAChB,EAEMC,EAA8C,CAClD,UAAW,gBACX,WAAY,oBACZ,eAAgB,uBAChB,aAAc,gBAChB,EAUaC,EAAsC,CAAC,CAAE,KAAAC,EAAM,MAAAC,EAAO,UAAAC,EAAW,QAAAC,EAAS,MAAAC,KACrFC,EAAAA,KAAC,OAAA,CACC,UAAWC,EAAG,aAAcN,EAAMG,EAAU,kCAAoC,GAAID,CAAS,EAC7F,QAAAC,EACA,MAAAC,EAEA,SAAA,CAAAG,EAAAA,IAAC,OAAA,CAAK,UAAU,SAAA,CAAU,EACzBN,GAAS,MAAQM,EAAAA,IAAC,OAAA,CAAK,UAAU,mBAAoB,SAAAN,CAAA,CAAM,CAAA,CAAA,CAC9D,EAUWO,EAAkD,CAAC,CAC9D,OAAAC,EACA,QAAAC,EACA,YAAAC,EACA,UAAAT,CACF,IAAM,CACJ,KAAM,CAAE,EAAAU,CAAA,EAAMC,EAAA,EACd,GAAIH,IAAY,GACd,OAAOH,MAACR,GAAU,KAAK,QAAQ,MAAOa,EAAE,gBAAgB,GAAK,WAAY,UAAAV,CAAA,CAAsB,EAEjG,MAAMF,EAAOH,EAAeY,CAAM,GAAK,QACjCK,EAAUL,IAAW,iBAC3B,OACEF,EAAAA,IAACR,EAAA,CACC,KAAAC,EACA,MACEK,EAAAA,KAAAU,WAAA,CACG,SAAA,CAAAD,GAAWP,EAAAA,IAAC,OAAA,CAAK,cAAW,GAAC,SAAA,KAAE,QAC/B,OAAA,CAAM,SAAAK,EAAEd,EAAcW,CAAM,GAAKA,CAAM,CAAA,CAAE,CAAA,EAC5C,EAEF,QAASK,GAAWH,EAAcA,EAAc,OAChD,MAAOG,EAAUF,EAAE,yBAAyB,EAAI,OAChD,UAAAV,CAAA,CAAA,CAGN"}
1
+ {"version":3,"file":"StatusDot-C-kTn-AA.js","sources":["../../src/components/ui/StatusDot.tsx"],"sourcesContent":["import React from 'react';\nimport { useTranslation } from 'react-i18next';\nimport type { ServerStatus } from '@/types';\nimport { cn } from '@/utils/cn';\n\nexport type DotKind = 'ok' | 'warn' | 'err' | 'muted';\n\nconst STATUS_TO_KIND: Record<ServerStatus, DotKind> = {\n connected: 'ok',\n connecting: 'warn',\n oauth_required: 'warn',\n disconnected: 'err',\n};\n\nconst STATUS_TO_KEY: Record<ServerStatus, string> = {\n connected: 'status.online',\n connecting: 'status.connecting',\n oauth_required: 'status.oauthRequired',\n disconnected: 'status.offline',\n};\n\ninterface StatusDotProps {\n kind: DotKind;\n label?: React.ReactNode;\n className?: string;\n onClick?: (e: React.MouseEvent) => void;\n title?: string;\n}\n\nexport const StatusDot: React.FC<StatusDotProps> = ({ kind, label, className, onClick, title }) => (\n <span\n className={cn('hub-status', kind, onClick ? 'cursor-pointer hover:opacity-80' : '', className)}\n onClick={onClick}\n title={title}\n >\n <span className=\"hub-dot\" />\n {label != null && <span className=\"hub-status-label\">{label}</span>}\n </span>\n);\n\ninterface ServerStatusDotProps {\n status: ServerStatus;\n enabled?: boolean;\n onAuthClick?: (e: React.MouseEvent) => void;\n className?: string;\n}\n\nexport const ServerStatusDot: React.FC<ServerStatusDotProps> = ({\n status,\n enabled,\n onAuthClick,\n className,\n}) => {\n const { t } = useTranslation();\n if (enabled === false) {\n return <StatusDot kind=\"muted\" label={t('server.disable') || 'Disabled'} className={className} />;\n }\n const kind = STATUS_TO_KIND[status] ?? 'muted';\n const isOAuth = status === 'oauth_required';\n return (\n <StatusDot\n kind={kind}\n label={\n <>\n {isOAuth && <span aria-hidden>🔐</span>}\n <span>{t(STATUS_TO_KEY[status] || status)}</span>\n </>\n }\n onClick={isOAuth && onAuthClick ? onAuthClick : undefined}\n title={isOAuth ? t('status.clickToAuthorize') : undefined}\n className={className}\n />\n );\n};\n"],"names":["STATUS_TO_KIND","STATUS_TO_KEY","StatusDot","kind","label","className","onClick","title","jsxs","cn","jsx","ServerStatusDot","status","enabled","onAuthClick","t","useTranslation","isOAuth","Fragment"],"mappings":"yIAOA,MAAMA,EAAgD,CACpD,UAAW,KACX,WAAY,OACZ,eAAgB,OAChB,aAAc,KAChB,EAEMC,EAA8C,CAClD,UAAW,gBACX,WAAY,oBACZ,eAAgB,uBAChB,aAAc,gBAChB,EAUaC,EAAsC,CAAC,CAAE,KAAAC,EAAM,MAAAC,EAAO,UAAAC,EAAW,QAAAC,EAAS,MAAAC,KACrFC,EAAAA,KAAC,OAAA,CACC,UAAWC,EAAG,aAAcN,EAAMG,EAAU,kCAAoC,GAAID,CAAS,EAC7F,QAAAC,EACA,MAAAC,EAEA,SAAA,CAAAG,EAAAA,IAAC,OAAA,CAAK,UAAU,SAAA,CAAU,EACzBN,GAAS,MAAQM,EAAAA,IAAC,OAAA,CAAK,UAAU,mBAAoB,SAAAN,CAAA,CAAM,CAAA,CAAA,CAC9D,EAUWO,EAAkD,CAAC,CAC9D,OAAAC,EACA,QAAAC,EACA,YAAAC,EACA,UAAAT,CACF,IAAM,CACJ,KAAM,CAAE,EAAAU,CAAA,EAAMC,EAAA,EACd,GAAIH,IAAY,GACd,OAAOH,MAACR,GAAU,KAAK,QAAQ,MAAOa,EAAE,gBAAgB,GAAK,WAAY,UAAAV,CAAA,CAAsB,EAEjG,MAAMF,EAAOH,EAAeY,CAAM,GAAK,QACjCK,EAAUL,IAAW,iBAC3B,OACEF,EAAAA,IAACR,EAAA,CACC,KAAAC,EACA,MACEK,EAAAA,KAAAU,WAAA,CACG,SAAA,CAAAD,GAAWP,EAAAA,IAAC,OAAA,CAAK,cAAW,GAAC,SAAA,KAAE,QAC/B,OAAA,CAAM,SAAAK,EAAEd,EAAcW,CAAM,GAAKA,CAAM,CAAA,CAAE,CAAA,EAC5C,EAEF,QAASK,GAAWH,EAAcA,EAAc,OAChD,MAAOG,EAAUF,EAAE,yBAAyB,EAAI,OAChD,UAAAV,CAAA,CAAA,CAGN"}
@@ -1,2 +1,2 @@
1
- import{j as s}from"./framework-vendor-BUhDPOUZ.js";import{m as i}from"./index-9Vmc8uCD.js";const l=({checked:t,onCheckedChange:n,disabled:o=!1})=>s.jsx("button",{type:"button",role:"switch","aria-checked":t,disabled:o,className:i("relative inline-flex h-6 w-11 items-center rounded-full transition-colors focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-blue-500",t?"bg-blue-200":"bg-gray-100",o?"opacity-50 cursor-not-allowed":"cursor-pointer"),onClick:()=>!o&&n(!t),children:s.jsx("span",{className:i("inline-block h-4 w-4 transform rounded-full bg-white transition-transform",t?"translate-x-6":"translate-x-1")})});export{l as S};
2
- //# sourceMappingURL=ToggleGroup-9TIHUIkU.js.map
1
+ import{j as s}from"./framework-vendor-BUhDPOUZ.js";import{m as i}from"./index-otG7s0Ro.js";const l=({checked:t,onCheckedChange:n,disabled:o=!1})=>s.jsx("button",{type:"button",role:"switch","aria-checked":t,disabled:o,className:i("relative inline-flex h-6 w-11 items-center rounded-full transition-colors focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-blue-500",t?"bg-blue-200":"bg-gray-100",o?"opacity-50 cursor-not-allowed":"cursor-pointer"),onClick:()=>!o&&n(!t),children:s.jsx("span",{className:i("inline-block h-4 w-4 transform rounded-full bg-white transition-transform",t?"translate-x-6":"translate-x-1")})});export{l as S};
2
+ //# sourceMappingURL=ToggleGroup-B4fP-TVG.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"ToggleGroup-9TIHUIkU.js","sources":["../../src/components/ui/ToggleGroup.tsx"],"sourcesContent":["import React, { ReactNode } from 'react';\nimport { cn } from '@/utils/cn';\n\ninterface ToggleGroupItemProps {\n value: string;\n isSelected: boolean;\n onClick: () => void;\n children: ReactNode;\n}\n\nexport const ToggleGroupItem: React.FC<ToggleGroupItemProps> = ({\n isSelected,\n onClick,\n children\n}) => {\n return (\n <button\n type=\"button\"\n role=\"checkbox\"\n aria-checked={isSelected}\n className={cn(\n \"flex w-full items-center justify-between p-2 rounded transition-colors cursor-pointer\",\n isSelected\n ? \"bg-blue-50 text-blue-700 hover:bg-blue-100 border-l-4 border-blue-500\"\n : \"hover:bg-gray-50 text-gray-700\"\n )}\n onClick={onClick}\n >\n <span className=\"flex items-center\">\n {children}\n </span>\n {isSelected && (\n <svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 20 20\" fill=\"currentColor\" className=\"w-5 h-5 text-blue-500\">\n <path fillRule=\"evenodd\" d=\"M16.704 4.153a.75.75 0 01.143 1.052l-8 10.5a.75.75 0 01-1.127.075l-4.5-4.5a.75.75 0 011.06-1.06l3.894 3.893 7.48-9.817a.75.75 0 011.05-.143z\" clipRule=\"evenodd\" />\n </svg>\n )}\n </button>\n );\n};\n\ninterface ToggleGroupProps {\n label: string;\n helpText?: string;\n noOptionsText?: string;\n values: string[];\n options: { value: string; label: string }[];\n onChange: (values: string[]) => void;\n className?: string;\n}\n\nexport const ToggleGroup: React.FC<ToggleGroupProps> = ({\n label,\n helpText,\n noOptionsText = \"No options available\",\n values,\n options,\n onChange,\n className\n}) => {\n const handleToggle = (value: string) => {\n const isSelected = values.includes(value);\n if (isSelected) {\n onChange(values.filter(v => v !== value));\n } else {\n onChange([...values, value]);\n }\n };\n\n return (\n <div className={className}>\n <label className=\"block text-gray-700 text-sm font-bold mb-2\">\n {label}\n </label>\n <div className=\"border border-gray-200 dark:border-gray-700 rounded shadow max-h-60 overflow-y-auto\">\n {options.length === 0 ? (\n <p className=\"text-gray-500 text-sm p-3\">{noOptionsText}</p>\n ) : (\n <div className=\"space-y-1 p-1\">\n {options.map(option => (\n <ToggleGroupItem\n key={option.value}\n value={option.value}\n isSelected={values.includes(option.value)}\n onClick={() => handleToggle(option.value)}\n >\n {option.label}\n </ToggleGroupItem>\n ))}\n </div>\n )}\n </div>\n {helpText && (\n <p className=\"text-xs text-gray-500 mt-1\">\n {helpText}\n </p>\n )}\n </div>\n );\n};\n\ninterface SwitchProps {\n checked: boolean;\n onCheckedChange: (checked: boolean) => void;\n disabled?: boolean;\n}\n\nexport const Switch: React.FC<SwitchProps> = ({\n checked,\n onCheckedChange,\n disabled = false\n}) => {\n return (\n <button\n type=\"button\"\n role=\"switch\"\n aria-checked={checked}\n disabled={disabled}\n className={cn(\n \"relative inline-flex h-6 w-11 items-center rounded-full transition-colors focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-blue-500\",\n checked ? \"bg-blue-200\" : \"bg-gray-100\",\n disabled ? \"opacity-50 cursor-not-allowed\" : \"cursor-pointer\"\n )}\n onClick={() => !disabled && onCheckedChange(!checked)}\n >\n <span\n className={cn(\n \"inline-block h-4 w-4 transform rounded-full bg-white transition-transform\",\n checked ? \"translate-x-6\" : \"translate-x-1\"\n )}\n />\n </button>\n );\n};"],"names":["Switch","checked","onCheckedChange","disabled","jsx","cn"],"mappings":"2FA0GO,MAAMA,EAAgC,CAAC,CAC5C,QAAAC,EACA,gBAAAC,EACA,SAAAC,EAAW,EACb,IAEIC,EAAAA,IAAC,SAAA,CACC,KAAK,SACL,KAAK,SACL,eAAcH,EACd,SAAAE,EACA,UAAWE,EACT,wLACAJ,EAAU,cAAgB,cAC1BE,EAAW,gCAAkC,gBAAA,EAE/C,QAAS,IAAM,CAACA,GAAYD,EAAgB,CAACD,CAAO,EAEpD,SAAAG,EAAAA,IAAC,OAAA,CACC,UAAWC,EACT,4EACAJ,EAAU,gBAAkB,eAAA,CAC9B,CAAA,CACF,CAAA"}
1
+ {"version":3,"file":"ToggleGroup-B4fP-TVG.js","sources":["../../src/components/ui/ToggleGroup.tsx"],"sourcesContent":["import React, { ReactNode } from 'react';\nimport { cn } from '@/utils/cn';\n\ninterface ToggleGroupItemProps {\n value: string;\n isSelected: boolean;\n onClick: () => void;\n children: ReactNode;\n}\n\nexport const ToggleGroupItem: React.FC<ToggleGroupItemProps> = ({\n isSelected,\n onClick,\n children\n}) => {\n return (\n <button\n type=\"button\"\n role=\"checkbox\"\n aria-checked={isSelected}\n className={cn(\n \"flex w-full items-center justify-between p-2 rounded transition-colors cursor-pointer\",\n isSelected\n ? \"bg-blue-50 text-blue-700 hover:bg-blue-100 border-l-4 border-blue-500\"\n : \"hover:bg-gray-50 text-gray-700\"\n )}\n onClick={onClick}\n >\n <span className=\"flex items-center\">\n {children}\n </span>\n {isSelected && (\n <svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 20 20\" fill=\"currentColor\" className=\"w-5 h-5 text-blue-500\">\n <path fillRule=\"evenodd\" d=\"M16.704 4.153a.75.75 0 01.143 1.052l-8 10.5a.75.75 0 01-1.127.075l-4.5-4.5a.75.75 0 011.06-1.06l3.894 3.893 7.48-9.817a.75.75 0 011.05-.143z\" clipRule=\"evenodd\" />\n </svg>\n )}\n </button>\n );\n};\n\ninterface ToggleGroupProps {\n label: string;\n helpText?: string;\n noOptionsText?: string;\n values: string[];\n options: { value: string; label: string }[];\n onChange: (values: string[]) => void;\n className?: string;\n}\n\nexport const ToggleGroup: React.FC<ToggleGroupProps> = ({\n label,\n helpText,\n noOptionsText = \"No options available\",\n values,\n options,\n onChange,\n className\n}) => {\n const handleToggle = (value: string) => {\n const isSelected = values.includes(value);\n if (isSelected) {\n onChange(values.filter(v => v !== value));\n } else {\n onChange([...values, value]);\n }\n };\n\n return (\n <div className={className}>\n <label className=\"block text-gray-700 text-sm font-bold mb-2\">\n {label}\n </label>\n <div className=\"border border-gray-200 dark:border-gray-700 rounded shadow max-h-60 overflow-y-auto\">\n {options.length === 0 ? (\n <p className=\"text-gray-500 text-sm p-3\">{noOptionsText}</p>\n ) : (\n <div className=\"space-y-1 p-1\">\n {options.map(option => (\n <ToggleGroupItem\n key={option.value}\n value={option.value}\n isSelected={values.includes(option.value)}\n onClick={() => handleToggle(option.value)}\n >\n {option.label}\n </ToggleGroupItem>\n ))}\n </div>\n )}\n </div>\n {helpText && (\n <p className=\"text-xs text-gray-500 mt-1\">\n {helpText}\n </p>\n )}\n </div>\n );\n};\n\ninterface SwitchProps {\n checked: boolean;\n onCheckedChange: (checked: boolean) => void;\n disabled?: boolean;\n}\n\nexport const Switch: React.FC<SwitchProps> = ({\n checked,\n onCheckedChange,\n disabled = false\n}) => {\n return (\n <button\n type=\"button\"\n role=\"switch\"\n aria-checked={checked}\n disabled={disabled}\n className={cn(\n \"relative inline-flex h-6 w-11 items-center rounded-full transition-colors focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-blue-500\",\n checked ? \"bg-blue-200\" : \"bg-gray-100\",\n disabled ? \"opacity-50 cursor-not-allowed\" : \"cursor-pointer\"\n )}\n onClick={() => !disabled && onCheckedChange(!checked)}\n >\n <span\n className={cn(\n \"inline-block h-4 w-4 transform rounded-full bg-white transition-transform\",\n checked ? \"translate-x-6\" : \"translate-x-1\"\n )}\n />\n </button>\n );\n};"],"names":["Switch","checked","onCheckedChange","disabled","jsx","cn"],"mappings":"2FA0GO,MAAMA,EAAgC,CAAC,CAC5C,QAAAC,EACA,gBAAAC,EACA,SAAAC,EAAW,EACb,IAEIC,EAAAA,IAAC,SAAA,CACC,KAAK,SACL,KAAK,SACL,eAAcH,EACd,SAAAE,EACA,UAAWE,EACT,wLACAJ,EAAU,cAAgB,cAC1BE,EAAW,gCAAkC,gBAAA,EAE/C,QAAS,IAAM,CAACA,GAAYD,EAAgB,CAACD,CAAO,EAEpD,SAAAG,EAAAA,IAAC,OAAA,CACC,UAAWC,EACT,4EACAJ,EAAU,gBAAkB,eAAA,CAC9B,CAAA,CACF,CAAA"}
@@ -1,2 +1,2 @@
1
- import{r as d,j as e}from"./framework-vendor-BUhDPOUZ.js";import{j as v,f as k,h as C,e as P,u as S}from"./index-9Vmc8uCD.js";import{u as j}from"./i18n-vendor-Kbr87Ofu.js";import{D as A}from"./DeleteDialog-DRbWonMu.js";import{a as E}from"./StatusDot-CnuxXTsd.js";import{R as U,P as F,j as z,X as D,U as R,t as T,T as L}from"./icons-vendor-CKgJB3SC.js";const y=()=>{const{t:a}=j(),[g,t]=d.useState([]),[l,f]=d.useState(!0),[h,n]=d.useState(null),[u,c]=d.useState(0),i=d.useCallback(async()=>{try{f(!0);const r=await v("/users");if(!r.success){n(r.message||a("users.fetchError"));return}r&&r.success&&Array.isArray(r.data)?t(r.data):(console.error("Invalid user data format:",r),t([])),n(null)}catch(r){console.error("Error fetching users:",r),n(r instanceof Error?r.message:"Failed to fetch users"),t([])}finally{f(!1)}},[]),x=d.useCallback(()=>{c(r=>r+1)},[]),p=async r=>{try{const s=await P("/users",r);return x(),s}catch(s){return n(s instanceof Error?s.message:"Failed to create user"),null}},m=async(r,s)=>{try{const b=await C(`/users/${r}`,s);return x(),b||null}catch(b){return n(b instanceof Error?b.message:"Failed to update user"),null}},o=async r=>{try{const s=await k(`/users/${r}`);return s!=null&&s.success?(x(),s):(n((s==null?void 0:s.message)||a("users.deleteError")),s)}catch(s){return n(s instanceof Error?s.message:"Failed to delete user"),!1}};return d.useEffect(()=>{i()},[i,u]),{users:g,loading:l,error:h,setError:n,triggerRefresh:x,createUser:p,updateUser:m,deleteUser:o}},I=({onAdd:a,onCancel:g})=>{const{t}=j(),{createUser:l}=y(),[f,h]=d.useState(null),[n,u]=d.useState(!1),[c,i]=d.useState({username:"",password:"",isAdmin:!1,email:""}),x=async m=>{if(m.preventDefault(),h(null),!c.username.trim()){h(t("users.usernameRequired"));return}if(!c.password.trim()){h(t("users.passwordRequired"));return}if(c.password.length<6){h(t("users.passwordTooShort"));return}u(!0);try{const o=await l(c);o!=null&&o.success?a():h((o==null?void 0:o.message)||t("users.createError"))}catch(o){h(o instanceof Error?o.message:t("users.createError"))}finally{u(!1)}},p=m=>{const{name:o,value:r,type:s,checked:b}=m.target;i(w=>({...w,[o]:s==="checkbox"?b:r}))};return e.jsx("div",{className:"fixed inset-0 bg-black/50 z-50 flex items-center justify-center p-4",children:e.jsx("div",{className:"bg-white dark:bg-gray-800 p-8 rounded-xl shadow-2xl max-w-md w-full mx-4 border border-gray-100 dark:border-gray-700",children:e.jsxs("form",{onSubmit:x,children:[e.jsx("h2",{className:"text-xl font-bold text-gray-900 mb-6",children:t("users.addNew")}),f&&e.jsx("div",{className:"bg-red-50 border-l-4 border-red-500 text-red-700 p-4 mb-6 rounded-md",children:e.jsx("p",{className:"text-sm font-medium",children:f})}),e.jsxs("div",{className:"space-y-5",children:[e.jsxs("div",{children:[e.jsxs("label",{htmlFor:"username",className:"block text-sm font-medium text-gray-700 mb-1",children:[t("users.username")," ",e.jsx("span",{className:"text-red-500",children:"*"})]}),e.jsx("input",{type:"text",id:"username",name:"username",value:c.username,onChange:p,placeholder:t("users.usernamePlaceholder"),className:"w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent form-input transition-all duration-200",required:!0,disabled:n})]}),e.jsxs("div",{children:[e.jsx("label",{htmlFor:"email",className:"block text-sm font-medium text-gray-700 mb-1",children:t("users.email")}),e.jsx("input",{type:"email",id:"email",name:"email",value:c.email||"",onChange:p,placeholder:t("users.emailPlaceholder"),className:"w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent form-input transition-all duration-200",disabled:n})]}),e.jsxs("div",{children:[e.jsxs("label",{htmlFor:"password",className:"block text-sm font-medium text-gray-700 mb-1",children:[t("users.password")," ",e.jsx("span",{className:"text-red-500",children:"*"})]}),e.jsx("input",{type:"password",id:"password",name:"password",value:c.password,onChange:p,placeholder:t("users.passwordPlaceholder"),className:"w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent form-input transition-all duration-200",required:!0,disabled:n,minLength:6})]}),e.jsxs("div",{className:"flex items-center pt-2",children:[e.jsx("input",{type:"checkbox",id:"isAdmin",name:"isAdmin",checked:c.isAdmin,onChange:p,className:"h-5 w-5 text-blue-600 focus:ring-blue-500 border-gray-300 rounded transition-colors duration-200",disabled:n}),e.jsx("label",{htmlFor:"isAdmin",className:"ml-3 block text-sm font-medium text-gray-700 cursor-pointer select-none",children:t("users.adminRole")})]})]}),e.jsxs("div",{className:"flex justify-end space-x-2 mt-6",children:[e.jsx("button",{type:"button",onClick:g,className:"hub-btn",disabled:n,children:t("common.cancel")}),e.jsxs("button",{type:"submit",className:"hub-btn primary",disabled:n,children:[n&&e.jsxs("svg",{className:"animate-spin -ml-1 mr-2 h-4 w-4 text-white",xmlns:"http://www.w3.org/2000/svg",fill:"none",viewBox:"0 0 24 24",children:[e.jsx("circle",{className:"opacity-25",cx:"12",cy:"12",r:"10",stroke:"currentColor",strokeWidth:"4"}),e.jsx("path",{className:"opacity-75",fill:"currentColor",d:"M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"})]}),t(n?"common.creating":"users.create")]})]})]})})})},q=({user:a,onEdit:g,onCancel:t})=>{const{t:l}=j(),{updateUser:f}=y(),[h,n]=d.useState(null),[u,c]=d.useState(!1),[i,x]=d.useState({isAdmin:a.isAdmin,email:a.email||"",newPassword:"",confirmPassword:""}),p=async o=>{if(o.preventDefault(),n(null),i.newPassword&&i.newPassword!==i.confirmPassword){n(l("users.passwordMismatch"));return}if(i.newPassword&&i.newPassword.length<6){n(l("users.passwordTooShort"));return}c(!0);try{const r={isAdmin:i.isAdmin,email:i.email};i.newPassword&&(r.newPassword=i.newPassword);const s=await f(a.username,r);s!=null&&s.success?g():n((s==null?void 0:s.message)||l("users.updateError"))}catch(r){n(r instanceof Error?r.message:l("users.updateError"))}finally{c(!1)}},m=o=>{const{name:r,value:s,type:b,checked:w}=o.target;x(N=>({...N,[r]:b==="checkbox"?w:s}))};return e.jsx("div",{className:"fixed inset-0 bg-black/50 z-50 flex items-center justify-center p-4",children:e.jsx("div",{className:"bg-white dark:bg-gray-800 p-8 rounded-xl shadow-2xl max-w-md w-full mx-4 border border-gray-100 dark:border-gray-700",children:e.jsxs("form",{onSubmit:p,children:[e.jsxs("h2",{className:"text-xl font-bold text-gray-900 mb-6",children:[l("users.edit")," - ",e.jsx("span",{className:"text-blue-600",children:a.username})]}),h&&e.jsx("div",{className:"bg-red-50 border-l-4 border-red-500 text-red-700 p-4 mb-6 rounded-md",children:e.jsx("p",{className:"text-sm font-medium",children:h})}),e.jsxs("div",{className:"space-y-5",children:[e.jsxs("div",{className:"flex items-center pt-2",children:[e.jsx("input",{type:"checkbox",id:"isAdmin",name:"isAdmin",checked:i.isAdmin,onChange:m,className:"h-5 w-5 text-blue-600 focus:ring-blue-500 border-gray-300 rounded transition-colors duration-200",disabled:u}),e.jsx("label",{htmlFor:"isAdmin",className:"ml-3 block text-sm font-medium text-gray-700 cursor-pointer select-none",children:l("users.adminRole")})]}),e.jsxs("div",{children:[e.jsx("label",{htmlFor:"email",className:"block text-sm font-medium text-gray-700 mb-1",children:l("users.email")}),e.jsx("input",{type:"email",id:"email",name:"email",value:i.email,onChange:m,placeholder:l("users.emailPlaceholder"),className:"w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent form-input transition-all duration-200",disabled:u})]}),e.jsxs("div",{className:"border-t border-gray-100 dark:border-gray-700 pt-4 mt-2",children:[e.jsx("p",{className:"text-xs text-gray-500 uppercase font-semibold tracking-wider mb-3",children:l("users.changePassword")}),e.jsxs("div",{className:"space-y-4",children:[e.jsxs("div",{children:[e.jsx("label",{htmlFor:"newPassword",className:"block text-sm font-medium text-gray-700 mb-1",children:l("users.newPassword")}),e.jsx("input",{type:"password",id:"newPassword",name:"newPassword",value:i.newPassword,onChange:m,placeholder:l("users.newPasswordPlaceholder"),className:"w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent form-input transition-all duration-200",disabled:u,minLength:6})]}),i.newPassword&&e.jsxs("div",{className:"animate-fadeIn",children:[e.jsx("label",{htmlFor:"confirmPassword",className:"block text-sm font-medium text-gray-700 mb-1",children:l("users.confirmPassword")}),e.jsx("input",{type:"password",id:"confirmPassword",name:"confirmPassword",value:i.confirmPassword,onChange:m,placeholder:l("users.confirmPasswordPlaceholder"),className:"w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent form-input transition-all duration-200",disabled:u,minLength:6})]})]})]})]}),e.jsxs("div",{className:"flex justify-end space-x-2 mt-6",children:[e.jsx("button",{type:"button",onClick:t,className:"hub-btn",disabled:u,children:l("common.cancel")}),e.jsxs("button",{type:"submit",className:"hub-btn primary",disabled:u,children:[u&&e.jsxs("svg",{className:"animate-spin -ml-1 mr-2 h-4 w-4 text-white",xmlns:"http://www.w3.org/2000/svg",fill:"none",viewBox:"0 0 24 24",children:[e.jsx("circle",{className:"opacity-25",cx:"12",cy:"12",r:"10",stroke:"currentColor",strokeWidth:"4"}),e.jsx("path",{className:"opacity-75",fill:"currentColor",d:"M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"})]}),l(u?"common.updating":"users.update")]})]})]})})})},V=()=>{const{t:a}=j(),{auth:g}=S(),t=g.user,{users:l,loading:f,error:h,setError:n,deleteUser:u,triggerRefresh:c}=y(),[i,x]=d.useState(null),[p,m]=d.useState(!1),[o,r]=d.useState(null);return t!=null&&t.isAdmin?e.jsxs("div",{children:[e.jsxs("div",{className:"flex items-end justify-between gap-4 mb-6",children:[e.jsxs("div",{children:[e.jsx("h1",{className:"hub-h1",children:a("pages.users.title")}),e.jsxs("p",{className:"hub-sub",children:[e.jsx("span",{className:"hub-num",children:l.length})," ",a("nav.users").toLowerCase()]})]}),e.jsxs("div",{className:"flex gap-2",children:[e.jsxs("button",{className:"hub-btn",onClick:()=>c(),"aria-label":a("common.refresh"),children:[e.jsx(U,{size:13})," ",a("common.refresh")]}),e.jsxs("button",{className:"hub-btn primary",onClick:()=>m(!0),children:[e.jsx(F,{size:13})," ",a("users.add")]})]})]}),h&&e.jsxs("div",{className:"hub-card flex items-center justify-between gap-3 mb-4",style:{padding:"10px 14px",borderColor:"oklch(0.85 0.1 25)",background:"oklch(0.97 0.03 25)",color:"oklch(0.4 0.18 25)"},children:[e.jsxs("div",{className:"flex items-center gap-2 min-w-0",children:[e.jsx(z,{size:14,className:"flex-shrink-0"}),e.jsx("span",{className:"truncate text-[13px]",children:h})]}),e.jsx("button",{className:"hub-icon-btn sm",onClick:()=>n(null),children:e.jsx(D,{size:13})})]}),f?e.jsx("div",{className:"hub-card p-10 text-center",style:{color:"var(--hub-ink-3)"},children:a("app.loading")}):l.length===0?e.jsx("div",{className:"hub-card p-10 text-center",style:{color:"var(--hub-ink-3)"},children:e.jsxs("div",{className:"flex flex-col items-center gap-3",children:[e.jsx("div",{className:"grid place-items-center",style:{width:40,height:40,borderRadius:10,border:"1px solid var(--hub-line)",background:"var(--hub-bg-2)"},children:e.jsx(R,{size:18})}),e.jsx("div",{className:"font-medium",style:{color:"var(--hub-ink-2)",fontSize:13},children:a("users.noUsers")}),e.jsx("button",{onClick:()=>m(!0),className:"hub-btn ghost sm",style:{color:"var(--hub-accent)"},children:a("users.addFirst")})]})}):e.jsxs("div",{className:"hub-card overflow-hidden",children:[e.jsxs("div",{className:"hub-row head hub-mono",style:{gridTemplateColumns:"1.6fr 1.2fr 100px 100px"},children:[e.jsx("div",{children:a("users.username")}),e.jsx("div",{children:a("users.email")}),e.jsx("div",{children:a("users.role")}),e.jsx("div",{className:"text-right",children:a("users.actions")})]}),l.map(s=>{const b=(t==null?void 0:t.username)===s.username;return e.jsxs("div",{className:"hub-row hover",style:{gridTemplateColumns:"1.6fr 1.2fr 100px 100px"},children:[e.jsxs("div",{className:"flex items-center gap-3 min-w-0",children:[e.jsx("div",{className:"grid place-items-center flex-shrink-0 hub-mono",style:{width:28,height:28,borderRadius:7,background:"var(--hub-bg-2)",border:"1px solid var(--hub-line)",color:"var(--hub-ink-2)",fontWeight:600,fontSize:12},children:s.username.charAt(0).toUpperCase()}),e.jsx("span",{className:"hub-mono truncate",style:{fontSize:13,color:"var(--hub-ink)"},children:s.username}),b&&e.jsx("span",{className:"hub-tag accent",style:{fontSize:10},children:a("users.currentUser")})]}),e.jsx("div",{className:"flex items-center min-w-0",children:e.jsx("span",{className:"truncate",style:{fontSize:13,color:s.email?"var(--hub-ink)":"var(--hub-ink-3)"},children:s.email||"—"})}),e.jsx("div",{children:e.jsx(E,{kind:s.isAdmin?"ok":"muted",label:s.isAdmin?a("users.admin"):a("users.user")})}),e.jsxs("div",{className:"flex justify-end gap-1",children:[e.jsx("button",{onClick:()=>x(s),className:"hub-icon-btn sm",title:a("users.edit"),children:e.jsx(T,{size:13})}),!b&&e.jsx("button",{onClick:()=>r(s.username),className:"hub-icon-btn sm",title:a("users.delete"),style:{color:"var(--hub-err)"},children:e.jsx(L,{size:13})})]})]},s.username)})]}),p&&e.jsx(I,{onAdd:()=>{m(!1),c()},onCancel:()=>m(!1)}),i&&e.jsx(q,{user:i,onEdit:()=>{x(null),c()},onCancel:()=>x(null)}),e.jsx(A,{isOpen:!!o,onClose:()=>r(null),onConfirm:async()=>{if(o){const s=await u(o);s!=null&&s.success||n((s==null?void 0:s.message)||a("users.deleteError")),r(null)}},serverName:o||"",isGroup:!1,isUser:!0})]}):e.jsx("div",{className:"hub-card p-6 text-center",style:{color:"var(--hub-err)"},children:a("users.adminRequired")})};export{V as default};
2
- //# sourceMappingURL=UsersPage-B8zPaI6u.js.map
1
+ import{r as d,j as e}from"./framework-vendor-BUhDPOUZ.js";import{j as v,f as k,h as C,e as P,u as S}from"./index-otG7s0Ro.js";import{u as j}from"./i18n-vendor-Kbr87Ofu.js";import{D as A}from"./DeleteDialog-DRbWonMu.js";import{a as E}from"./StatusDot-C-kTn-AA.js";import{R as U,P as F,j as z,X as D,U as R,t as T,T as L}from"./icons-vendor-CKgJB3SC.js";const y=()=>{const{t:a}=j(),[g,t]=d.useState([]),[l,f]=d.useState(!0),[h,n]=d.useState(null),[u,c]=d.useState(0),i=d.useCallback(async()=>{try{f(!0);const r=await v("/users");if(!r.success){n(r.message||a("users.fetchError"));return}r&&r.success&&Array.isArray(r.data)?t(r.data):(console.error("Invalid user data format:",r),t([])),n(null)}catch(r){console.error("Error fetching users:",r),n(r instanceof Error?r.message:"Failed to fetch users"),t([])}finally{f(!1)}},[]),x=d.useCallback(()=>{c(r=>r+1)},[]),p=async r=>{try{const s=await P("/users",r);return x(),s}catch(s){return n(s instanceof Error?s.message:"Failed to create user"),null}},m=async(r,s)=>{try{const b=await C(`/users/${r}`,s);return x(),b||null}catch(b){return n(b instanceof Error?b.message:"Failed to update user"),null}},o=async r=>{try{const s=await k(`/users/${r}`);return s!=null&&s.success?(x(),s):(n((s==null?void 0:s.message)||a("users.deleteError")),s)}catch(s){return n(s instanceof Error?s.message:"Failed to delete user"),!1}};return d.useEffect(()=>{i()},[i,u]),{users:g,loading:l,error:h,setError:n,triggerRefresh:x,createUser:p,updateUser:m,deleteUser:o}},I=({onAdd:a,onCancel:g})=>{const{t}=j(),{createUser:l}=y(),[f,h]=d.useState(null),[n,u]=d.useState(!1),[c,i]=d.useState({username:"",password:"",isAdmin:!1,email:""}),x=async m=>{if(m.preventDefault(),h(null),!c.username.trim()){h(t("users.usernameRequired"));return}if(!c.password.trim()){h(t("users.passwordRequired"));return}if(c.password.length<6){h(t("users.passwordTooShort"));return}u(!0);try{const o=await l(c);o!=null&&o.success?a():h((o==null?void 0:o.message)||t("users.createError"))}catch(o){h(o instanceof Error?o.message:t("users.createError"))}finally{u(!1)}},p=m=>{const{name:o,value:r,type:s,checked:b}=m.target;i(w=>({...w,[o]:s==="checkbox"?b:r}))};return e.jsx("div",{className:"fixed inset-0 bg-black/50 z-50 flex items-center justify-center p-4",children:e.jsx("div",{className:"bg-white dark:bg-gray-800 p-8 rounded-xl shadow-2xl max-w-md w-full mx-4 border border-gray-100 dark:border-gray-700",children:e.jsxs("form",{onSubmit:x,children:[e.jsx("h2",{className:"text-xl font-bold text-gray-900 mb-6",children:t("users.addNew")}),f&&e.jsx("div",{className:"bg-red-50 border-l-4 border-red-500 text-red-700 p-4 mb-6 rounded-md",children:e.jsx("p",{className:"text-sm font-medium",children:f})}),e.jsxs("div",{className:"space-y-5",children:[e.jsxs("div",{children:[e.jsxs("label",{htmlFor:"username",className:"block text-sm font-medium text-gray-700 mb-1",children:[t("users.username")," ",e.jsx("span",{className:"text-red-500",children:"*"})]}),e.jsx("input",{type:"text",id:"username",name:"username",value:c.username,onChange:p,placeholder:t("users.usernamePlaceholder"),className:"w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent form-input transition-all duration-200",required:!0,disabled:n})]}),e.jsxs("div",{children:[e.jsx("label",{htmlFor:"email",className:"block text-sm font-medium text-gray-700 mb-1",children:t("users.email")}),e.jsx("input",{type:"email",id:"email",name:"email",value:c.email||"",onChange:p,placeholder:t("users.emailPlaceholder"),className:"w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent form-input transition-all duration-200",disabled:n})]}),e.jsxs("div",{children:[e.jsxs("label",{htmlFor:"password",className:"block text-sm font-medium text-gray-700 mb-1",children:[t("users.password")," ",e.jsx("span",{className:"text-red-500",children:"*"})]}),e.jsx("input",{type:"password",id:"password",name:"password",value:c.password,onChange:p,placeholder:t("users.passwordPlaceholder"),className:"w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent form-input transition-all duration-200",required:!0,disabled:n,minLength:6})]}),e.jsxs("div",{className:"flex items-center pt-2",children:[e.jsx("input",{type:"checkbox",id:"isAdmin",name:"isAdmin",checked:c.isAdmin,onChange:p,className:"h-5 w-5 text-blue-600 focus:ring-blue-500 border-gray-300 rounded transition-colors duration-200",disabled:n}),e.jsx("label",{htmlFor:"isAdmin",className:"ml-3 block text-sm font-medium text-gray-700 cursor-pointer select-none",children:t("users.adminRole")})]})]}),e.jsxs("div",{className:"flex justify-end space-x-2 mt-6",children:[e.jsx("button",{type:"button",onClick:g,className:"hub-btn",disabled:n,children:t("common.cancel")}),e.jsxs("button",{type:"submit",className:"hub-btn primary",disabled:n,children:[n&&e.jsxs("svg",{className:"animate-spin -ml-1 mr-2 h-4 w-4 text-white",xmlns:"http://www.w3.org/2000/svg",fill:"none",viewBox:"0 0 24 24",children:[e.jsx("circle",{className:"opacity-25",cx:"12",cy:"12",r:"10",stroke:"currentColor",strokeWidth:"4"}),e.jsx("path",{className:"opacity-75",fill:"currentColor",d:"M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"})]}),t(n?"common.creating":"users.create")]})]})]})})})},q=({user:a,onEdit:g,onCancel:t})=>{const{t:l}=j(),{updateUser:f}=y(),[h,n]=d.useState(null),[u,c]=d.useState(!1),[i,x]=d.useState({isAdmin:a.isAdmin,email:a.email||"",newPassword:"",confirmPassword:""}),p=async o=>{if(o.preventDefault(),n(null),i.newPassword&&i.newPassword!==i.confirmPassword){n(l("users.passwordMismatch"));return}if(i.newPassword&&i.newPassword.length<6){n(l("users.passwordTooShort"));return}c(!0);try{const r={isAdmin:i.isAdmin,email:i.email};i.newPassword&&(r.newPassword=i.newPassword);const s=await f(a.username,r);s!=null&&s.success?g():n((s==null?void 0:s.message)||l("users.updateError"))}catch(r){n(r instanceof Error?r.message:l("users.updateError"))}finally{c(!1)}},m=o=>{const{name:r,value:s,type:b,checked:w}=o.target;x(N=>({...N,[r]:b==="checkbox"?w:s}))};return e.jsx("div",{className:"fixed inset-0 bg-black/50 z-50 flex items-center justify-center p-4",children:e.jsx("div",{className:"bg-white dark:bg-gray-800 p-8 rounded-xl shadow-2xl max-w-md w-full mx-4 border border-gray-100 dark:border-gray-700",children:e.jsxs("form",{onSubmit:p,children:[e.jsxs("h2",{className:"text-xl font-bold text-gray-900 mb-6",children:[l("users.edit")," - ",e.jsx("span",{className:"text-blue-600",children:a.username})]}),h&&e.jsx("div",{className:"bg-red-50 border-l-4 border-red-500 text-red-700 p-4 mb-6 rounded-md",children:e.jsx("p",{className:"text-sm font-medium",children:h})}),e.jsxs("div",{className:"space-y-5",children:[e.jsxs("div",{className:"flex items-center pt-2",children:[e.jsx("input",{type:"checkbox",id:"isAdmin",name:"isAdmin",checked:i.isAdmin,onChange:m,className:"h-5 w-5 text-blue-600 focus:ring-blue-500 border-gray-300 rounded transition-colors duration-200",disabled:u}),e.jsx("label",{htmlFor:"isAdmin",className:"ml-3 block text-sm font-medium text-gray-700 cursor-pointer select-none",children:l("users.adminRole")})]}),e.jsxs("div",{children:[e.jsx("label",{htmlFor:"email",className:"block text-sm font-medium text-gray-700 mb-1",children:l("users.email")}),e.jsx("input",{type:"email",id:"email",name:"email",value:i.email,onChange:m,placeholder:l("users.emailPlaceholder"),className:"w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent form-input transition-all duration-200",disabled:u})]}),e.jsxs("div",{className:"border-t border-gray-100 dark:border-gray-700 pt-4 mt-2",children:[e.jsx("p",{className:"text-xs text-gray-500 uppercase font-semibold tracking-wider mb-3",children:l("users.changePassword")}),e.jsxs("div",{className:"space-y-4",children:[e.jsxs("div",{children:[e.jsx("label",{htmlFor:"newPassword",className:"block text-sm font-medium text-gray-700 mb-1",children:l("users.newPassword")}),e.jsx("input",{type:"password",id:"newPassword",name:"newPassword",value:i.newPassword,onChange:m,placeholder:l("users.newPasswordPlaceholder"),className:"w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent form-input transition-all duration-200",disabled:u,minLength:6})]}),i.newPassword&&e.jsxs("div",{className:"animate-fadeIn",children:[e.jsx("label",{htmlFor:"confirmPassword",className:"block text-sm font-medium text-gray-700 mb-1",children:l("users.confirmPassword")}),e.jsx("input",{type:"password",id:"confirmPassword",name:"confirmPassword",value:i.confirmPassword,onChange:m,placeholder:l("users.confirmPasswordPlaceholder"),className:"w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent form-input transition-all duration-200",disabled:u,minLength:6})]})]})]})]}),e.jsxs("div",{className:"flex justify-end space-x-2 mt-6",children:[e.jsx("button",{type:"button",onClick:t,className:"hub-btn",disabled:u,children:l("common.cancel")}),e.jsxs("button",{type:"submit",className:"hub-btn primary",disabled:u,children:[u&&e.jsxs("svg",{className:"animate-spin -ml-1 mr-2 h-4 w-4 text-white",xmlns:"http://www.w3.org/2000/svg",fill:"none",viewBox:"0 0 24 24",children:[e.jsx("circle",{className:"opacity-25",cx:"12",cy:"12",r:"10",stroke:"currentColor",strokeWidth:"4"}),e.jsx("path",{className:"opacity-75",fill:"currentColor",d:"M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"})]}),l(u?"common.updating":"users.update")]})]})]})})})},V=()=>{const{t:a}=j(),{auth:g}=S(),t=g.user,{users:l,loading:f,error:h,setError:n,deleteUser:u,triggerRefresh:c}=y(),[i,x]=d.useState(null),[p,m]=d.useState(!1),[o,r]=d.useState(null);return t!=null&&t.isAdmin?e.jsxs("div",{children:[e.jsxs("div",{className:"flex items-end justify-between gap-4 mb-6",children:[e.jsxs("div",{children:[e.jsx("h1",{className:"hub-h1",children:a("pages.users.title")}),e.jsxs("p",{className:"hub-sub",children:[e.jsx("span",{className:"hub-num",children:l.length})," ",a("nav.users").toLowerCase()]})]}),e.jsxs("div",{className:"flex gap-2",children:[e.jsxs("button",{className:"hub-btn",onClick:()=>c(),"aria-label":a("common.refresh"),children:[e.jsx(U,{size:13})," ",a("common.refresh")]}),e.jsxs("button",{className:"hub-btn primary",onClick:()=>m(!0),children:[e.jsx(F,{size:13})," ",a("users.add")]})]})]}),h&&e.jsxs("div",{className:"hub-card flex items-center justify-between gap-3 mb-4",style:{padding:"10px 14px",borderColor:"oklch(0.85 0.1 25)",background:"oklch(0.97 0.03 25)",color:"oklch(0.4 0.18 25)"},children:[e.jsxs("div",{className:"flex items-center gap-2 min-w-0",children:[e.jsx(z,{size:14,className:"flex-shrink-0"}),e.jsx("span",{className:"truncate text-[13px]",children:h})]}),e.jsx("button",{className:"hub-icon-btn sm",onClick:()=>n(null),children:e.jsx(D,{size:13})})]}),f?e.jsx("div",{className:"hub-card p-10 text-center",style:{color:"var(--hub-ink-3)"},children:a("app.loading")}):l.length===0?e.jsx("div",{className:"hub-card p-10 text-center",style:{color:"var(--hub-ink-3)"},children:e.jsxs("div",{className:"flex flex-col items-center gap-3",children:[e.jsx("div",{className:"grid place-items-center",style:{width:40,height:40,borderRadius:10,border:"1px solid var(--hub-line)",background:"var(--hub-bg-2)"},children:e.jsx(R,{size:18})}),e.jsx("div",{className:"font-medium",style:{color:"var(--hub-ink-2)",fontSize:13},children:a("users.noUsers")}),e.jsx("button",{onClick:()=>m(!0),className:"hub-btn ghost sm",style:{color:"var(--hub-accent)"},children:a("users.addFirst")})]})}):e.jsxs("div",{className:"hub-card overflow-hidden",children:[e.jsxs("div",{className:"hub-row head hub-mono",style:{gridTemplateColumns:"1.6fr 1.2fr 100px 100px"},children:[e.jsx("div",{children:a("users.username")}),e.jsx("div",{children:a("users.email")}),e.jsx("div",{children:a("users.role")}),e.jsx("div",{className:"text-right",children:a("users.actions")})]}),l.map(s=>{const b=(t==null?void 0:t.username)===s.username;return e.jsxs("div",{className:"hub-row hover",style:{gridTemplateColumns:"1.6fr 1.2fr 100px 100px"},children:[e.jsxs("div",{className:"flex items-center gap-3 min-w-0",children:[e.jsx("div",{className:"grid place-items-center flex-shrink-0 hub-mono",style:{width:28,height:28,borderRadius:7,background:"var(--hub-bg-2)",border:"1px solid var(--hub-line)",color:"var(--hub-ink-2)",fontWeight:600,fontSize:12},children:s.username.charAt(0).toUpperCase()}),e.jsx("span",{className:"hub-mono truncate",style:{fontSize:13,color:"var(--hub-ink)"},children:s.username}),b&&e.jsx("span",{className:"hub-tag accent",style:{fontSize:10},children:a("users.currentUser")})]}),e.jsx("div",{className:"flex items-center min-w-0",children:e.jsx("span",{className:"truncate",style:{fontSize:13,color:s.email?"var(--hub-ink)":"var(--hub-ink-3)"},children:s.email||"—"})}),e.jsx("div",{children:e.jsx(E,{kind:s.isAdmin?"ok":"muted",label:s.isAdmin?a("users.admin"):a("users.user")})}),e.jsxs("div",{className:"flex justify-end gap-1",children:[e.jsx("button",{onClick:()=>x(s),className:"hub-icon-btn sm",title:a("users.edit"),children:e.jsx(T,{size:13})}),!b&&e.jsx("button",{onClick:()=>r(s.username),className:"hub-icon-btn sm",title:a("users.delete"),style:{color:"var(--hub-err)"},children:e.jsx(L,{size:13})})]})]},s.username)})]}),p&&e.jsx(I,{onAdd:()=>{m(!1),c()},onCancel:()=>m(!1)}),i&&e.jsx(q,{user:i,onEdit:()=>{x(null),c()},onCancel:()=>x(null)}),e.jsx(A,{isOpen:!!o,onClose:()=>r(null),onConfirm:async()=>{if(o){const s=await u(o);s!=null&&s.success||n((s==null?void 0:s.message)||a("users.deleteError")),r(null)}},serverName:o||"",isGroup:!1,isUser:!0})]}):e.jsx("div",{className:"hub-card p-6 text-center",style:{color:"var(--hub-err)"},children:a("users.adminRequired")})};export{V as default};
2
+ //# sourceMappingURL=UsersPage-MDtzW9-F.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"UsersPage-B8zPaI6u.js","sources":["../../src/hooks/useUserData.ts","../../src/components/AddUserForm.tsx","../../src/components/EditUserForm.tsx","../../src/pages/UsersPage.tsx"],"sourcesContent":["import { useState, useEffect, useCallback } from 'react';\nimport { useTranslation } from 'react-i18next';\nimport { User, ApiResponse, UserFormData, UserUpdateData } from '@/types';\nimport { apiDelete, apiGet, apiPost, apiPut } from '../utils/fetchInterceptor';\n\nexport const useUserData = () => {\n const { t } = useTranslation();\n const [users, setUsers] = useState<User[]>([]);\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState<string | null>(null);\n const [refreshKey, setRefreshKey] = useState(0);\n\n const fetchUsers = useCallback(async () => {\n try {\n setLoading(true);\n const data: ApiResponse<User[]> = await apiGet('/users');\n if (!data.success) {\n setError(data.message || t('users.fetchError'));\n return;\n }\n\n if (data && data.success && Array.isArray(data.data)) {\n setUsers(data.data);\n } else {\n console.error('Invalid user data format:', data);\n setUsers([]);\n }\n\n setError(null);\n } catch (err) {\n console.error('Error fetching users:', err);\n setError(err instanceof Error ? err.message : 'Failed to fetch users');\n setUsers([]);\n } finally {\n setLoading(false);\n }\n }, []);\n\n // Trigger a refresh of the users data\n const triggerRefresh = useCallback(() => {\n setRefreshKey((prev) => prev + 1);\n }, []);\n\n // Create a new user\n const createUser = async (userData: UserFormData) => {\n try {\n const result: ApiResponse<User> = await apiPost('/users', userData);\n triggerRefresh();\n return result;\n } catch (err) {\n setError(err instanceof Error ? err.message : 'Failed to create user');\n return null;\n }\n };\n\n // Update an existing user\n const updateUser = async (username: string, data: UserUpdateData) => {\n try {\n const result: ApiResponse<User> = await apiPut(`/users/${username}`, data);\n triggerRefresh();\n return result || null;\n } catch (err) {\n setError(err instanceof Error ? err.message : 'Failed to update user');\n return null;\n }\n };\n\n // Delete a user\n const deleteUser = async (username: string) => {\n try {\n const result = await apiDelete(`/users/${username}`);\n if (!result?.success) {\n setError(result?.message || t('users.deleteError'));\n return result;\n }\n\n triggerRefresh();\n return result;\n } catch (err) {\n setError(err instanceof Error ? err.message : 'Failed to delete user');\n return false;\n }\n };\n\n // Fetch users when the component mounts or refreshKey changes\n useEffect(() => {\n fetchUsers();\n }, [fetchUsers, refreshKey]);\n\n return {\n users,\n loading,\n error,\n setError,\n triggerRefresh,\n createUser,\n updateUser,\n deleteUser,\n };\n};\n","import { useState } from 'react';\nimport { useTranslation } from 'react-i18next';\nimport { useUserData } from '@/hooks/useUserData';\nimport { UserFormData } from '@/types';\n\ninterface AddUserFormProps {\n onAdd: () => void;\n onCancel: () => void;\n}\n\nconst AddUserForm = ({ onAdd, onCancel }: AddUserFormProps) => {\n const { t } = useTranslation();\n const { createUser } = useUserData();\n const [error, setError] = useState<string | null>(null);\n const [isSubmitting, setIsSubmitting] = useState(false);\n\n const [formData, setFormData] = useState<UserFormData>({\n username: '',\n password: '',\n isAdmin: false,\n email: '',\n });\n\n const handleSubmit = async (e: React.FormEvent) => {\n e.preventDefault();\n setError(null);\n\n if (!formData.username.trim()) {\n setError(t('users.usernameRequired'));\n return;\n }\n\n if (!formData.password.trim()) {\n setError(t('users.passwordRequired'));\n return;\n }\n\n if (formData.password.length < 6) {\n setError(t('users.passwordTooShort'));\n return;\n }\n\n setIsSubmitting(true);\n\n try {\n const result = await createUser(formData);\n if (result?.success) {\n onAdd();\n } else {\n setError(result?.message || t('users.createError'));\n }\n } catch (err) {\n setError(err instanceof Error ? err.message : t('users.createError'));\n } finally {\n setIsSubmitting(false);\n }\n };\n\n const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {\n const { name, value, type, checked } = e.target;\n setFormData((prev) => ({\n ...prev,\n [name]: type === 'checkbox' ? checked : value,\n }));\n };\n\n return (\n <div className=\"fixed inset-0 bg-black/50 z-50 flex items-center justify-center p-4\">\n <div className=\"bg-white dark:bg-gray-800 p-8 rounded-xl shadow-2xl max-w-md w-full mx-4 border border-gray-100 dark:border-gray-700\">\n <form onSubmit={handleSubmit}>\n <h2 className=\"text-xl font-bold text-gray-900 mb-6\">{t('users.addNew')}</h2>\n\n {error && (\n <div className=\"bg-red-50 border-l-4 border-red-500 text-red-700 p-4 mb-6 rounded-md\">\n <p className=\"text-sm font-medium\">{error}</p>\n </div>\n )}\n\n <div className=\"space-y-5\">\n <div>\n <label htmlFor=\"username\" className=\"block text-sm font-medium text-gray-700 mb-1\">\n {t('users.username')} <span className=\"text-red-500\">*</span>\n </label>\n <input\n type=\"text\"\n id=\"username\"\n name=\"username\"\n value={formData.username}\n onChange={handleInputChange}\n placeholder={t('users.usernamePlaceholder')}\n className=\"w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent form-input transition-all duration-200\"\n required\n disabled={isSubmitting}\n />\n </div>\n\n <div>\n <label htmlFor=\"email\" className=\"block text-sm font-medium text-gray-700 mb-1\">\n {t('users.email')}\n </label>\n <input\n type=\"email\"\n id=\"email\"\n name=\"email\"\n value={formData.email || ''}\n onChange={handleInputChange}\n placeholder={t('users.emailPlaceholder')}\n className=\"w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent form-input transition-all duration-200\"\n disabled={isSubmitting}\n />\n </div>\n\n <div>\n <label htmlFor=\"password\" className=\"block text-sm font-medium text-gray-700 mb-1\">\n {t('users.password')} <span className=\"text-red-500\">*</span>\n </label>\n <input\n type=\"password\"\n id=\"password\"\n name=\"password\"\n value={formData.password}\n onChange={handleInputChange}\n placeholder={t('users.passwordPlaceholder')}\n className=\"w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent form-input transition-all duration-200\"\n required\n disabled={isSubmitting}\n minLength={6}\n />\n </div>\n\n <div className=\"flex items-center pt-2\">\n <input\n type=\"checkbox\"\n id=\"isAdmin\"\n name=\"isAdmin\"\n checked={formData.isAdmin}\n onChange={handleInputChange}\n className=\"h-5 w-5 text-blue-600 focus:ring-blue-500 border-gray-300 rounded transition-colors duration-200\"\n disabled={isSubmitting}\n />\n <label\n htmlFor=\"isAdmin\"\n className=\"ml-3 block text-sm font-medium text-gray-700 cursor-pointer select-none\"\n >\n {t('users.adminRole')}\n </label>\n </div>\n </div>\n\n <div className=\"flex justify-end space-x-2 mt-6\">\n <button\n type=\"button\"\n onClick={onCancel}\n className=\"hub-btn\"\n disabled={isSubmitting}\n >\n {t('common.cancel')}\n </button>\n <button\n type=\"submit\"\n className=\"hub-btn primary\"\n disabled={isSubmitting}\n >\n {isSubmitting && (\n <svg\n className=\"animate-spin -ml-1 mr-2 h-4 w-4 text-white\"\n xmlns=\"http://www.w3.org/2000/svg\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n >\n <circle\n className=\"opacity-25\"\n cx=\"12\"\n cy=\"12\"\n r=\"10\"\n stroke=\"currentColor\"\n strokeWidth=\"4\"\n ></circle>\n <path\n className=\"opacity-75\"\n fill=\"currentColor\"\n d=\"M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z\"\n ></path>\n </svg>\n )}\n {isSubmitting ? t('common.creating') : t('users.create')}\n </button>\n </div>\n </form>\n </div>\n </div>\n );\n};\n\nexport default AddUserForm;\n","import { useState } from 'react';\nimport { useTranslation } from 'react-i18next';\nimport { useUserData } from '@/hooks/useUserData';\nimport { User, UserUpdateData } from '@/types';\n\ninterface EditUserFormProps {\n user: User;\n onEdit: () => void;\n onCancel: () => void;\n}\n\nconst EditUserForm = ({ user, onEdit, onCancel }: EditUserFormProps) => {\n const { t } = useTranslation();\n const { updateUser } = useUserData();\n const [error, setError] = useState<string | null>(null);\n const [isSubmitting, setIsSubmitting] = useState(false);\n\n const [formData, setFormData] = useState({\n isAdmin: user.isAdmin,\n email: user.email || '',\n newPassword: '',\n confirmPassword: '',\n });\n\n const handleSubmit = async (e: React.FormEvent) => {\n e.preventDefault();\n setError(null);\n\n // Validate passwords match if changing password\n if (formData.newPassword && formData.newPassword !== formData.confirmPassword) {\n setError(t('users.passwordMismatch'));\n return;\n }\n\n if (formData.newPassword && formData.newPassword.length < 6) {\n setError(t('users.passwordTooShort'));\n return;\n }\n\n setIsSubmitting(true);\n\n try {\n const updateData: UserUpdateData = {\n isAdmin: formData.isAdmin,\n email: formData.email,\n };\n\n if (formData.newPassword) {\n updateData.newPassword = formData.newPassword;\n }\n\n const result = await updateUser(user.username, updateData);\n if (result?.success) {\n onEdit();\n } else {\n setError(result?.message || t('users.updateError'));\n }\n } catch (err) {\n setError(err instanceof Error ? err.message : t('users.updateError'));\n } finally {\n setIsSubmitting(false);\n }\n };\n\n const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {\n const { name, value, type, checked } = e.target;\n setFormData((prev) => ({\n ...prev,\n [name]: type === 'checkbox' ? checked : value,\n }));\n };\n\n return (\n <div className=\"fixed inset-0 bg-black/50 z-50 flex items-center justify-center p-4\">\n <div className=\"bg-white dark:bg-gray-800 p-8 rounded-xl shadow-2xl max-w-md w-full mx-4 border border-gray-100 dark:border-gray-700\">\n <form onSubmit={handleSubmit}>\n <h2 className=\"text-xl font-bold text-gray-900 mb-6\">\n {t('users.edit')} - <span className=\"text-blue-600\">{user.username}</span>\n </h2>\n\n {error && (\n <div className=\"bg-red-50 border-l-4 border-red-500 text-red-700 p-4 mb-6 rounded-md\">\n <p className=\"text-sm font-medium\">{error}</p>\n </div>\n )}\n\n <div className=\"space-y-5\">\n <div className=\"flex items-center pt-2\">\n <input\n type=\"checkbox\"\n id=\"isAdmin\"\n name=\"isAdmin\"\n checked={formData.isAdmin}\n onChange={handleInputChange}\n className=\"h-5 w-5 text-blue-600 focus:ring-blue-500 border-gray-300 rounded transition-colors duration-200\"\n disabled={isSubmitting}\n />\n <label\n htmlFor=\"isAdmin\"\n className=\"ml-3 block text-sm font-medium text-gray-700 cursor-pointer select-none\"\n >\n {t('users.adminRole')}\n </label>\n </div>\n\n <div>\n <label htmlFor=\"email\" className=\"block text-sm font-medium text-gray-700 mb-1\">\n {t('users.email')}\n </label>\n <input\n type=\"email\"\n id=\"email\"\n name=\"email\"\n value={formData.email}\n onChange={handleInputChange}\n placeholder={t('users.emailPlaceholder')}\n className=\"w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent form-input transition-all duration-200\"\n disabled={isSubmitting}\n />\n </div>\n\n <div className=\"border-t border-gray-100 dark:border-gray-700 pt-4 mt-2\">\n <p className=\"text-xs text-gray-500 uppercase font-semibold tracking-wider mb-3\">\n {t('users.changePassword')}\n </p>\n\n <div className=\"space-y-4\">\n <div>\n <label\n htmlFor=\"newPassword\"\n className=\"block text-sm font-medium text-gray-700 mb-1\"\n >\n {t('users.newPassword')}\n </label>\n <input\n type=\"password\"\n id=\"newPassword\"\n name=\"newPassword\"\n value={formData.newPassword}\n onChange={handleInputChange}\n placeholder={t('users.newPasswordPlaceholder')}\n className=\"w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent form-input transition-all duration-200\"\n disabled={isSubmitting}\n minLength={6}\n />\n </div>\n\n {formData.newPassword && (\n <div className=\"animate-fadeIn\">\n <label\n htmlFor=\"confirmPassword\"\n className=\"block text-sm font-medium text-gray-700 mb-1\"\n >\n {t('users.confirmPassword')}\n </label>\n <input\n type=\"password\"\n id=\"confirmPassword\"\n name=\"confirmPassword\"\n value={formData.confirmPassword}\n onChange={handleInputChange}\n placeholder={t('users.confirmPasswordPlaceholder')}\n className=\"w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent form-input transition-all duration-200\"\n disabled={isSubmitting}\n minLength={6}\n />\n </div>\n )}\n </div>\n </div>\n </div>\n\n <div className=\"flex justify-end space-x-2 mt-6\">\n <button\n type=\"button\"\n onClick={onCancel}\n className=\"hub-btn\"\n disabled={isSubmitting}\n >\n {t('common.cancel')}\n </button>\n <button\n type=\"submit\"\n className=\"hub-btn primary\"\n disabled={isSubmitting}\n >\n {isSubmitting && (\n <svg\n className=\"animate-spin -ml-1 mr-2 h-4 w-4 text-white\"\n xmlns=\"http://www.w3.org/2000/svg\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n >\n <circle\n className=\"opacity-25\"\n cx=\"12\"\n cy=\"12\"\n r=\"10\"\n stroke=\"currentColor\"\n strokeWidth=\"4\"\n ></circle>\n <path\n className=\"opacity-75\"\n fill=\"currentColor\"\n d=\"M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z\"\n ></path>\n </svg>\n )}\n {isSubmitting ? t('common.updating') : t('users.update')}\n </button>\n </div>\n </form>\n </div>\n </div>\n );\n};\n\nexport default EditUserForm;\n","import React, { useState } from 'react';\nimport { useTranslation } from 'react-i18next';\nimport { User } from '@/types';\nimport { useUserData } from '@/hooks/useUserData';\nimport { useAuth } from '@/contexts/AuthContext';\nimport AddUserForm from '@/components/AddUserForm';\nimport EditUserForm from '@/components/EditUserForm';\nimport { Edit3, Trash2, User as UserIcon, Plus, AlertCircle, X, RefreshCw } from 'lucide-react';\nimport DeleteDialog from '@/components/ui/DeleteDialog';\nimport { StatusDot } from '@/components/ui/StatusDot';\n\nconst UsersPage: React.FC = () => {\n const { t } = useTranslation();\n const { auth } = useAuth();\n const currentUser = auth.user;\n const {\n users,\n loading: usersLoading,\n error: userError,\n setError: setUserError,\n deleteUser,\n triggerRefresh,\n } = useUserData();\n\n const [editingUser, setEditingUser] = useState<User | null>(null);\n const [showAddForm, setShowAddForm] = useState(false);\n const [userToDelete, setUserToDelete] = useState<string | null>(null);\n\n if (!currentUser?.isAdmin) {\n return (\n <div className=\"hub-card p-6 text-center\" style={{ color: 'var(--hub-err)' }}>\n {t('users.adminRequired')}\n </div>\n );\n }\n\n return (\n <div>\n <div className=\"flex items-end justify-between gap-4 mb-6\">\n <div>\n <h1 className=\"hub-h1\">{t('pages.users.title')}</h1>\n <p className=\"hub-sub\">\n <span className=\"hub-num\">{users.length}</span> {t('nav.users').toLowerCase()}\n </p>\n </div>\n <div className=\"flex gap-2\">\n <button\n className=\"hub-btn\"\n onClick={() => triggerRefresh()}\n aria-label={t('common.refresh')}\n >\n <RefreshCw size={13} /> {t('common.refresh')}\n </button>\n <button className=\"hub-btn primary\" onClick={() => setShowAddForm(true)}>\n <Plus size={13} /> {t('users.add')}\n </button>\n </div>\n </div>\n\n {userError && (\n <div\n className=\"hub-card flex items-center justify-between gap-3 mb-4\"\n style={{\n padding: '10px 14px',\n borderColor: 'oklch(0.85 0.1 25)',\n background: 'oklch(0.97 0.03 25)',\n color: 'oklch(0.4 0.18 25)',\n }}\n >\n <div className=\"flex items-center gap-2 min-w-0\">\n <AlertCircle size={14} className=\"flex-shrink-0\" />\n <span className=\"truncate text-[13px]\">{userError}</span>\n </div>\n <button className=\"hub-icon-btn sm\" onClick={() => setUserError(null)}>\n <X size={13} />\n </button>\n </div>\n )}\n\n {usersLoading ? (\n <div className=\"hub-card p-10 text-center\" style={{ color: 'var(--hub-ink-3)' }}>\n {t('app.loading')}\n </div>\n ) : users.length === 0 ? (\n <div className=\"hub-card p-10 text-center\" style={{ color: 'var(--hub-ink-3)' }}>\n <div className=\"flex flex-col items-center gap-3\">\n <div\n className=\"grid place-items-center\"\n style={{\n width: 40,\n height: 40,\n borderRadius: 10,\n border: '1px solid var(--hub-line)',\n background: 'var(--hub-bg-2)',\n }}\n >\n <UserIcon size={18} />\n </div>\n <div className=\"font-medium\" style={{ color: 'var(--hub-ink-2)', fontSize: 13 }}>\n {t('users.noUsers')}\n </div>\n <button\n onClick={() => setShowAddForm(true)}\n className=\"hub-btn ghost sm\"\n style={{ color: 'var(--hub-accent)' }}\n >\n {t('users.addFirst')}\n </button>\n </div>\n </div>\n ) : (\n <div className=\"hub-card overflow-hidden\">\n <div\n className=\"hub-row head hub-mono\"\n style={{ gridTemplateColumns: '1.6fr 1.2fr 100px 100px' }}\n >\n <div>{t('users.username')}</div>\n <div>{t('users.email')}</div>\n <div>{t('users.role')}</div>\n <div className=\"text-right\">{t('users.actions')}</div>\n </div>\n {users.map((user) => {\n const isCurrentUser = currentUser?.username === user.username;\n return (\n <div\n key={user.username}\n className=\"hub-row hover\"\n style={{ gridTemplateColumns: '1.6fr 1.2fr 100px 100px' }}\n >\n <div className=\"flex items-center gap-3 min-w-0\">\n <div\n className=\"grid place-items-center flex-shrink-0 hub-mono\"\n style={{\n width: 28,\n height: 28,\n borderRadius: 7,\n background: 'var(--hub-bg-2)',\n border: '1px solid var(--hub-line)',\n color: 'var(--hub-ink-2)',\n fontWeight: 600,\n fontSize: 12,\n }}\n >\n {user.username.charAt(0).toUpperCase()}\n </div>\n <span\n className=\"hub-mono truncate\"\n style={{ fontSize: 13, color: 'var(--hub-ink)' }}\n >\n {user.username}\n </span>\n {isCurrentUser && (\n <span className=\"hub-tag accent\" style={{ fontSize: 10 }}>\n {t('users.currentUser')}\n </span>\n )}\n </div>\n <div className=\"flex items-center min-w-0\">\n <span\n className=\"truncate\"\n style={{ fontSize: 13, color: user.email ? 'var(--hub-ink)' : 'var(--hub-ink-3)' }}\n >\n {user.email || '—'}\n </span>\n </div>\n <div>\n <StatusDot\n kind={user.isAdmin ? 'ok' : 'muted'}\n label={user.isAdmin ? t('users.admin') : t('users.user')}\n />\n </div>\n <div className=\"flex justify-end gap-1\">\n <button\n onClick={() => setEditingUser(user)}\n className=\"hub-icon-btn sm\"\n title={t('users.edit')}\n >\n <Edit3 size={13} />\n </button>\n {!isCurrentUser && (\n <button\n onClick={() => setUserToDelete(user.username)}\n className=\"hub-icon-btn sm\"\n title={t('users.delete')}\n style={{ color: 'var(--hub-err)' }}\n >\n <Trash2 size={13} />\n </button>\n )}\n </div>\n </div>\n );\n })}\n </div>\n )}\n\n {showAddForm && (\n <AddUserForm\n onAdd={() => {\n setShowAddForm(false);\n triggerRefresh();\n }}\n onCancel={() => setShowAddForm(false)}\n />\n )}\n\n {editingUser && (\n <EditUserForm\n user={editingUser}\n onEdit={() => {\n setEditingUser(null);\n triggerRefresh();\n }}\n onCancel={() => setEditingUser(null)}\n />\n )}\n\n <DeleteDialog\n isOpen={!!userToDelete}\n onClose={() => setUserToDelete(null)}\n onConfirm={async () => {\n if (userToDelete) {\n const result = await deleteUser(userToDelete);\n if (!result?.success) {\n setUserError(result?.message || t('users.deleteError'));\n }\n setUserToDelete(null);\n }\n }}\n serverName={userToDelete || ''}\n isGroup={false}\n isUser={true}\n />\n </div>\n );\n};\n\nexport default UsersPage;\n"],"names":["useUserData","t","useTranslation","users","setUsers","useState","loading","setLoading","error","setError","refreshKey","setRefreshKey","fetchUsers","useCallback","data","apiGet","err","triggerRefresh","prev","createUser","userData","result","apiPost","updateUser","username","apiPut","deleteUser","apiDelete","useEffect","AddUserForm","onAdd","onCancel","isSubmitting","setIsSubmitting","formData","setFormData","handleSubmit","e","handleInputChange","name","value","type","checked","jsx","jsxs","EditUserForm","user","onEdit","updateData","UsersPage","auth","useAuth","currentUser","usersLoading","userError","setUserError","editingUser","setEditingUser","showAddForm","setShowAddForm","userToDelete","setUserToDelete","RefreshCw","Plus","AlertCircle","X","UserIcon","isCurrentUser","StatusDot","Edit3","Trash2","DeleteDialog"],"mappings":"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"}
1
+ {"version":3,"file":"UsersPage-MDtzW9-F.js","sources":["../../src/hooks/useUserData.ts","../../src/components/AddUserForm.tsx","../../src/components/EditUserForm.tsx","../../src/pages/UsersPage.tsx"],"sourcesContent":["import { useState, useEffect, useCallback } from 'react';\nimport { useTranslation } from 'react-i18next';\nimport { User, ApiResponse, UserFormData, UserUpdateData } from '@/types';\nimport { apiDelete, apiGet, apiPost, apiPut } from '../utils/fetchInterceptor';\n\nexport const useUserData = () => {\n const { t } = useTranslation();\n const [users, setUsers] = useState<User[]>([]);\n const [loading, setLoading] = useState(true);\n const [error, setError] = useState<string | null>(null);\n const [refreshKey, setRefreshKey] = useState(0);\n\n const fetchUsers = useCallback(async () => {\n try {\n setLoading(true);\n const data: ApiResponse<User[]> = await apiGet('/users');\n if (!data.success) {\n setError(data.message || t('users.fetchError'));\n return;\n }\n\n if (data && data.success && Array.isArray(data.data)) {\n setUsers(data.data);\n } else {\n console.error('Invalid user data format:', data);\n setUsers([]);\n }\n\n setError(null);\n } catch (err) {\n console.error('Error fetching users:', err);\n setError(err instanceof Error ? err.message : 'Failed to fetch users');\n setUsers([]);\n } finally {\n setLoading(false);\n }\n }, []);\n\n // Trigger a refresh of the users data\n const triggerRefresh = useCallback(() => {\n setRefreshKey((prev) => prev + 1);\n }, []);\n\n // Create a new user\n const createUser = async (userData: UserFormData) => {\n try {\n const result: ApiResponse<User> = await apiPost('/users', userData);\n triggerRefresh();\n return result;\n } catch (err) {\n setError(err instanceof Error ? err.message : 'Failed to create user');\n return null;\n }\n };\n\n // Update an existing user\n const updateUser = async (username: string, data: UserUpdateData) => {\n try {\n const result: ApiResponse<User> = await apiPut(`/users/${username}`, data);\n triggerRefresh();\n return result || null;\n } catch (err) {\n setError(err instanceof Error ? err.message : 'Failed to update user');\n return null;\n }\n };\n\n // Delete a user\n const deleteUser = async (username: string) => {\n try {\n const result = await apiDelete(`/users/${username}`);\n if (!result?.success) {\n setError(result?.message || t('users.deleteError'));\n return result;\n }\n\n triggerRefresh();\n return result;\n } catch (err) {\n setError(err instanceof Error ? err.message : 'Failed to delete user');\n return false;\n }\n };\n\n // Fetch users when the component mounts or refreshKey changes\n useEffect(() => {\n fetchUsers();\n }, [fetchUsers, refreshKey]);\n\n return {\n users,\n loading,\n error,\n setError,\n triggerRefresh,\n createUser,\n updateUser,\n deleteUser,\n };\n};\n","import { useState } from 'react';\nimport { useTranslation } from 'react-i18next';\nimport { useUserData } from '@/hooks/useUserData';\nimport { UserFormData } from '@/types';\n\ninterface AddUserFormProps {\n onAdd: () => void;\n onCancel: () => void;\n}\n\nconst AddUserForm = ({ onAdd, onCancel }: AddUserFormProps) => {\n const { t } = useTranslation();\n const { createUser } = useUserData();\n const [error, setError] = useState<string | null>(null);\n const [isSubmitting, setIsSubmitting] = useState(false);\n\n const [formData, setFormData] = useState<UserFormData>({\n username: '',\n password: '',\n isAdmin: false,\n email: '',\n });\n\n const handleSubmit = async (e: React.FormEvent) => {\n e.preventDefault();\n setError(null);\n\n if (!formData.username.trim()) {\n setError(t('users.usernameRequired'));\n return;\n }\n\n if (!formData.password.trim()) {\n setError(t('users.passwordRequired'));\n return;\n }\n\n if (formData.password.length < 6) {\n setError(t('users.passwordTooShort'));\n return;\n }\n\n setIsSubmitting(true);\n\n try {\n const result = await createUser(formData);\n if (result?.success) {\n onAdd();\n } else {\n setError(result?.message || t('users.createError'));\n }\n } catch (err) {\n setError(err instanceof Error ? err.message : t('users.createError'));\n } finally {\n setIsSubmitting(false);\n }\n };\n\n const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {\n const { name, value, type, checked } = e.target;\n setFormData((prev) => ({\n ...prev,\n [name]: type === 'checkbox' ? checked : value,\n }));\n };\n\n return (\n <div className=\"fixed inset-0 bg-black/50 z-50 flex items-center justify-center p-4\">\n <div className=\"bg-white dark:bg-gray-800 p-8 rounded-xl shadow-2xl max-w-md w-full mx-4 border border-gray-100 dark:border-gray-700\">\n <form onSubmit={handleSubmit}>\n <h2 className=\"text-xl font-bold text-gray-900 mb-6\">{t('users.addNew')}</h2>\n\n {error && (\n <div className=\"bg-red-50 border-l-4 border-red-500 text-red-700 p-4 mb-6 rounded-md\">\n <p className=\"text-sm font-medium\">{error}</p>\n </div>\n )}\n\n <div className=\"space-y-5\">\n <div>\n <label htmlFor=\"username\" className=\"block text-sm font-medium text-gray-700 mb-1\">\n {t('users.username')} <span className=\"text-red-500\">*</span>\n </label>\n <input\n type=\"text\"\n id=\"username\"\n name=\"username\"\n value={formData.username}\n onChange={handleInputChange}\n placeholder={t('users.usernamePlaceholder')}\n className=\"w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent form-input transition-all duration-200\"\n required\n disabled={isSubmitting}\n />\n </div>\n\n <div>\n <label htmlFor=\"email\" className=\"block text-sm font-medium text-gray-700 mb-1\">\n {t('users.email')}\n </label>\n <input\n type=\"email\"\n id=\"email\"\n name=\"email\"\n value={formData.email || ''}\n onChange={handleInputChange}\n placeholder={t('users.emailPlaceholder')}\n className=\"w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent form-input transition-all duration-200\"\n disabled={isSubmitting}\n />\n </div>\n\n <div>\n <label htmlFor=\"password\" className=\"block text-sm font-medium text-gray-700 mb-1\">\n {t('users.password')} <span className=\"text-red-500\">*</span>\n </label>\n <input\n type=\"password\"\n id=\"password\"\n name=\"password\"\n value={formData.password}\n onChange={handleInputChange}\n placeholder={t('users.passwordPlaceholder')}\n className=\"w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent form-input transition-all duration-200\"\n required\n disabled={isSubmitting}\n minLength={6}\n />\n </div>\n\n <div className=\"flex items-center pt-2\">\n <input\n type=\"checkbox\"\n id=\"isAdmin\"\n name=\"isAdmin\"\n checked={formData.isAdmin}\n onChange={handleInputChange}\n className=\"h-5 w-5 text-blue-600 focus:ring-blue-500 border-gray-300 rounded transition-colors duration-200\"\n disabled={isSubmitting}\n />\n <label\n htmlFor=\"isAdmin\"\n className=\"ml-3 block text-sm font-medium text-gray-700 cursor-pointer select-none\"\n >\n {t('users.adminRole')}\n </label>\n </div>\n </div>\n\n <div className=\"flex justify-end space-x-2 mt-6\">\n <button\n type=\"button\"\n onClick={onCancel}\n className=\"hub-btn\"\n disabled={isSubmitting}\n >\n {t('common.cancel')}\n </button>\n <button\n type=\"submit\"\n className=\"hub-btn primary\"\n disabled={isSubmitting}\n >\n {isSubmitting && (\n <svg\n className=\"animate-spin -ml-1 mr-2 h-4 w-4 text-white\"\n xmlns=\"http://www.w3.org/2000/svg\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n >\n <circle\n className=\"opacity-25\"\n cx=\"12\"\n cy=\"12\"\n r=\"10\"\n stroke=\"currentColor\"\n strokeWidth=\"4\"\n ></circle>\n <path\n className=\"opacity-75\"\n fill=\"currentColor\"\n d=\"M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z\"\n ></path>\n </svg>\n )}\n {isSubmitting ? t('common.creating') : t('users.create')}\n </button>\n </div>\n </form>\n </div>\n </div>\n );\n};\n\nexport default AddUserForm;\n","import { useState } from 'react';\nimport { useTranslation } from 'react-i18next';\nimport { useUserData } from '@/hooks/useUserData';\nimport { User, UserUpdateData } from '@/types';\n\ninterface EditUserFormProps {\n user: User;\n onEdit: () => void;\n onCancel: () => void;\n}\n\nconst EditUserForm = ({ user, onEdit, onCancel }: EditUserFormProps) => {\n const { t } = useTranslation();\n const { updateUser } = useUserData();\n const [error, setError] = useState<string | null>(null);\n const [isSubmitting, setIsSubmitting] = useState(false);\n\n const [formData, setFormData] = useState({\n isAdmin: user.isAdmin,\n email: user.email || '',\n newPassword: '',\n confirmPassword: '',\n });\n\n const handleSubmit = async (e: React.FormEvent) => {\n e.preventDefault();\n setError(null);\n\n // Validate passwords match if changing password\n if (formData.newPassword && formData.newPassword !== formData.confirmPassword) {\n setError(t('users.passwordMismatch'));\n return;\n }\n\n if (formData.newPassword && formData.newPassword.length < 6) {\n setError(t('users.passwordTooShort'));\n return;\n }\n\n setIsSubmitting(true);\n\n try {\n const updateData: UserUpdateData = {\n isAdmin: formData.isAdmin,\n email: formData.email,\n };\n\n if (formData.newPassword) {\n updateData.newPassword = formData.newPassword;\n }\n\n const result = await updateUser(user.username, updateData);\n if (result?.success) {\n onEdit();\n } else {\n setError(result?.message || t('users.updateError'));\n }\n } catch (err) {\n setError(err instanceof Error ? err.message : t('users.updateError'));\n } finally {\n setIsSubmitting(false);\n }\n };\n\n const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {\n const { name, value, type, checked } = e.target;\n setFormData((prev) => ({\n ...prev,\n [name]: type === 'checkbox' ? checked : value,\n }));\n };\n\n return (\n <div className=\"fixed inset-0 bg-black/50 z-50 flex items-center justify-center p-4\">\n <div className=\"bg-white dark:bg-gray-800 p-8 rounded-xl shadow-2xl max-w-md w-full mx-4 border border-gray-100 dark:border-gray-700\">\n <form onSubmit={handleSubmit}>\n <h2 className=\"text-xl font-bold text-gray-900 mb-6\">\n {t('users.edit')} - <span className=\"text-blue-600\">{user.username}</span>\n </h2>\n\n {error && (\n <div className=\"bg-red-50 border-l-4 border-red-500 text-red-700 p-4 mb-6 rounded-md\">\n <p className=\"text-sm font-medium\">{error}</p>\n </div>\n )}\n\n <div className=\"space-y-5\">\n <div className=\"flex items-center pt-2\">\n <input\n type=\"checkbox\"\n id=\"isAdmin\"\n name=\"isAdmin\"\n checked={formData.isAdmin}\n onChange={handleInputChange}\n className=\"h-5 w-5 text-blue-600 focus:ring-blue-500 border-gray-300 rounded transition-colors duration-200\"\n disabled={isSubmitting}\n />\n <label\n htmlFor=\"isAdmin\"\n className=\"ml-3 block text-sm font-medium text-gray-700 cursor-pointer select-none\"\n >\n {t('users.adminRole')}\n </label>\n </div>\n\n <div>\n <label htmlFor=\"email\" className=\"block text-sm font-medium text-gray-700 mb-1\">\n {t('users.email')}\n </label>\n <input\n type=\"email\"\n id=\"email\"\n name=\"email\"\n value={formData.email}\n onChange={handleInputChange}\n placeholder={t('users.emailPlaceholder')}\n className=\"w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent form-input transition-all duration-200\"\n disabled={isSubmitting}\n />\n </div>\n\n <div className=\"border-t border-gray-100 dark:border-gray-700 pt-4 mt-2\">\n <p className=\"text-xs text-gray-500 uppercase font-semibold tracking-wider mb-3\">\n {t('users.changePassword')}\n </p>\n\n <div className=\"space-y-4\">\n <div>\n <label\n htmlFor=\"newPassword\"\n className=\"block text-sm font-medium text-gray-700 mb-1\"\n >\n {t('users.newPassword')}\n </label>\n <input\n type=\"password\"\n id=\"newPassword\"\n name=\"newPassword\"\n value={formData.newPassword}\n onChange={handleInputChange}\n placeholder={t('users.newPasswordPlaceholder')}\n className=\"w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent form-input transition-all duration-200\"\n disabled={isSubmitting}\n minLength={6}\n />\n </div>\n\n {formData.newPassword && (\n <div className=\"animate-fadeIn\">\n <label\n htmlFor=\"confirmPassword\"\n className=\"block text-sm font-medium text-gray-700 mb-1\"\n >\n {t('users.confirmPassword')}\n </label>\n <input\n type=\"password\"\n id=\"confirmPassword\"\n name=\"confirmPassword\"\n value={formData.confirmPassword}\n onChange={handleInputChange}\n placeholder={t('users.confirmPasswordPlaceholder')}\n className=\"w-full px-4 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent form-input transition-all duration-200\"\n disabled={isSubmitting}\n minLength={6}\n />\n </div>\n )}\n </div>\n </div>\n </div>\n\n <div className=\"flex justify-end space-x-2 mt-6\">\n <button\n type=\"button\"\n onClick={onCancel}\n className=\"hub-btn\"\n disabled={isSubmitting}\n >\n {t('common.cancel')}\n </button>\n <button\n type=\"submit\"\n className=\"hub-btn primary\"\n disabled={isSubmitting}\n >\n {isSubmitting && (\n <svg\n className=\"animate-spin -ml-1 mr-2 h-4 w-4 text-white\"\n xmlns=\"http://www.w3.org/2000/svg\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n >\n <circle\n className=\"opacity-25\"\n cx=\"12\"\n cy=\"12\"\n r=\"10\"\n stroke=\"currentColor\"\n strokeWidth=\"4\"\n ></circle>\n <path\n className=\"opacity-75\"\n fill=\"currentColor\"\n d=\"M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z\"\n ></path>\n </svg>\n )}\n {isSubmitting ? t('common.updating') : t('users.update')}\n </button>\n </div>\n </form>\n </div>\n </div>\n );\n};\n\nexport default EditUserForm;\n","import React, { useState } from 'react';\nimport { useTranslation } from 'react-i18next';\nimport { User } from '@/types';\nimport { useUserData } from '@/hooks/useUserData';\nimport { useAuth } from '@/contexts/AuthContext';\nimport AddUserForm from '@/components/AddUserForm';\nimport EditUserForm from '@/components/EditUserForm';\nimport { Edit3, Trash2, User as UserIcon, Plus, AlertCircle, X, RefreshCw } from 'lucide-react';\nimport DeleteDialog from '@/components/ui/DeleteDialog';\nimport { StatusDot } from '@/components/ui/StatusDot';\n\nconst UsersPage: React.FC = () => {\n const { t } = useTranslation();\n const { auth } = useAuth();\n const currentUser = auth.user;\n const {\n users,\n loading: usersLoading,\n error: userError,\n setError: setUserError,\n deleteUser,\n triggerRefresh,\n } = useUserData();\n\n const [editingUser, setEditingUser] = useState<User | null>(null);\n const [showAddForm, setShowAddForm] = useState(false);\n const [userToDelete, setUserToDelete] = useState<string | null>(null);\n\n if (!currentUser?.isAdmin) {\n return (\n <div className=\"hub-card p-6 text-center\" style={{ color: 'var(--hub-err)' }}>\n {t('users.adminRequired')}\n </div>\n );\n }\n\n return (\n <div>\n <div className=\"flex items-end justify-between gap-4 mb-6\">\n <div>\n <h1 className=\"hub-h1\">{t('pages.users.title')}</h1>\n <p className=\"hub-sub\">\n <span className=\"hub-num\">{users.length}</span> {t('nav.users').toLowerCase()}\n </p>\n </div>\n <div className=\"flex gap-2\">\n <button\n className=\"hub-btn\"\n onClick={() => triggerRefresh()}\n aria-label={t('common.refresh')}\n >\n <RefreshCw size={13} /> {t('common.refresh')}\n </button>\n <button className=\"hub-btn primary\" onClick={() => setShowAddForm(true)}>\n <Plus size={13} /> {t('users.add')}\n </button>\n </div>\n </div>\n\n {userError && (\n <div\n className=\"hub-card flex items-center justify-between gap-3 mb-4\"\n style={{\n padding: '10px 14px',\n borderColor: 'oklch(0.85 0.1 25)',\n background: 'oklch(0.97 0.03 25)',\n color: 'oklch(0.4 0.18 25)',\n }}\n >\n <div className=\"flex items-center gap-2 min-w-0\">\n <AlertCircle size={14} className=\"flex-shrink-0\" />\n <span className=\"truncate text-[13px]\">{userError}</span>\n </div>\n <button className=\"hub-icon-btn sm\" onClick={() => setUserError(null)}>\n <X size={13} />\n </button>\n </div>\n )}\n\n {usersLoading ? (\n <div className=\"hub-card p-10 text-center\" style={{ color: 'var(--hub-ink-3)' }}>\n {t('app.loading')}\n </div>\n ) : users.length === 0 ? (\n <div className=\"hub-card p-10 text-center\" style={{ color: 'var(--hub-ink-3)' }}>\n <div className=\"flex flex-col items-center gap-3\">\n <div\n className=\"grid place-items-center\"\n style={{\n width: 40,\n height: 40,\n borderRadius: 10,\n border: '1px solid var(--hub-line)',\n background: 'var(--hub-bg-2)',\n }}\n >\n <UserIcon size={18} />\n </div>\n <div className=\"font-medium\" style={{ color: 'var(--hub-ink-2)', fontSize: 13 }}>\n {t('users.noUsers')}\n </div>\n <button\n onClick={() => setShowAddForm(true)}\n className=\"hub-btn ghost sm\"\n style={{ color: 'var(--hub-accent)' }}\n >\n {t('users.addFirst')}\n </button>\n </div>\n </div>\n ) : (\n <div className=\"hub-card overflow-hidden\">\n <div\n className=\"hub-row head hub-mono\"\n style={{ gridTemplateColumns: '1.6fr 1.2fr 100px 100px' }}\n >\n <div>{t('users.username')}</div>\n <div>{t('users.email')}</div>\n <div>{t('users.role')}</div>\n <div className=\"text-right\">{t('users.actions')}</div>\n </div>\n {users.map((user) => {\n const isCurrentUser = currentUser?.username === user.username;\n return (\n <div\n key={user.username}\n className=\"hub-row hover\"\n style={{ gridTemplateColumns: '1.6fr 1.2fr 100px 100px' }}\n >\n <div className=\"flex items-center gap-3 min-w-0\">\n <div\n className=\"grid place-items-center flex-shrink-0 hub-mono\"\n style={{\n width: 28,\n height: 28,\n borderRadius: 7,\n background: 'var(--hub-bg-2)',\n border: '1px solid var(--hub-line)',\n color: 'var(--hub-ink-2)',\n fontWeight: 600,\n fontSize: 12,\n }}\n >\n {user.username.charAt(0).toUpperCase()}\n </div>\n <span\n className=\"hub-mono truncate\"\n style={{ fontSize: 13, color: 'var(--hub-ink)' }}\n >\n {user.username}\n </span>\n {isCurrentUser && (\n <span className=\"hub-tag accent\" style={{ fontSize: 10 }}>\n {t('users.currentUser')}\n </span>\n )}\n </div>\n <div className=\"flex items-center min-w-0\">\n <span\n className=\"truncate\"\n style={{ fontSize: 13, color: user.email ? 'var(--hub-ink)' : 'var(--hub-ink-3)' }}\n >\n {user.email || '—'}\n </span>\n </div>\n <div>\n <StatusDot\n kind={user.isAdmin ? 'ok' : 'muted'}\n label={user.isAdmin ? t('users.admin') : t('users.user')}\n />\n </div>\n <div className=\"flex justify-end gap-1\">\n <button\n onClick={() => setEditingUser(user)}\n className=\"hub-icon-btn sm\"\n title={t('users.edit')}\n >\n <Edit3 size={13} />\n </button>\n {!isCurrentUser && (\n <button\n onClick={() => setUserToDelete(user.username)}\n className=\"hub-icon-btn sm\"\n title={t('users.delete')}\n style={{ color: 'var(--hub-err)' }}\n >\n <Trash2 size={13} />\n </button>\n )}\n </div>\n </div>\n );\n })}\n </div>\n )}\n\n {showAddForm && (\n <AddUserForm\n onAdd={() => {\n setShowAddForm(false);\n triggerRefresh();\n }}\n onCancel={() => setShowAddForm(false)}\n />\n )}\n\n {editingUser && (\n <EditUserForm\n user={editingUser}\n onEdit={() => {\n setEditingUser(null);\n triggerRefresh();\n }}\n onCancel={() => setEditingUser(null)}\n />\n )}\n\n <DeleteDialog\n isOpen={!!userToDelete}\n onClose={() => setUserToDelete(null)}\n onConfirm={async () => {\n if (userToDelete) {\n const result = await deleteUser(userToDelete);\n if (!result?.success) {\n setUserError(result?.message || t('users.deleteError'));\n }\n setUserToDelete(null);\n }\n }}\n serverName={userToDelete || ''}\n isGroup={false}\n isUser={true}\n />\n </div>\n );\n};\n\nexport default UsersPage;\n"],"names":["useUserData","t","useTranslation","users","setUsers","useState","loading","setLoading","error","setError","refreshKey","setRefreshKey","fetchUsers","useCallback","data","apiGet","err","triggerRefresh","prev","createUser","userData","result","apiPost","updateUser","username","apiPut","deleteUser","apiDelete","useEffect","AddUserForm","onAdd","onCancel","isSubmitting","setIsSubmitting","formData","setFormData","handleSubmit","e","handleInputChange","name","value","type","checked","jsx","jsxs","EditUserForm","user","onEdit","updateData","UsersPage","auth","useAuth","currentUser","usersLoading","userError","setUserError","editingUser","setEditingUser","showAddForm","setShowAddForm","userToDelete","setUserToDelete","RefreshCw","Plus","AlertCircle","X","UserIcon","isCurrentUser","StatusDot","Edit3","Trash2","DeleteDialog"],"mappings":"gWAKO,MAAMA,EAAc,IAAM,CAC/B,KAAM,CAAE,EAAAC,CAAA,EAAMC,EAAA,EACR,CAACC,EAAOC,CAAQ,EAAIC,EAAAA,SAAiB,CAAA,CAAE,EACvC,CAACC,EAASC,CAAU,EAAIF,EAAAA,SAAS,EAAI,EACrC,CAACG,EAAOC,CAAQ,EAAIJ,EAAAA,SAAwB,IAAI,EAChD,CAACK,EAAYC,CAAa,EAAIN,EAAAA,SAAS,CAAC,EAExCO,EAAaC,EAAAA,YAAY,SAAY,CACzC,GAAI,CACFN,EAAW,EAAI,EACf,MAAMO,EAA4B,MAAMC,EAAO,QAAQ,EACvD,GAAI,CAACD,EAAK,QAAS,CACjBL,EAASK,EAAK,SAAWb,EAAE,kBAAkB,CAAC,EAC9C,MACF,CAEIa,GAAQA,EAAK,SAAW,MAAM,QAAQA,EAAK,IAAI,EACjDV,EAASU,EAAK,IAAI,GAElB,QAAQ,MAAM,4BAA6BA,CAAI,EAC/CV,EAAS,CAAA,CAAE,GAGbK,EAAS,IAAI,CACf,OAASO,EAAK,CACZ,QAAQ,MAAM,wBAAyBA,CAAG,EAC1CP,EAASO,aAAe,MAAQA,EAAI,QAAU,uBAAuB,EACrEZ,EAAS,CAAA,CAAE,CACb,QAAA,CACEG,EAAW,EAAK,CAClB,CACF,EAAG,CAAA,CAAE,EAGCU,EAAiBJ,EAAAA,YAAY,IAAM,CACvCF,EAAeO,GAASA,EAAO,CAAC,CAClC,EAAG,CAAA,CAAE,EAGCC,EAAa,MAAOC,GAA2B,CACnD,GAAI,CACF,MAAMC,EAA4B,MAAMC,EAAQ,SAAUF,CAAQ,EAClE,OAAAH,EAAA,EACOI,CACT,OAASL,EAAK,CACZ,OAAAP,EAASO,aAAe,MAAQA,EAAI,QAAU,uBAAuB,EAC9D,IACT,CACF,EAGMO,EAAa,MAAOC,EAAkBV,IAAyB,CACnE,GAAI,CACF,MAAMO,EAA4B,MAAMI,EAAO,UAAUD,CAAQ,GAAIV,CAAI,EACzE,OAAAG,EAAA,EACOI,GAAU,IACnB,OAASL,EAAK,CACZ,OAAAP,EAASO,aAAe,MAAQA,EAAI,QAAU,uBAAuB,EAC9D,IACT,CACF,EAGMU,EAAa,MAAOF,GAAqB,CAC7C,GAAI,CACF,MAAMH,EAAS,MAAMM,EAAU,UAAUH,CAAQ,EAAE,EACnD,OAAKH,GAAA,MAAAA,EAAQ,SAKbJ,EAAA,EACOI,IALLZ,GAASY,GAAA,YAAAA,EAAQ,UAAWpB,EAAE,mBAAmB,CAAC,EAC3CoB,EAKX,OAASL,EAAK,CACZ,OAAAP,EAASO,aAAe,MAAQA,EAAI,QAAU,uBAAuB,EAC9D,EACT,CACF,EAGAY,OAAAA,EAAAA,UAAU,IAAM,CACdhB,EAAA,CACF,EAAG,CAACA,EAAYF,CAAU,CAAC,EAEpB,CACL,MAAAP,EACA,QAAAG,EACA,MAAAE,EACA,SAAAC,EACA,eAAAQ,EACA,WAAAE,EACA,WAAAI,EACA,WAAAG,CAAA,CAEJ,ECzFMG,EAAc,CAAC,CAAE,MAAAC,EAAO,SAAAC,KAAiC,CAC7D,KAAM,CAAE,CAAA,EAAM7B,EAAA,EACR,CAAE,WAAAiB,CAAA,EAAenB,EAAA,EACjB,CAACQ,EAAOC,CAAQ,EAAIJ,EAAAA,SAAwB,IAAI,EAChD,CAAC2B,EAAcC,CAAe,EAAI5B,EAAAA,SAAS,EAAK,EAEhD,CAAC6B,EAAUC,CAAW,EAAI9B,WAAuB,CACrD,SAAU,GACV,SAAU,GACV,QAAS,GACT,MAAO,EAAA,CACR,EAEK+B,EAAe,MAAOC,GAAuB,CAIjD,GAHAA,EAAE,eAAA,EACF5B,EAAS,IAAI,EAET,CAACyB,EAAS,SAAS,OAAQ,CAC7BzB,EAAS,EAAE,wBAAwB,CAAC,EACpC,MACF,CAEA,GAAI,CAACyB,EAAS,SAAS,OAAQ,CAC7BzB,EAAS,EAAE,wBAAwB,CAAC,EACpC,MACF,CAEA,GAAIyB,EAAS,SAAS,OAAS,EAAG,CAChCzB,EAAS,EAAE,wBAAwB,CAAC,EACpC,MACF,CAEAwB,EAAgB,EAAI,EAEpB,GAAI,CACF,MAAMZ,EAAS,MAAMF,EAAWe,CAAQ,EACpCb,GAAA,MAAAA,EAAQ,QACVS,EAAA,EAEArB,GAASY,GAAA,YAAAA,EAAQ,UAAW,EAAE,mBAAmB,CAAC,CAEtD,OAASL,EAAK,CACZP,EAASO,aAAe,MAAQA,EAAI,QAAU,EAAE,mBAAmB,CAAC,CACtE,QAAA,CACEiB,EAAgB,EAAK,CACvB,CACF,EAEMK,EAAqBD,GAA2C,CACpE,KAAM,CAAE,KAAAE,EAAM,MAAAC,EAAO,KAAAC,EAAM,QAAAC,CAAA,EAAYL,EAAE,OACzCF,EAAajB,IAAU,CACrB,GAAGA,EACH,CAACqB,CAAI,EAAGE,IAAS,WAAaC,EAAUF,CAAA,EACxC,CACJ,EAEA,OACEG,EAAAA,IAAC,MAAA,CAAI,UAAU,sEACb,SAAAA,EAAAA,IAAC,MAAA,CAAI,UAAU,uHACb,SAAAC,EAAAA,KAAC,OAAA,CAAK,SAAUR,EACd,SAAA,CAAAO,MAAC,KAAA,CAAG,UAAU,uCAAwC,SAAA,EAAE,cAAc,EAAE,EAEvEnC,GACCmC,EAAAA,IAAC,MAAA,CAAI,UAAU,uEACb,eAAC,IAAA,CAAE,UAAU,sBAAuB,SAAAnC,CAAA,CAAM,CAAA,CAC5C,EAGFoC,EAAAA,KAAC,MAAA,CAAI,UAAU,YACb,SAAA,CAAAA,OAAC,MAAA,CACC,SAAA,CAAAA,EAAAA,KAAC,QAAA,CAAM,QAAQ,WAAW,UAAU,+CACjC,SAAA,CAAA,EAAE,gBAAgB,EAAE,IAACD,EAAAA,IAAC,OAAA,CAAK,UAAU,eAAe,SAAA,GAAA,CAAC,CAAA,EACxD,EACAA,EAAAA,IAAC,QAAA,CACC,KAAK,OACL,GAAG,WACH,KAAK,WACL,MAAOT,EAAS,SAChB,SAAUI,EACV,YAAa,EAAE,2BAA2B,EAC1C,UAAU,yKACV,SAAQ,GACR,SAAUN,CAAA,CAAA,CACZ,EACF,SAEC,MAAA,CACC,SAAA,CAAAW,EAAAA,IAAC,SAAM,QAAQ,QAAQ,UAAU,+CAC9B,SAAA,EAAE,aAAa,EAClB,EACAA,EAAAA,IAAC,QAAA,CACC,KAAK,QACL,GAAG,QACH,KAAK,QACL,MAAOT,EAAS,OAAS,GACzB,SAAUI,EACV,YAAa,EAAE,wBAAwB,EACvC,UAAU,yKACV,SAAUN,CAAA,CAAA,CACZ,EACF,SAEC,MAAA,CACC,SAAA,CAAAY,EAAAA,KAAC,QAAA,CAAM,QAAQ,WAAW,UAAU,+CACjC,SAAA,CAAA,EAAE,gBAAgB,EAAE,IAACD,EAAAA,IAAC,OAAA,CAAK,UAAU,eAAe,SAAA,GAAA,CAAC,CAAA,EACxD,EACAA,EAAAA,IAAC,QAAA,CACC,KAAK,WACL,GAAG,WACH,KAAK,WACL,MAAOT,EAAS,SAChB,SAAUI,EACV,YAAa,EAAE,2BAA2B,EAC1C,UAAU,yKACV,SAAQ,GACR,SAAUN,EACV,UAAW,CAAA,CAAA,CACb,EACF,EAEAY,EAAAA,KAAC,MAAA,CAAI,UAAU,yBACb,SAAA,CAAAD,EAAAA,IAAC,QAAA,CACC,KAAK,WACL,GAAG,UACH,KAAK,UACL,QAAST,EAAS,QAClB,SAAUI,EACV,UAAU,mGACV,SAAUN,CAAA,CAAA,EAEZW,EAAAA,IAAC,QAAA,CACC,QAAQ,UACR,UAAU,0EAET,WAAE,iBAAiB,CAAA,CAAA,CACtB,CAAA,CACF,CAAA,EACF,EAEAC,EAAAA,KAAC,MAAA,CAAI,UAAU,kCACb,SAAA,CAAAD,EAAAA,IAAC,SAAA,CACC,KAAK,SACL,QAASZ,EACT,UAAU,UACV,SAAUC,EAET,WAAE,eAAe,CAAA,CAAA,EAEpBY,EAAAA,KAAC,SAAA,CACC,KAAK,SACL,UAAU,kBACV,SAAUZ,EAET,SAAA,CAAAA,GACCY,EAAAA,KAAC,MAAA,CACC,UAAU,6CACV,MAAM,6BACN,KAAK,OACL,QAAQ,YAER,SAAA,CAAAD,EAAAA,IAAC,SAAA,CACC,UAAU,aACV,GAAG,KACH,GAAG,KACH,EAAE,KACF,OAAO,eACP,YAAY,GAAA,CAAA,EAEdA,EAAAA,IAAC,OAAA,CACC,UAAU,aACV,KAAK,eACL,EAAE,iHAAA,CAAA,CACH,CAAA,CAAA,EAGW,EAAfX,EAAiB,kBAAuB,cAAN,CAAoB,CAAA,CAAA,CACzD,CAAA,CACF,CAAA,CAAA,CACF,EACF,EACF,CAEJ,ECrLMa,EAAe,CAAC,CAAE,KAAAC,EAAM,OAAAC,EAAQ,SAAAhB,KAAkC,CACtE,KAAM,CAAE,EAAA9B,CAAA,EAAMC,EAAA,EACR,CAAE,WAAAqB,CAAA,EAAevB,EAAA,EACjB,CAACQ,EAAOC,CAAQ,EAAIJ,EAAAA,SAAwB,IAAI,EAChD,CAAC2B,EAAcC,CAAe,EAAI5B,EAAAA,SAAS,EAAK,EAEhD,CAAC6B,EAAUC,CAAW,EAAI9B,WAAS,CACvC,QAASyC,EAAK,QACd,MAAOA,EAAK,OAAS,GACrB,YAAa,GACb,gBAAiB,EAAA,CAClB,EAEKV,EAAe,MAAOC,GAAuB,CAKjD,GAJAA,EAAE,eAAA,EACF5B,EAAS,IAAI,EAGTyB,EAAS,aAAeA,EAAS,cAAgBA,EAAS,gBAAiB,CAC7EzB,EAASR,EAAE,wBAAwB,CAAC,EACpC,MACF,CAEA,GAAIiC,EAAS,aAAeA,EAAS,YAAY,OAAS,EAAG,CAC3DzB,EAASR,EAAE,wBAAwB,CAAC,EACpC,MACF,CAEAgC,EAAgB,EAAI,EAEpB,GAAI,CACF,MAAMe,EAA6B,CACjC,QAASd,EAAS,QAClB,MAAOA,EAAS,KAAA,EAGdA,EAAS,cACXc,EAAW,YAAcd,EAAS,aAGpC,MAAMb,EAAS,MAAME,EAAWuB,EAAK,SAAUE,CAAU,EACrD3B,GAAA,MAAAA,EAAQ,QACV0B,EAAA,EAEAtC,GAASY,GAAA,YAAAA,EAAQ,UAAWpB,EAAE,mBAAmB,CAAC,CAEtD,OAASe,EAAK,CACZP,EAASO,aAAe,MAAQA,EAAI,QAAUf,EAAE,mBAAmB,CAAC,CACtE,QAAA,CACEgC,EAAgB,EAAK,CACvB,CACF,EAEMK,EAAqBD,GAA2C,CACpE,KAAM,CAAE,KAAAE,EAAM,MAAAC,EAAO,KAAAC,EAAM,QAAAC,CAAA,EAAYL,EAAE,OACzCF,EAAajB,IAAU,CACrB,GAAGA,EACH,CAACqB,CAAI,EAAGE,IAAS,WAAaC,EAAUF,CAAA,EACxC,CACJ,EAEA,OACEG,EAAAA,IAAC,MAAA,CAAI,UAAU,sEACb,SAAAA,EAAAA,IAAC,MAAA,CAAI,UAAU,uHACb,SAAAC,EAAAA,KAAC,OAAA,CAAK,SAAUR,EACd,SAAA,CAAAQ,EAAAA,KAAC,KAAA,CAAG,UAAU,uCACX,SAAA,CAAA3C,EAAE,YAAY,EAAE,MAAG0C,EAAAA,IAAC,OAAA,CAAK,UAAU,gBAAiB,WAAK,QAAA,CAAS,CAAA,EACrE,EAECnC,GACCmC,EAAAA,IAAC,MAAA,CAAI,UAAU,uEACb,eAAC,IAAA,CAAE,UAAU,sBAAuB,SAAAnC,CAAA,CAAM,CAAA,CAC5C,EAGFoC,EAAAA,KAAC,MAAA,CAAI,UAAU,YACb,SAAA,CAAAA,EAAAA,KAAC,MAAA,CAAI,UAAU,yBACb,SAAA,CAAAD,EAAAA,IAAC,QAAA,CACC,KAAK,WACL,GAAG,UACH,KAAK,UACL,QAAST,EAAS,QAClB,SAAUI,EACV,UAAU,mGACV,SAAUN,CAAA,CAAA,EAEZW,EAAAA,IAAC,QAAA,CACC,QAAQ,UACR,UAAU,0EAET,WAAE,iBAAiB,CAAA,CAAA,CACtB,EACF,SAEC,MAAA,CACC,SAAA,CAAAA,EAAAA,IAAC,SAAM,QAAQ,QAAQ,UAAU,+CAC9B,SAAA1C,EAAE,aAAa,EAClB,EACA0C,EAAAA,IAAC,QAAA,CACC,KAAK,QACL,GAAG,QACH,KAAK,QACL,MAAOT,EAAS,MAChB,SAAUI,EACV,YAAarC,EAAE,wBAAwB,EACvC,UAAU,yKACV,SAAU+B,CAAA,CAAA,CACZ,EACF,EAEAY,EAAAA,KAAC,MAAA,CAAI,UAAU,0DACb,SAAA,CAAAD,MAAC,IAAA,CAAE,UAAU,oEACV,SAAA1C,EAAE,sBAAsB,EAC3B,EAEA2C,EAAAA,KAAC,MAAA,CAAI,UAAU,YACb,SAAA,CAAAA,OAAC,MAAA,CACC,SAAA,CAAAD,EAAAA,IAAC,QAAA,CACC,QAAQ,cACR,UAAU,+CAET,WAAE,mBAAmB,CAAA,CAAA,EAExBA,EAAAA,IAAC,QAAA,CACC,KAAK,WACL,GAAG,cACH,KAAK,cACL,MAAOT,EAAS,YAChB,SAAUI,EACV,YAAarC,EAAE,8BAA8B,EAC7C,UAAU,yKACV,SAAU+B,EACV,UAAW,CAAA,CAAA,CACb,EACF,EAECE,EAAS,aACRU,OAAC,MAAA,CAAI,UAAU,iBACb,SAAA,CAAAD,EAAAA,IAAC,QAAA,CACC,QAAQ,kBACR,UAAU,+CAET,WAAE,uBAAuB,CAAA,CAAA,EAE5BA,EAAAA,IAAC,QAAA,CACC,KAAK,WACL,GAAG,kBACH,KAAK,kBACL,MAAOT,EAAS,gBAChB,SAAUI,EACV,YAAarC,EAAE,kCAAkC,EACjD,UAAU,yKACV,SAAU+B,EACV,UAAW,CAAA,CAAA,CACb,CAAA,CACF,CAAA,CAAA,CAEJ,CAAA,CAAA,CACF,CAAA,EACF,EAEAY,EAAAA,KAAC,MAAA,CAAI,UAAU,kCACb,SAAA,CAAAD,EAAAA,IAAC,SAAA,CACC,KAAK,SACL,QAASZ,EACT,UAAU,UACV,SAAUC,EAET,WAAE,eAAe,CAAA,CAAA,EAEpBY,EAAAA,KAAC,SAAA,CACC,KAAK,SACL,UAAU,kBACV,SAAUZ,EAET,SAAA,CAAAA,GACCY,EAAAA,KAAC,MAAA,CACC,UAAU,6CACV,MAAM,6BACN,KAAK,OACL,QAAQ,YAER,SAAA,CAAAD,EAAAA,IAAC,SAAA,CACC,UAAU,aACV,GAAG,KACH,GAAG,KACH,EAAE,KACF,OAAO,eACP,YAAY,GAAA,CAAA,EAEdA,EAAAA,IAAC,OAAA,CACC,UAAU,aACV,KAAK,eACL,EAAE,iHAAA,CAAA,CACH,CAAA,CAAA,EAGW1C,EAAf+B,EAAiB,kBAAuB,cAAN,CAAoB,CAAA,CAAA,CACzD,CAAA,CACF,CAAA,CAAA,CACF,EACF,EACF,CAEJ,EC5MMiB,EAAsB,IAAM,CAChC,KAAM,CAAE,EAAAhD,CAAA,EAAMC,EAAA,EACR,CAAE,KAAAgD,CAAA,EAASC,EAAA,EACXC,EAAcF,EAAK,KACnB,CACJ,MAAA/C,EACA,QAASkD,EACT,MAAOC,EACP,SAAUC,EACV,WAAA7B,EACA,eAAAT,CAAA,EACEjB,EAAA,EAEE,CAACwD,EAAaC,CAAc,EAAIpD,EAAAA,SAAsB,IAAI,EAC1D,CAACqD,EAAaC,CAAc,EAAItD,EAAAA,SAAS,EAAK,EAC9C,CAACuD,EAAcC,CAAe,EAAIxD,EAAAA,SAAwB,IAAI,EAEpE,OAAK+C,GAAA,MAAAA,EAAa,eASf,MAAA,CACC,SAAA,CAAAR,EAAAA,KAAC,MAAA,CAAI,UAAU,4CACb,SAAA,CAAAA,OAAC,MAAA,CACC,SAAA,CAAAD,MAAC,KAAA,CAAG,UAAU,SAAU,SAAA1C,EAAE,mBAAmB,EAAE,EAC/C2C,EAAAA,KAAC,IAAA,CAAE,UAAU,UACX,SAAA,CAAAD,EAAAA,IAAC,OAAA,CAAK,UAAU,UAAW,SAAAxC,EAAM,OAAO,EAAO,IAAEF,EAAE,WAAW,EAAE,YAAA,CAAY,CAAA,CAC9E,CAAA,EACF,EACA2C,EAAAA,KAAC,MAAA,CAAI,UAAU,aACb,SAAA,CAAAA,EAAAA,KAAC,SAAA,CACC,UAAU,UACV,QAAS,IAAM3B,EAAA,EACf,aAAYhB,EAAE,gBAAgB,EAE9B,SAAA,CAAA0C,EAAAA,IAACmB,EAAA,CAAU,KAAM,EAAA,CAAI,EAAE,IAAE7D,EAAE,gBAAgB,CAAA,CAAA,CAAA,EAE7C2C,OAAC,UAAO,UAAU,kBAAkB,QAAS,IAAMe,EAAe,EAAI,EACpE,SAAA,CAAAhB,EAAAA,IAACoB,EAAA,CAAK,KAAM,EAAA,CAAI,EAAE,IAAE9D,EAAE,WAAW,CAAA,CAAA,CACnC,CAAA,CAAA,CACF,CAAA,EACF,EAECqD,GACCV,EAAAA,KAAC,MAAA,CACC,UAAU,wDACV,MAAO,CACL,QAAS,YACT,YAAa,qBACb,WAAY,sBACZ,MAAO,oBAAA,EAGT,SAAA,CAAAA,EAAAA,KAAC,MAAA,CAAI,UAAU,kCACb,SAAA,CAAAD,EAAAA,IAACqB,EAAA,CAAY,KAAM,GAAI,UAAU,gBAAgB,EACjDrB,EAAAA,IAAC,OAAA,CAAK,UAAU,uBAAwB,SAAAW,CAAA,CAAU,CAAA,EACpD,EACAX,EAAAA,IAAC,SAAA,CAAO,UAAU,kBAAkB,QAAS,IAAMY,EAAa,IAAI,EAClE,SAAAZ,EAAAA,IAACsB,EAAA,CAAE,KAAM,GAAI,CAAA,CACf,CAAA,CAAA,CAAA,EAIHZ,EACCV,EAAAA,IAAC,MAAA,CAAI,UAAU,4BAA4B,MAAO,CAAE,MAAO,kBAAA,EACxD,SAAA1C,EAAE,aAAa,CAAA,CAClB,EACEE,EAAM,SAAW,EACnBwC,EAAAA,IAAC,MAAA,CAAI,UAAU,4BAA4B,MAAO,CAAE,MAAO,kBAAA,EACzD,SAAAC,EAAAA,KAAC,MAAA,CAAI,UAAU,mCACb,SAAA,CAAAD,EAAAA,IAAC,MAAA,CACC,UAAU,0BACV,MAAO,CACL,MAAO,GACP,OAAQ,GACR,aAAc,GACd,OAAQ,4BACR,WAAY,iBAAA,EAGd,SAAAA,EAAAA,IAACuB,EAAA,CAAS,KAAM,EAAA,CAAI,CAAA,CAAA,EAEtBvB,EAAAA,IAAC,MAAA,CAAI,UAAU,cAAc,MAAO,CAAE,MAAO,mBAAoB,SAAU,EAAA,EACxE,SAAA1C,EAAE,eAAe,CAAA,CACpB,EACA0C,EAAAA,IAAC,SAAA,CACC,QAAS,IAAMgB,EAAe,EAAI,EAClC,UAAU,mBACV,MAAO,CAAE,MAAO,mBAAA,EAEf,WAAE,gBAAgB,CAAA,CAAA,CACrB,CAAA,CACF,CAAA,CACF,EAEAf,EAAAA,KAAC,MAAA,CAAI,UAAU,2BACb,SAAA,CAAAA,EAAAA,KAAC,MAAA,CACC,UAAU,wBACV,MAAO,CAAE,oBAAqB,yBAAA,EAE9B,SAAA,CAAAD,EAAAA,IAAC,MAAA,CAAK,SAAA1C,EAAE,gBAAgB,CAAA,CAAE,EAC1B0C,EAAAA,IAAC,MAAA,CAAK,SAAA1C,EAAE,aAAa,CAAA,CAAE,EACvB0C,EAAAA,IAAC,MAAA,CAAK,SAAA1C,EAAE,YAAY,CAAA,CAAE,QACrB,MAAA,CAAI,UAAU,aAAc,SAAAA,EAAE,eAAe,CAAA,CAAE,CAAA,CAAA,CAAA,EAEjDE,EAAM,IAAK2C,GAAS,CACnB,MAAMqB,GAAgBf,GAAA,YAAAA,EAAa,YAAaN,EAAK,SACrD,OACEF,EAAAA,KAAC,MAAA,CAEC,UAAU,gBACV,MAAO,CAAE,oBAAqB,yBAAA,EAE9B,SAAA,CAAAA,EAAAA,KAAC,MAAA,CAAI,UAAU,kCACb,SAAA,CAAAD,EAAAA,IAAC,MAAA,CACC,UAAU,iDACV,MAAO,CACL,MAAO,GACP,OAAQ,GACR,aAAc,EACd,WAAY,kBACZ,OAAQ,4BACR,MAAO,mBACP,WAAY,IACZ,SAAU,EAAA,EAGX,SAAAG,EAAK,SAAS,OAAO,CAAC,EAAE,YAAA,CAAY,CAAA,EAEvCH,EAAAA,IAAC,OAAA,CACC,UAAU,oBACV,MAAO,CAAE,SAAU,GAAI,MAAO,gBAAA,EAE7B,SAAAG,EAAK,QAAA,CAAA,EAEPqB,GACCxB,EAAAA,IAAC,OAAA,CAAK,UAAU,iBAAiB,MAAO,CAAE,SAAU,EAAA,EACjD,SAAA1C,EAAE,mBAAmB,CAAA,CACxB,CAAA,EAEJ,EACA0C,EAAAA,IAAC,MAAA,CAAI,UAAU,4BACb,SAAAA,EAAAA,IAAC,OAAA,CACC,UAAU,WACV,MAAO,CAAE,SAAU,GAAI,MAAOG,EAAK,MAAQ,iBAAmB,kBAAA,EAE7D,WAAK,OAAS,GAAA,CAAA,EAEnB,QACC,MAAA,CACC,SAAAH,EAAAA,IAACyB,EAAA,CACC,KAAMtB,EAAK,QAAU,KAAO,QAC5B,MAAOA,EAAK,QAAU7C,EAAE,aAAa,EAAIA,EAAE,YAAY,CAAA,CAAA,EAE3D,EACA2C,EAAAA,KAAC,MAAA,CAAI,UAAU,yBACb,SAAA,CAAAD,EAAAA,IAAC,SAAA,CACC,QAAS,IAAMc,EAAeX,CAAI,EAClC,UAAU,kBACV,MAAO7C,EAAE,YAAY,EAErB,SAAA0C,EAAAA,IAAC0B,EAAA,CAAM,KAAM,EAAA,CAAI,CAAA,CAAA,EAElB,CAACF,GACAxB,EAAAA,IAAC,SAAA,CACC,QAAS,IAAMkB,EAAgBf,EAAK,QAAQ,EAC5C,UAAU,kBACV,MAAO7C,EAAE,cAAc,EACvB,MAAO,CAAE,MAAO,gBAAA,EAEhB,SAAA0C,EAAAA,IAAC2B,EAAA,CAAO,KAAM,EAAA,CAAI,CAAA,CAAA,CACpB,CAAA,CAEJ,CAAA,CAAA,EAhEKxB,EAAK,QAAA,CAmEhB,CAAC,CAAA,EACH,EAGDY,GACCf,EAAAA,IAACd,EAAA,CACC,MAAO,IAAM,CACX8B,EAAe,EAAK,EACpB1C,EAAA,CACF,EACA,SAAU,IAAM0C,EAAe,EAAK,CAAA,CAAA,EAIvCH,GACCb,EAAAA,IAACE,EAAA,CACC,KAAMW,EACN,OAAQ,IAAM,CACZC,EAAe,IAAI,EACnBxC,EAAA,CACF,EACA,SAAU,IAAMwC,EAAe,IAAI,CAAA,CAAA,EAIvCd,EAAAA,IAAC4B,EAAA,CACC,OAAQ,CAAC,CAACX,EACV,QAAS,IAAMC,EAAgB,IAAI,EACnC,UAAW,SAAY,CACrB,GAAID,EAAc,CAChB,MAAMvC,EAAS,MAAMK,EAAWkC,CAAY,EACvCvC,GAAA,MAAAA,EAAQ,SACXkC,GAAalC,GAAA,YAAAA,EAAQ,UAAWpB,EAAE,mBAAmB,CAAC,EAExD4D,EAAgB,IAAI,CACtB,CACF,EACA,WAAYD,GAAgB,GAC5B,QAAS,GACT,OAAQ,EAAA,CAAA,CACV,EACF,EA3MEjB,EAAAA,IAAC,MAAA,CAAI,UAAU,2BAA2B,MAAO,CAAE,MAAO,gBAAA,EACvD,SAAA1C,EAAE,qBAAqB,CAAA,CAC1B,CA2MN"}
@@ -0,0 +1 @@
1
+ /*! tailwindcss v4.1.17 | MIT License | https://tailwindcss.com */@layer properties{@supports ((-webkit-hyphens:none) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-translate-x:0;--tw-translate-y:0;--tw-translate-z:0;--tw-rotate-x:initial;--tw-rotate-y:initial;--tw-rotate-z:initial;--tw-skew-x:initial;--tw-skew-y:initial;--tw-space-y-reverse:0;--tw-space-x-reverse:0;--tw-divide-y-reverse:0;--tw-border-style:solid;--tw-gradient-position:initial;--tw-gradient-from:#0000;--tw-gradient-via:#0000;--tw-gradient-to:#0000;--tw-gradient-stops:initial;--tw-gradient-via-stops:initial;--tw-gradient-from-position:0%;--tw-gradient-via-position:50%;--tw-gradient-to-position:100%;--tw-leading:initial;--tw-font-weight:initial;--tw-tracking:initial;--tw-shadow:0 0 #0000;--tw-shadow-color:initial;--tw-shadow-alpha:100%;--tw-inset-shadow:0 0 #0000;--tw-inset-shadow-color:initial;--tw-inset-shadow-alpha:100%;--tw-ring-color:initial;--tw-ring-shadow:0 0 #0000;--tw-inset-ring-color:initial;--tw-inset-ring-shadow:0 0 #0000;--tw-ring-inset:initial;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-offset-shadow:0 0 #0000;--tw-outline-style:solid;--tw-blur:initial;--tw-brightness:initial;--tw-contrast:initial;--tw-grayscale:initial;--tw-hue-rotate:initial;--tw-invert:initial;--tw-opacity:initial;--tw-saturate:initial;--tw-sepia:initial;--tw-drop-shadow:initial;--tw-drop-shadow-color:initial;--tw-drop-shadow-alpha:100%;--tw-drop-shadow-size:initial;--tw-duration:initial;--tw-ease:initial;--tw-scale-x:1;--tw-scale-y:1;--tw-scale-z:1}}}@layer theme{:root,:host{--font-sans:ui-sans-serif,system-ui,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";--font-mono:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;--color-red-50:oklch(97.1% .013 17.38);--color-red-100:oklch(93.6% .032 17.717);--color-red-200:oklch(88.5% .062 18.334);--color-red-300:oklch(80.8% .114 19.571);--color-red-400:oklch(70.4% .191 22.216);--color-red-500:oklch(63.7% .237 25.331);--color-red-600:oklch(57.7% .245 27.325);--color-red-700:oklch(50.5% .213 27.518);--color-red-800:oklch(44.4% .177 26.899);--color-red-900:oklch(39.6% .141 25.723);--color-orange-50:oklch(98% .016 73.684);--color-orange-200:oklch(90.1% .076 70.697);--color-orange-400:oklch(75% .183 55.934);--color-orange-700:oklch(55.3% .195 38.402);--color-orange-800:oklch(47% .157 37.304);--color-amber-50:oklch(98.7% .022 95.277);--color-amber-100:oklch(96.2% .059 95.617);--color-amber-200:oklch(92.4% .12 95.746);--color-amber-300:oklch(87.9% .169 91.605);--color-amber-400:oklch(82.8% .189 84.429);--color-amber-500:oklch(76.9% .188 70.08);--color-amber-600:oklch(66.6% .179 58.318);--color-amber-700:oklch(55.5% .163 48.998);--color-amber-800:oklch(47.3% .137 46.201);--color-amber-900:oklch(41.4% .112 45.904);--color-yellow-50:oklch(98.7% .026 102.212);--color-yellow-100:oklch(97.3% .071 103.193);--color-yellow-200:oklch(94.5% .129 101.54);--color-yellow-400:oklch(85.2% .199 91.936);--color-yellow-500:oklch(79.5% .184 86.047);--color-yellow-600:oklch(68.1% .162 75.834);--color-yellow-700:oklch(55.4% .135 66.442);--color-yellow-800:oklch(47.6% .114 61.907);--color-green-50:oklch(98.2% .018 155.826);--color-green-100:oklch(96.2% .044 156.743);--color-green-200:oklch(92.5% .084 155.995);--color-green-400:oklch(79.2% .209 151.711);--color-green-500:oklch(72.3% .219 149.579);--color-green-600:oklch(62.7% .194 149.214);--color-green-700:oklch(52.7% .154 150.069);--color-green-800:oklch(44.8% .119 151.328);--color-green-900:oklch(39.3% .095 152.535);--color-blue-50:oklch(97% .014 254.604);--color-blue-100:oklch(93.2% .032 255.585);--color-blue-200:oklch(88.2% .059 254.128);--color-blue-300:oklch(80.9% .105 251.813);--color-blue-400:oklch(70.7% .165 254.624);--color-blue-500:oklch(62.3% .214 259.815);--color-blue-600:oklch(54.6% .245 262.881);--color-blue-700:oklch(48.8% .243 264.376);--color-blue-800:oklch(42.4% .199 265.638);--color-blue-900:oklch(37.9% .146 265.522);--color-purple-100:oklch(94.6% .033 307.174);--color-purple-300:oklch(82.7% .119 306.383);--color-purple-400:oklch(71.4% .203 305.504);--color-purple-600:oklch(55.8% .288 302.321);--color-purple-800:oklch(43.8% .218 303.724);--color-purple-900:oklch(38.1% .176 304.987);--color-gray-50:oklch(98.5% .002 247.839);--color-gray-100:oklch(96.7% .003 264.542);--color-gray-200:oklch(92.8% .006 264.531);--color-gray-300:oklch(87.2% .01 258.338);--color-gray-400:oklch(70.7% .022 261.325);--color-gray-500:oklch(55.1% .027 264.364);--color-gray-600:oklch(44.6% .03 256.802);--color-gray-700:oklch(37.3% .034 259.733);--color-gray-800:oklch(27.8% .033 256.848);--color-gray-900:oklch(21% .034 264.665);--color-black:#000;--color-white:#fff;--spacing:.25rem;--container-sm:24rem;--container-md:28rem;--container-lg:32rem;--container-3xl:48rem;--container-4xl:56rem;--text-xs:.75rem;--text-xs--line-height:calc(1/.75);--text-sm:.875rem;--text-sm--line-height:calc(1.25/.875);--text-lg:1.125rem;--text-lg--line-height:calc(1.75/1.125);--text-xl:1.25rem;--text-xl--line-height:calc(1.75/1.25);--text-2xl:1.5rem;--text-2xl--line-height:calc(2/1.5);--text-3xl:1.875rem;--text-3xl--line-height: 1.2 ;--font-weight-normal:400;--font-weight-medium:500;--font-weight-semibold:600;--font-weight-bold:700;--tracking-tight:-.025em;--tracking-wider:.05em;--leading-tight:1.25;--leading-relaxed:1.625;--radius-md:.375rem;--radius-lg:.5rem;--radius-xl:.75rem;--ease-out:cubic-bezier(0,0,.2,1);--ease-in-out:cubic-bezier(.4,0,.2,1);--animate-spin:spin 1s linear infinite;--animate-pulse:pulse 2s cubic-bezier(.4,0,.6,1)infinite;--default-transition-duration:.15s;--default-transition-timing-function:cubic-bezier(.4,0,.2,1);--default-font-family:var(--font-sans);--default-mono-font-family:var(--font-mono)}}@layer base{*,:after,:before,::backdrop{box-sizing:border-box;border:0 solid;margin:0;padding:0}::file-selector-button{box-sizing:border-box;border:0 solid;margin:0;padding:0}html,:host{-webkit-text-size-adjust:100%;-moz-tab-size:4;-o-tab-size:4;tab-size:4;line-height:1.5;font-family:var(--default-font-family,ui-sans-serif,system-ui,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji");font-feature-settings:var(--default-font-feature-settings,normal);font-variation-settings:var(--default-font-variation-settings,normal);-webkit-tap-highlight-color:transparent}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:var(--default-mono-font-family,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace);font-feature-settings:var(--default-mono-font-feature-settings,normal);font-variation-settings:var(--default-mono-font-variation-settings,normal);font-size:1em}small{font-size:80%}sub,sup{vertical-align:baseline;font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}:-moz-focusring{outline:auto}progress{vertical-align:baseline}summary{display:list-item}ol,ul,menu{list-style:none}img,svg,video,canvas,audio,iframe,embed,object{vertical-align:middle;display:block}img,video{max-width:100%;height:auto}button,input,select,optgroup,textarea{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}::file-selector-button{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}:where(select:is([multiple],[size])) optgroup{font-weight:bolder}:where(select:is([multiple],[size])) optgroup option{padding-inline-start:20px}::file-selector-button{margin-inline-end:4px}::-moz-placeholder{opacity:1}::placeholder{opacity:1}@supports (not (-webkit-appearance:-apple-pay-button)) or (contain-intrinsic-size:1px){::-moz-placeholder{color:currentColor}::placeholder{color:currentColor}@supports (color:color-mix(in lab,red,red)){::-moz-placeholder{color:color-mix(in oklab,currentcolor 50%,transparent)}::placeholder{color:color-mix(in oklab,currentcolor 50%,transparent)}}}textarea{resize:vertical}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-date-and-time-value{min-height:1lh;text-align:inherit}::-webkit-datetime-edit{display:inline-flex}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-datetime-edit{padding-block:0}::-webkit-datetime-edit-year-field{padding-block:0}::-webkit-datetime-edit-month-field{padding-block:0}::-webkit-datetime-edit-day-field{padding-block:0}::-webkit-datetime-edit-hour-field{padding-block:0}::-webkit-datetime-edit-minute-field{padding-block:0}::-webkit-datetime-edit-second-field{padding-block:0}::-webkit-datetime-edit-millisecond-field{padding-block:0}::-webkit-datetime-edit-meridiem-field{padding-block:0}::-webkit-calendar-picker-indicator{line-height:1}:-moz-ui-invalid{box-shadow:none}button,input:where([type=button],[type=reset],[type=submit]){-webkit-appearance:button;-moz-appearance:button;appearance:button}::file-selector-button{-webkit-appearance:button;-moz-appearance:button;appearance:button}::-webkit-inner-spin-button{height:auto}::-webkit-outer-spin-button{height:auto}[hidden]:where(:not([hidden=until-found])){display:none!important}}@layer components;@layer utilities{.pointer-events-none{pointer-events:none}.invisible{visibility:hidden}.visible{visibility:visible}.sr-only{clip-path:inset(50%);white-space:nowrap;border-width:0;width:1px;height:1px;margin:-1px;padding:0;position:absolute;overflow:hidden}.absolute{position:absolute}.fixed{position:fixed}.relative{position:relative}.inset-0{inset:calc(var(--spacing)*0)}.inset-y-0{inset-block:calc(var(--spacing)*0)}.-top-1{top:calc(var(--spacing)*-1)}.top-0{top:calc(var(--spacing)*0)}.top-1\/2{top:50%}.top-2{top:calc(var(--spacing)*2)}.top-3{top:calc(var(--spacing)*3)}.top-4{top:calc(var(--spacing)*4)}.top-full{top:100%}.-right-0\.5{right:calc(var(--spacing)*-.5)}.-right-1{right:calc(var(--spacing)*-1)}.right-0{right:calc(var(--spacing)*0)}.right-1\.5{right:calc(var(--spacing)*1.5)}.right-2{right:calc(var(--spacing)*2)}.right-4{right:calc(var(--spacing)*4)}.-bottom-0\.5{bottom:calc(var(--spacing)*-.5)}.left-0{left:calc(var(--spacing)*0)}.-z-10{z-index:-10}.z-20{z-index:20}.z-50{z-index:50}.z-\[60\]{z-index:60}.z-\[100\]{z-index:100}.m-0{margin:calc(var(--spacing)*0)}.-mx-1\.5{margin-inline:calc(var(--spacing)*-1.5)}.mx-1{margin-inline:calc(var(--spacing)*1)}.mx-4{margin-inline:calc(var(--spacing)*4)}.mx-auto{margin-inline:auto}.-my-1\.5{margin-block:calc(var(--spacing)*-1.5)}.my-4{margin-block:calc(var(--spacing)*4)}.my-6{margin-block:calc(var(--spacing)*6)}.mt-0\.5{margin-top:calc(var(--spacing)*.5)}.mt-1{margin-top:calc(var(--spacing)*1)}.mt-1\.5{margin-top:calc(var(--spacing)*1.5)}.mt-2{margin-top:calc(var(--spacing)*2)}.mt-3{margin-top:calc(var(--spacing)*3)}.mt-4{margin-top:calc(var(--spacing)*4)}.mt-5{margin-top:calc(var(--spacing)*5)}.mt-6{margin-top:calc(var(--spacing)*6)}.mr-1{margin-right:calc(var(--spacing)*1)}.mr-1\.5{margin-right:calc(var(--spacing)*1.5)}.mr-2{margin-right:calc(var(--spacing)*2)}.mr-3{margin-right:calc(var(--spacing)*3)}.mr-4{margin-right:calc(var(--spacing)*4)}.-mb-px{margin-bottom:-1px}.mb-1{margin-bottom:calc(var(--spacing)*1)}.mb-1\.5{margin-bottom:calc(var(--spacing)*1.5)}.mb-2{margin-bottom:calc(var(--spacing)*2)}.mb-3{margin-bottom:calc(var(--spacing)*3)}.mb-4{margin-bottom:calc(var(--spacing)*4)}.mb-5{margin-bottom:calc(var(--spacing)*5)}.mb-6{margin-bottom:calc(var(--spacing)*6)}.-ml-1{margin-left:calc(var(--spacing)*-1)}.ml-1{margin-left:calc(var(--spacing)*1)}.ml-1\.5{margin-left:calc(var(--spacing)*1.5)}.ml-2{margin-left:calc(var(--spacing)*2)}.ml-3{margin-left:calc(var(--spacing)*3)}.ml-4{margin-left:calc(var(--spacing)*4)}.ml-6{margin-left:calc(var(--spacing)*6)}.ml-auto{margin-left:auto}.line-clamp-2{-webkit-line-clamp:2;-webkit-box-orient:vertical;display:-webkit-box;overflow:hidden}.block{display:block}.flex{display:flex}.grid{display:grid}.hidden{display:none}.inline-block{display:inline-block}.inline-flex{display:inline-flex}.table{display:table}.h-1\.5{height:calc(var(--spacing)*1.5)}.h-2{height:calc(var(--spacing)*2)}.h-3{height:calc(var(--spacing)*3)}.h-3\.5{height:calc(var(--spacing)*3.5)}.h-4{height:calc(var(--spacing)*4)}.h-5{height:calc(var(--spacing)*5)}.h-6{height:calc(var(--spacing)*6)}.h-7{height:calc(var(--spacing)*7)}.h-8{height:calc(var(--spacing)*8)}.h-10{height:calc(var(--spacing)*10)}.h-12{height:calc(var(--spacing)*12)}.h-20{height:calc(var(--spacing)*20)}.h-64{height:calc(var(--spacing)*64)}.h-96{height:calc(var(--spacing)*96)}.h-\[6px\]{height:6px}.h-\[18px\]{height:18px}.h-\[38px\]{height:38px}.h-auto{height:auto}.h-full{height:100%}.h-px{height:1px}.h-screen{height:100vh}.max-h-32{max-height:calc(var(--spacing)*32)}.max-h-40{max-height:calc(var(--spacing)*40)}.max-h-48{max-height:calc(var(--spacing)*48)}.max-h-60{max-height:calc(var(--spacing)*60)}.max-h-64{max-height:calc(var(--spacing)*64)}.max-h-96{max-height:calc(var(--spacing)*96)}.max-h-\[90vh\]{max-height:90vh}.max-h-\[calc\(90vh-120px\)\]{max-height:calc(90vh - 120px)}.max-h-screen{max-height:100vh}.min-h-0{min-height:calc(var(--spacing)*0)}.min-h-\[30px\]{min-height:30px}.min-h-\[38px\]{min-height:38px}.min-h-\[240px\]{min-height:240px}.min-h-screen{min-height:100vh}.w-1\/2{width:50%}.w-2{width:calc(var(--spacing)*2)}.w-3{width:calc(var(--spacing)*3)}.w-3\.5{width:calc(var(--spacing)*3.5)}.w-4{width:calc(var(--spacing)*4)}.w-5{width:calc(var(--spacing)*5)}.w-6{width:calc(var(--spacing)*6)}.w-7{width:calc(var(--spacing)*7)}.w-8{width:calc(var(--spacing)*8)}.w-10{width:calc(var(--spacing)*10)}.w-11{width:calc(var(--spacing)*11)}.w-12{width:calc(var(--spacing)*12)}.w-14{width:calc(var(--spacing)*14)}.w-16{width:calc(var(--spacing)*16)}.w-20{width:calc(var(--spacing)*20)}.w-24{width:calc(var(--spacing)*24)}.w-40{width:calc(var(--spacing)*40)}.w-48{width:calc(var(--spacing)*48)}.w-56{width:calc(var(--spacing)*56)}.w-\[6px\]{width:6px}.w-\[30px\]{width:30px}.w-\[232px\]{width:232px}.w-full{width:100%}.max-w-3xl{max-width:var(--container-3xl)}.max-w-4xl{max-width:var(--container-4xl)}.max-w-\[1680px\]{max-width:1680px}.max-w-full{max-width:100%}.max-w-lg{max-width:var(--container-lg)}.max-w-md{max-width:var(--container-md)}.max-w-sm{max-width:var(--container-sm)}.min-w-0{min-width:calc(var(--spacing)*0)}.min-w-48{min-width:calc(var(--spacing)*48)}.min-w-\[30px\]{min-width:30px}.min-w-\[100px\]{min-width:100px}.min-w-\[140px\]{min-width:140px}.min-w-\[200px\]{min-width:200px}.min-w-full{min-width:100%}.min-w-max{min-width:-moz-max-content;min-width:max-content}.flex-1{flex:1}.flex-\[2\]{flex:2}.flex-\[4\]{flex:4}.flex-shrink-0,.shrink-0{flex-shrink:0}.flex-grow{flex-grow:1}.translate-x-0{--tw-translate-x:calc(var(--spacing)*0);translate:var(--tw-translate-x)var(--tw-translate-y)}.translate-x-1{--tw-translate-x:calc(var(--spacing)*1);translate:var(--tw-translate-x)var(--tw-translate-y)}.translate-x-6{--tw-translate-x:calc(var(--spacing)*6);translate:var(--tw-translate-x)var(--tw-translate-y)}.translate-x-full{--tw-translate-x:100%;translate:var(--tw-translate-x)var(--tw-translate-y)}.-translate-y-1\/2{--tw-translate-y: -50% ;translate:var(--tw-translate-x)var(--tw-translate-y)}.-translate-y-full{--tw-translate-y:-100%;translate:var(--tw-translate-x)var(--tw-translate-y)}.rotate-0{rotate:none}.rotate-90{rotate:90deg}.rotate-180{rotate:180deg}.transform{transform:var(--tw-rotate-x,)var(--tw-rotate-y,)var(--tw-rotate-z,)var(--tw-skew-x,)var(--tw-skew-y,)}.animate-pulse{animation:var(--animate-pulse)}.animate-spin{animation:var(--animate-spin)}.cursor-default{cursor:default}.cursor-not-allowed{cursor:not-allowed}.cursor-pointer{cursor:pointer}.resize-y{resize:vertical}.list-inside{list-style-position:inside}.list-disc{list-style-type:disc}.appearance-none{-webkit-appearance:none;-moz-appearance:none;appearance:none}.grid-cols-1{grid-template-columns:repeat(1,minmax(0,1fr))}.grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.flex-col{flex-direction:column}.flex-wrap{flex-wrap:wrap}.place-items-center{place-items:center}.items-baseline{align-items:baseline}.items-center{align-items:center}.items-end{align-items:flex-end}.items-start{align-items:flex-start}.justify-between{justify-content:space-between}.justify-center{justify-content:center}.justify-end{justify-content:flex-end}.gap-0\.5{gap:calc(var(--spacing)*.5)}.gap-1{gap:calc(var(--spacing)*1)}.gap-1\.5{gap:calc(var(--spacing)*1.5)}.gap-2{gap:calc(var(--spacing)*2)}.gap-2\.5{gap:calc(var(--spacing)*2.5)}.gap-3{gap:calc(var(--spacing)*3)}.gap-3\.5{gap:calc(var(--spacing)*3.5)}.gap-4{gap:calc(var(--spacing)*4)}.gap-5{gap:calc(var(--spacing)*5)}.gap-px{gap:1px}:where(.space-y-1>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing)*1)*var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing)*1)*calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-2>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing)*2)*var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing)*2)*calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-3>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing)*3)*var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing)*3)*calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-4>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing)*4)*var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing)*4)*calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-5>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing)*5)*var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing)*5)*calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-6>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing)*6)*var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing)*6)*calc(1 - var(--tw-space-y-reverse)))}:where(.space-y-8>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing)*8)*var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing)*8)*calc(1 - var(--tw-space-y-reverse)))}:where(.space-x-2>:not(:last-child)){--tw-space-x-reverse:0;margin-inline-start:calc(calc(var(--spacing)*2)*var(--tw-space-x-reverse));margin-inline-end:calc(calc(var(--spacing)*2)*calc(1 - var(--tw-space-x-reverse)))}:where(.space-x-3>:not(:last-child)){--tw-space-x-reverse:0;margin-inline-start:calc(calc(var(--spacing)*3)*var(--tw-space-x-reverse));margin-inline-end:calc(calc(var(--spacing)*3)*calc(1 - var(--tw-space-x-reverse)))}:where(.space-x-4>:not(:last-child)){--tw-space-x-reverse:0;margin-inline-start:calc(calc(var(--spacing)*4)*var(--tw-space-x-reverse));margin-inline-end:calc(calc(var(--spacing)*4)*calc(1 - var(--tw-space-x-reverse)))}:where(.divide-y>:not(:last-child)){--tw-divide-y-reverse:0;border-bottom-style:var(--tw-border-style);border-top-style:var(--tw-border-style);border-top-width:calc(1px*var(--tw-divide-y-reverse));border-bottom-width:calc(1px*calc(1 - var(--tw-divide-y-reverse)))}:where(.divide-gray-200>:not(:last-child)){border-color:var(--color-gray-200)}.self-center{align-self:center}.truncate{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.overflow-auto{overflow:auto}.overflow-hidden{overflow:hidden}.overflow-visible{overflow:visible}.overflow-x-auto{overflow-x:auto}.overflow-y-auto{overflow-y:auto}.rounded{border-radius:.25rem}.rounded-full{border-radius:3.40282e38px}.rounded-lg{border-radius:var(--radius-lg)}.rounded-md{border-radius:var(--radius-md)}.rounded-xl{border-radius:var(--radius-xl)}.rounded-t-lg{border-top-left-radius:var(--radius-lg);border-top-right-radius:var(--radius-lg)}.rounded-t-md{border-top-left-radius:var(--radius-md);border-top-right-radius:var(--radius-md)}.rounded-b{border-bottom-right-radius:.25rem;border-bottom-left-radius:.25rem}.rounded-b-md{border-bottom-right-radius:var(--radius-md);border-bottom-left-radius:var(--radius-md)}.border{border-style:var(--tw-border-style);border-width:1px}.border-2{border-style:var(--tw-border-style);border-width:2px}.border-t{border-top-style:var(--tw-border-style);border-top-width:1px}.border-t-0{border-top-style:var(--tw-border-style);border-top-width:0}.border-r{border-right-style:var(--tw-border-style);border-right-width:1px}.border-b{border-bottom-style:var(--tw-border-style);border-bottom-width:1px}.border-l-4{border-left-style:var(--tw-border-style);border-left-width:4px}.border-dashed{--tw-border-style:dashed;border-style:dashed}.border-\[oklch\(0\.88_0\.04_85\)\]{border-color:#e4d6ba}.border-\[oklch\(0\.88_0\.04_145\)\]{border-color:#c8dfc8}.border-\[var\(--hub-line\)\]{border-color:var(--hub-line)}.border-\[var\(--hub-line-2\)\]{border-color:var(--hub-line-2)}.border-amber-200{border-color:var(--color-amber-200)}.border-amber-300{border-color:var(--color-amber-300)}.border-blue-200{border-color:var(--color-blue-200)}.border-blue-300{border-color:var(--color-blue-300)}.border-blue-500{border-color:var(--color-blue-500)}.border-gray-100{border-color:var(--color-gray-100)}.border-gray-200{border-color:var(--color-gray-200)}.border-gray-300{border-color:var(--color-gray-300)}.border-gray-500{border-color:var(--color-gray-500)}.border-green-200{border-color:var(--color-green-200)}.border-green-400{border-color:var(--color-green-400)}.border-green-500{border-color:var(--color-green-500)}.border-orange-200{border-color:var(--color-orange-200)}.border-red-200{border-color:var(--color-red-200)}.border-red-300{border-color:var(--color-red-300)}.border-red-400{border-color:var(--color-red-400)}.border-red-500{border-color:var(--color-red-500)}.border-yellow-200{border-color:var(--color-yellow-200)}.border-yellow-500{border-color:var(--color-yellow-500)}.border-l-blue-500{border-left-color:var(--color-blue-500)}.border-l-green-500{border-left-color:var(--color-green-500)}.border-l-red-600{border-left-color:var(--color-red-600)}.border-l-yellow-500{border-left-color:var(--color-yellow-500)}.bg-\[\#13C3FF\]{background-color:#13c3ff}.bg-\[oklch\(0\.97_0\.02_85\)\]{background-color:#fbf4e6}.bg-\[oklch\(0\.97_0\.03_145\)\]{background-color:#e9fbe9}.bg-\[var\(--hub-bg-2\)\]{background-color:var(--hub-bg-2)}.bg-\[var\(--hub-surface\)\]{background-color:var(--hub-surface)}.bg-amber-50{background-color:var(--color-amber-50)}.bg-amber-100{background-color:var(--color-amber-100)}.bg-black\/50{background-color:#00000080}@supports (color:color-mix(in lab,red,red)){.bg-black\/50{background-color:color-mix(in oklab,var(--color-black)50%,transparent)}}.bg-blue-50{background-color:var(--color-blue-50)}.bg-blue-100{background-color:var(--color-blue-100)}.bg-blue-200{background-color:var(--color-blue-200)}.bg-blue-400\/80{background-color:#54a2ffcc}@supports (color:color-mix(in lab,red,red)){.bg-blue-400\/80{background-color:color-mix(in oklab,var(--color-blue-400)80%,transparent)}}.bg-blue-500{background-color:var(--color-blue-500)}.bg-gray-50{background-color:var(--color-gray-50)}.bg-gray-100{background-color:var(--color-gray-100)}.bg-gray-200{background-color:var(--color-gray-200)}.bg-gray-400{background-color:var(--color-gray-400)}.bg-gray-400\/80{background-color:#99a1afcc}@supports (color:color-mix(in lab,red,red)){.bg-gray-400\/80{background-color:color-mix(in oklab,var(--color-gray-400)80%,transparent)}}.bg-gray-900{background-color:var(--color-gray-900)}.bg-green-50{background-color:var(--color-green-50)}.bg-green-100{background-color:var(--color-green-100)}.bg-green-400\/80{background-color:#05df72cc}@supports (color:color-mix(in lab,red,red)){.bg-green-400\/80{background-color:color-mix(in oklab,var(--color-green-400)80%,transparent)}}.bg-green-600{background-color:var(--color-green-600)}.bg-orange-50{background-color:var(--color-orange-50)}.bg-orange-400\/80{background-color:#ff8b1acc}@supports (color:color-mix(in lab,red,red)){.bg-orange-400\/80{background-color:color-mix(in oklab,var(--color-orange-400)80%,transparent)}}.bg-purple-100{background-color:var(--color-purple-100)}.bg-purple-400\/80{background-color:#c07effcc}@supports (color:color-mix(in lab,red,red)){.bg-purple-400\/80{background-color:color-mix(in oklab,var(--color-purple-400)80%,transparent)}}.bg-red-50{background-color:var(--color-red-50)}.bg-red-100{background-color:var(--color-red-100)}.bg-red-400\/80{background-color:#ff6568cc}@supports (color:color-mix(in lab,red,red)){.bg-red-400\/80{background-color:color-mix(in oklab,var(--color-red-400)80%,transparent)}}.bg-red-500{background-color:var(--color-red-500)}.bg-transparent{background-color:#0000}.bg-white{background-color:var(--color-white)}.bg-white\/60{background-color:#fff9}@supports (color:color-mix(in lab,red,red)){.bg-white\/60{background-color:color-mix(in oklab,var(--color-white)60%,transparent)}}.bg-yellow-50{background-color:var(--color-yellow-50)}.bg-yellow-100{background-color:var(--color-yellow-100)}.bg-yellow-400\/80{background-color:#fac800cc}@supports (color:color-mix(in lab,red,red)){.bg-yellow-400\/80{background-color:color-mix(in oklab,var(--color-yellow-400)80%,transparent)}}.bg-gradient-to-br{--tw-gradient-position:to bottom right in oklab;background-image:linear-gradient(var(--tw-gradient-stops))}.bg-gradient-to-r{--tw-gradient-position:to right in oklab;background-image:linear-gradient(var(--tw-gradient-stops))}.from-blue-500{--tw-gradient-from:var(--color-blue-500);--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position),var(--tw-gradient-from)var(--tw-gradient-from-position),var(--tw-gradient-to)var(--tw-gradient-to-position))}.from-gray-100{--tw-gradient-from:var(--color-gray-100);--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position),var(--tw-gradient-from)var(--tw-gradient-from-position),var(--tw-gradient-to)var(--tw-gradient-to-position))}.to-gray-200{--tw-gradient-to:var(--color-gray-200);--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position),var(--tw-gradient-from)var(--tw-gradient-from-position),var(--tw-gradient-to)var(--tw-gradient-to-position))}.to-purple-600{--tw-gradient-to:var(--color-purple-600);--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position),var(--tw-gradient-from)var(--tw-gradient-from-position),var(--tw-gradient-to)var(--tw-gradient-to-position))}.object-cover{-o-object-fit:cover;object-fit:cover}.p-0{padding:calc(var(--spacing)*0)}.p-0\.5{padding:calc(var(--spacing)*.5)}.p-1{padding:calc(var(--spacing)*1)}.p-1\.5{padding:calc(var(--spacing)*1.5)}.p-2{padding:calc(var(--spacing)*2)}.p-2\.5{padding:calc(var(--spacing)*2.5)}.p-3{padding:calc(var(--spacing)*3)}.p-3\.5{padding:calc(var(--spacing)*3.5)}.p-4{padding:calc(var(--spacing)*4)}.p-5{padding:calc(var(--spacing)*5)}.p-6{padding:calc(var(--spacing)*6)}.p-8{padding:calc(var(--spacing)*8)}.p-10{padding:calc(var(--spacing)*10)}.p-12{padding:calc(var(--spacing)*12)}.px-1{padding-inline:calc(var(--spacing)*1)}.px-1\.5{padding-inline:calc(var(--spacing)*1.5)}.px-2{padding-inline:calc(var(--spacing)*2)}.px-2\.5{padding-inline:calc(var(--spacing)*2.5)}.px-3{padding-inline:calc(var(--spacing)*3)}.px-3\.5{padding-inline:calc(var(--spacing)*3.5)}.px-4{padding-inline:calc(var(--spacing)*4)}.px-5{padding-inline:calc(var(--spacing)*5)}.px-6{padding-inline:calc(var(--spacing)*6)}.py-0\.5{padding-block:calc(var(--spacing)*.5)}.py-1{padding-block:calc(var(--spacing)*1)}.py-1\.5{padding-block:calc(var(--spacing)*1.5)}.py-2{padding-block:calc(var(--spacing)*2)}.py-2\.5{padding-block:calc(var(--spacing)*2.5)}.py-3{padding-block:calc(var(--spacing)*3)}.py-4{padding-block:calc(var(--spacing)*4)}.py-5{padding-block:calc(var(--spacing)*5)}.py-12{padding-block:calc(var(--spacing)*12)}.pt-2{padding-top:calc(var(--spacing)*2)}.pt-3{padding-top:calc(var(--spacing)*3)}.pt-4{padding-top:calc(var(--spacing)*4)}.pt-6{padding-top:calc(var(--spacing)*6)}.pr-7{padding-right:calc(var(--spacing)*7)}.pr-9{padding-right:calc(var(--spacing)*9)}.pb-1\.5{padding-bottom:calc(var(--spacing)*1.5)}.pb-2{padding-bottom:calc(var(--spacing)*2)}.pb-3{padding-bottom:calc(var(--spacing)*3)}.pb-4{padding-bottom:calc(var(--spacing)*4)}.pb-16{padding-bottom:calc(var(--spacing)*16)}.pl-3{padding-left:calc(var(--spacing)*3)}.text-center{text-align:center}.text-left{text-align:left}.text-right{text-align:right}.font-mono{font-family:var(--font-mono)}.text-2xl{font-size:var(--text-2xl);line-height:var(--tw-leading,var(--text-2xl--line-height))}.text-3xl{font-size:var(--text-3xl);line-height:var(--tw-leading,var(--text-3xl--line-height))}.text-lg{font-size:var(--text-lg);line-height:var(--tw-leading,var(--text-lg--line-height))}.text-sm{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height))}.text-xl{font-size:var(--text-xl);line-height:var(--tw-leading,var(--text-xl--line-height))}.text-xs{font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height))}.text-\[10\.5px\]{font-size:10.5px}.text-\[11\.5px\]{font-size:11.5px}.text-\[11px\]{font-size:11px}.text-\[12\.5px\]{font-size:12.5px}.text-\[12px\]{font-size:12px}.text-\[13\.5px\]{font-size:13.5px}.text-\[13px\]{font-size:13px}.text-\[14px\]{font-size:14px}.leading-5{--tw-leading:calc(var(--spacing)*5);line-height:calc(var(--spacing)*5)}.leading-relaxed{--tw-leading:var(--leading-relaxed);line-height:var(--leading-relaxed)}.leading-tight{--tw-leading:var(--leading-tight);line-height:var(--leading-tight)}.font-bold{--tw-font-weight:var(--font-weight-bold);font-weight:var(--font-weight-bold)}.font-medium{--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium)}.font-normal{--tw-font-weight:var(--font-weight-normal);font-weight:var(--font-weight-normal)}.font-semibold{--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold)}.tracking-tight{--tw-tracking:var(--tracking-tight);letter-spacing:var(--tracking-tight)}.tracking-wider{--tw-tracking:var(--tracking-wider);letter-spacing:var(--tracking-wider)}.break-words{overflow-wrap:break-word}.break-all{word-break:break-all}.whitespace-nowrap{white-space:nowrap}.whitespace-pre-wrap{white-space:pre-wrap}.text-\[oklch\(0\.42_0\.12_145\)\]{color:#135d1d}.text-\[oklch\(0\.45_0\.07_85\)\]{color:#675223}.text-\[var\(--hub-err\)\]{color:var(--hub-err)}.text-\[var\(--hub-ink\)\]{color:var(--hub-ink)}.text-\[var\(--hub-ink-2\)\]{color:var(--hub-ink-2)}.text-\[var\(--hub-ink-3\)\]{color:var(--hub-ink-3)}.text-\[var\(--hub-ok\)\]{color:var(--hub-ok)}.text-amber-400{color:var(--color-amber-400)}.text-amber-600{color:var(--color-amber-600)}.text-amber-700{color:var(--color-amber-700)}.text-amber-800{color:var(--color-amber-800)}.text-blue-500{color:var(--color-blue-500)}.text-blue-600{color:var(--color-blue-600)}.text-blue-700{color:var(--color-blue-700)}.text-blue-800{color:var(--color-blue-800)}.text-gray-100{color:var(--color-gray-100)}.text-gray-400{color:var(--color-gray-400)}.text-gray-500{color:var(--color-gray-500)}.text-gray-600{color:var(--color-gray-600)}.text-gray-700{color:var(--color-gray-700)}.text-gray-800{color:var(--color-gray-800)}.text-gray-900{color:var(--color-gray-900)}.text-green-200{color:var(--color-green-200)}.text-green-500{color:var(--color-green-500)}.text-green-600{color:var(--color-green-600)}.text-green-700{color:var(--color-green-700)}.text-green-800{color:var(--color-green-800)}.text-orange-700{color:var(--color-orange-700)}.text-orange-800{color:var(--color-orange-800)}.text-purple-800{color:var(--color-purple-800)}.text-red-400{color:var(--color-red-400)}.text-red-500{color:var(--color-red-500)}.text-red-600{color:var(--color-red-600)}.text-red-700{color:var(--color-red-700)}.text-red-800{color:var(--color-red-800)}.text-white{color:var(--color-white)}.text-yellow-400{color:var(--color-yellow-400)}.text-yellow-500{color:var(--color-yellow-500)}.text-yellow-600{color:var(--color-yellow-600)}.text-yellow-700{color:var(--color-yellow-700)}.text-yellow-800{color:var(--color-yellow-800)}.uppercase{text-transform:uppercase}.italic{font-style:italic}.underline-offset-4{text-underline-offset:4px}.opacity-0{opacity:0}.opacity-25{opacity:.25}.opacity-50{opacity:.5}.opacity-75{opacity:.75}.opacity-100{opacity:1}.shadow{--tw-shadow:0 1px 3px 0 var(--tw-shadow-color,#0000001a),0 1px 2px -1px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.shadow-2xl{--tw-shadow:0 25px 50px -12px var(--tw-shadow-color,#00000040);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.shadow-lg{--tw-shadow:0 10px 15px -3px var(--tw-shadow-color,#0000001a),0 4px 6px -4px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.shadow-md{--tw-shadow:0 4px 6px -1px var(--tw-shadow-color,#0000001a),0 2px 4px -2px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.shadow-sm{--tw-shadow:0 1px 3px 0 var(--tw-shadow-color,#0000001a),0 1px 2px -1px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.shadow-xl{--tw-shadow:0 20px 25px -5px var(--tw-shadow-color,#0000001a),0 8px 10px -6px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.ring-1{--tw-ring-shadow:var(--tw-ring-inset,)0 0 0 calc(1px + var(--tw-ring-offset-width))var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.ring-\[var\(--hub-line\)\]{--tw-ring-color:var(--hub-line)}.ring-blue-500{--tw-ring-color:var(--color-blue-500)}.outline{outline-style:var(--tw-outline-style);outline-width:1px}.filter{filter:var(--tw-blur,)var(--tw-brightness,)var(--tw-contrast,)var(--tw-grayscale,)var(--tw-hue-rotate,)var(--tw-invert,)var(--tw-saturate,)var(--tw-sepia,)var(--tw-drop-shadow,)}.transition{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to,opacity,box-shadow,transform,translate,scale,rotate,filter,backdrop-filter,display,content-visibility,overlay,pointer-events;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-\[width\]{transition-property:width;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-all{transition-property:all;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-colors{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-opacity{transition-property:opacity;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-shadow{transition-property:box-shadow;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-transform{transition-property:transform,translate,scale,rotate;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.duration-150{--tw-duration:.15s;transition-duration:.15s}.duration-200{--tw-duration:.2s;transition-duration:.2s}.duration-300{--tw-duration:.3s;transition-duration:.3s}.ease-in-out{--tw-ease:var(--ease-in-out);transition-timing-function:var(--ease-in-out)}.ease-out{--tw-ease:var(--ease-out);transition-timing-function:var(--ease-out)}.outline-none{--tw-outline-style:none;outline-style:none}.select-none{-webkit-user-select:none;-moz-user-select:none;user-select:none}.ring-inset{--tw-ring-inset:inset}@media(hover:hover){.group-hover\:-translate-x-1:is(:where(.group):hover *){--tw-translate-x:calc(var(--spacing)*-1);translate:var(--tw-translate-x)var(--tw-translate-y)}.group-hover\:text-\[var\(--hub-ink-2\)\]:is(:where(.group):hover *){color:var(--hub-ink-2)}.group-hover\:opacity-100:is(:where(.group):hover *){opacity:1}}.file\:mr-4::file-selector-button{margin-right:calc(var(--spacing)*4)}.file\:rounded-md::file-selector-button{border-radius:var(--radius-md)}.file\:border-0::file-selector-button{border-style:var(--tw-border-style);border-width:0}.file\:bg-blue-50::file-selector-button{background-color:var(--color-blue-50)}.file\:px-4::file-selector-button{padding-inline:calc(var(--spacing)*4)}.file\:py-2::file-selector-button{padding-block:calc(var(--spacing)*2)}.file\:text-sm::file-selector-button{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height))}.file\:font-semibold::file-selector-button{--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold)}.file\:text-blue-700::file-selector-button{color:var(--color-blue-700)}.last\:mb-0:last-child{margin-bottom:calc(var(--spacing)*0)}@media(hover:hover){.hover\:border-blue-400:hover{border-color:var(--color-blue-400)}.hover\:border-gray-300:hover{border-color:var(--color-gray-300)}.hover\:border-gray-400:hover{border-color:var(--color-gray-400)}.hover\:bg-\[\#00A5E5\]:hover{background-color:#00a5e5}.hover\:bg-\[var\(--hub-surface-hover\)\]:hover{background-color:var(--hub-surface-hover)}.hover\:bg-amber-200:hover{background-color:var(--color-amber-200)}.hover\:bg-blue-50:hover{background-color:var(--color-blue-50)}.hover\:bg-blue-100:hover{background-color:var(--color-blue-100)}.hover\:bg-blue-200:hover{background-color:var(--color-blue-200)}.hover\:bg-blue-600:hover{background-color:var(--color-blue-600)}.hover\:bg-gray-50:hover{background-color:var(--color-gray-50)}.hover\:bg-gray-100:hover{background-color:var(--color-gray-100)}.hover\:bg-gray-200:hover{background-color:var(--color-gray-200)}.hover\:bg-gray-300:hover{background-color:var(--color-gray-300)}.hover\:bg-red-600:hover{background-color:var(--color-red-600)}.hover\:text-\[var\(--hub-ink\)\]:hover{color:var(--hub-ink)}.hover\:text-\[var\(--hub-ink-2\)\]:hover{color:var(--hub-ink-2)}.hover\:text-amber-700:hover{color:var(--color-amber-700)}.hover\:text-blue-600:hover{color:var(--color-blue-600)}.hover\:text-blue-800:hover{color:var(--color-blue-800)}.hover\:text-blue-900:hover{color:var(--color-blue-900)}.hover\:text-gray-500:hover{color:var(--color-gray-500)}.hover\:text-gray-600:hover{color:var(--color-gray-600)}.hover\:text-gray-700:hover{color:var(--color-gray-700)}.hover\:text-gray-900:hover{color:var(--color-gray-900)}.hover\:text-red-600:hover{color:var(--color-red-600)}.hover\:text-red-700:hover{color:var(--color-red-700)}.hover\:text-red-900:hover{color:var(--color-red-900)}.hover\:underline:hover{text-decoration-line:underline}.hover\:opacity-80:hover{opacity:.8}.hover\:file\:bg-blue-100:hover::file-selector-button{background-color:var(--color-blue-100)}}.focus\:border-blue-500:focus{border-color:var(--color-blue-500)}.focus\:border-transparent:focus{border-color:#0000}.focus\:ring-1:focus{--tw-ring-shadow:var(--tw-ring-inset,)0 0 0 calc(1px + var(--tw-ring-offset-width))var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.focus\:ring-2:focus{--tw-ring-shadow:var(--tw-ring-inset,)0 0 0 calc(2px + var(--tw-ring-offset-width))var(--tw-ring-color,currentcolor);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.focus\:ring-amber-500:focus{--tw-ring-color:var(--color-amber-500)}.focus\:ring-blue-500:focus{--tw-ring-color:var(--color-blue-500)}.focus\:ring-red-500:focus{--tw-ring-color:var(--color-red-500)}.focus\:ring-offset-2:focus{--tw-ring-offset-width:2px;--tw-ring-offset-shadow:var(--tw-ring-inset,)0 0 0 var(--tw-ring-offset-width)var(--tw-ring-offset-color)}.focus\:outline-none:focus{--tw-outline-style:none;outline-style:none}.focus-visible\:outline:focus-visible{outline-style:var(--tw-outline-style);outline-width:1px}.focus-visible\:outline-2:focus-visible{outline-style:var(--tw-outline-style);outline-width:2px}.focus-visible\:outline-offset-2:focus-visible{outline-offset:2px}.focus-visible\:outline-blue-500:focus-visible{outline-color:var(--color-blue-500)}.active\:scale-95:active{--tw-scale-x:95%;--tw-scale-y:95%;--tw-scale-z:95%;scale:var(--tw-scale-x)var(--tw-scale-y)}.disabled\:pointer-events-none:disabled{pointer-events:none}.disabled\:cursor-not-allowed:disabled{cursor:not-allowed}.disabled\:opacity-50:disabled{opacity:.5}.disabled\:opacity-60:disabled{opacity:.6}@media(min-width:40rem){.sm\:text-sm{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height))}}@media(min-width:48rem){.md\:col-span-3{grid-column:span 3/span 3}.md\:col-span-4{grid-column:span 4/span 4}.md\:col-span-9{grid-column:span 9/span 9}.md\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.md\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.md\:grid-cols-4{grid-template-columns:repeat(4,minmax(0,1fr))}.md\:grid-cols-5{grid-template-columns:repeat(5,minmax(0,1fr))}.md\:grid-cols-12{grid-template-columns:repeat(12,minmax(0,1fr))}}@media(min-width:64rem){.lg\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.lg\:px-8{padding-inline:calc(var(--spacing)*8)}}@media(min-width:80rem){.xl\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.xl\:px-10{padding-inline:calc(var(--spacing)*10)}}:where(.dark\:divide-gray-700:where(.dark,.dark *)>:not(:last-child)){border-color:var(--color-gray-700)}.dark\:border-amber-700:where(.dark,.dark *){border-color:var(--color-amber-700)}.dark\:border-amber-900\/50:where(.dark,.dark *){border-color:#7b330680}@supports (color:color-mix(in lab,red,red)){.dark\:border-amber-900\/50:where(.dark,.dark *){border-color:color-mix(in oklab,var(--color-amber-900)50%,transparent)}}.dark\:border-gray-600:where(.dark,.dark *){border-color:var(--color-gray-600)}.dark\:border-gray-700:where(.dark,.dark *){border-color:var(--color-gray-700)}.dark\:border-red-900\/50:where(.dark,.dark *){border-color:#82181a80}@supports (color:color-mix(in lab,red,red)){.dark\:border-red-900\/50:where(.dark,.dark *){border-color:color-mix(in oklab,var(--color-red-900)50%,transparent)}}.dark\:bg-amber-900\/20:where(.dark,.dark *){background-color:#7b330633}@supports (color:color-mix(in lab,red,red)){.dark\:bg-amber-900\/20:where(.dark,.dark *){background-color:color-mix(in oklab,var(--color-amber-900)20%,transparent)}}.dark\:bg-amber-900\/40:where(.dark,.dark *){background-color:#7b330666}@supports (color:color-mix(in lab,red,red)){.dark\:bg-amber-900\/40:where(.dark,.dark *){background-color:color-mix(in oklab,var(--color-amber-900)40%,transparent)}}.dark\:bg-blue-900:where(.dark,.dark *){background-color:var(--color-blue-900)}.dark\:bg-blue-900\/40:where(.dark,.dark *){background-color:#1c398e66}@supports (color:color-mix(in lab,red,red)){.dark\:bg-blue-900\/40:where(.dark,.dark *){background-color:color-mix(in oklab,var(--color-blue-900)40%,transparent)}}.dark\:bg-gray-700:where(.dark,.dark *){background-color:var(--color-gray-700)}.dark\:bg-gray-800:where(.dark,.dark *){background-color:var(--color-gray-800)}.dark\:bg-gray-800\/60:where(.dark,.dark *){background-color:#1e293999}@supports (color:color-mix(in lab,red,red)){.dark\:bg-gray-800\/60:where(.dark,.dark *){background-color:color-mix(in oklab,var(--color-gray-800)60%,transparent)}}.dark\:bg-green-900:where(.dark,.dark *){background-color:var(--color-green-900)}.dark\:bg-purple-900\/40:where(.dark,.dark *){background-color:#59168b66}@supports (color:color-mix(in lab,red,red)){.dark\:bg-purple-900\/40:where(.dark,.dark *){background-color:color-mix(in oklab,var(--color-purple-900)40%,transparent)}}.dark\:bg-red-900:where(.dark,.dark *){background-color:var(--color-red-900)}.dark\:bg-red-900\/20:where(.dark,.dark *){background-color:#82181a33}@supports (color:color-mix(in lab,red,red)){.dark\:bg-red-900\/20:where(.dark,.dark *){background-color:color-mix(in oklab,var(--color-red-900)20%,transparent)}}.dark\:from-gray-800:where(.dark,.dark *){--tw-gradient-from:var(--color-gray-800);--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position),var(--tw-gradient-from)var(--tw-gradient-from-position),var(--tw-gradient-to)var(--tw-gradient-to-position))}.dark\:to-gray-700:where(.dark,.dark *){--tw-gradient-to:var(--color-gray-700);--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position),var(--tw-gradient-from)var(--tw-gradient-from-position),var(--tw-gradient-to)var(--tw-gradient-to-position))}.dark\:text-amber-300:where(.dark,.dark *){color:var(--color-amber-300)}.dark\:text-amber-400:where(.dark,.dark *){color:var(--color-amber-400)}.dark\:text-amber-500:where(.dark,.dark *){color:var(--color-amber-500)}.dark\:text-blue-300:where(.dark,.dark *){color:var(--color-blue-300)}.dark\:text-blue-400:where(.dark,.dark *){color:var(--color-blue-400)}.dark\:text-gray-100:where(.dark,.dark *){color:var(--color-gray-100)}.dark\:text-gray-300:where(.dark,.dark *){color:var(--color-gray-300)}.dark\:text-gray-400:where(.dark,.dark *){color:var(--color-gray-400)}.dark\:text-gray-500:where(.dark,.dark *){color:var(--color-gray-500)}.dark\:text-green-200:where(.dark,.dark *){color:var(--color-green-200)}.dark\:text-purple-300:where(.dark,.dark *){color:var(--color-purple-300)}.dark\:text-red-200:where(.dark,.dark *){color:var(--color-red-200)}.dark\:text-red-300:where(.dark,.dark *){color:var(--color-red-300)}.dark\:text-red-400:where(.dark,.dark *){color:var(--color-red-400)}.dark\:text-red-500:where(.dark,.dark *){color:var(--color-red-500)}.dark\:text-white:where(.dark,.dark *){color:var(--color-white)}.dark\:text-yellow-400:where(.dark,.dark *){color:var(--color-yellow-400)}@media(hover:hover){.dark\:hover\:bg-amber-900\/60:where(.dark,.dark *):hover{background-color:#7b330699}@supports (color:color-mix(in lab,red,red)){.dark\:hover\:bg-amber-900\/60:where(.dark,.dark *):hover{background-color:color-mix(in oklab,var(--color-amber-900)60%,transparent)}}.dark\:hover\:bg-gray-100:where(.dark,.dark *):hover{background-color:var(--color-gray-100)}.dark\:hover\:bg-gray-600:where(.dark,.dark *):hover{background-color:var(--color-gray-600)}.dark\:hover\:bg-gray-700:where(.dark,.dark *):hover{background-color:var(--color-gray-700)}.dark\:hover\:bg-gray-800:where(.dark,.dark *):hover{background-color:var(--color-gray-800)}.dark\:hover\:text-gray-200:where(.dark,.dark *):hover{color:var(--color-gray-200)}.dark\:hover\:text-gray-300:where(.dark,.dark *):hover{color:var(--color-gray-300)}.dark\:hover\:text-gray-400:where(.dark,.dark *):hover{color:var(--color-gray-400)}}.dark\:focus\:ring-amber-400:where(.dark,.dark *):focus{--tw-ring-color:var(--color-amber-400)}}:root{--hub-bg:oklch(98.5% .002 250);--hub-bg-2:oklch(97.5% .002 250);--hub-surface:#fff;--hub-surface-hover:oklch(97% .003 250);--hub-ink:oklch(18% .01 250);--hub-ink-2:oklch(42% .01 250);--hub-ink-3:oklch(60% .01 250);--hub-line:oklch(92% .004 250);--hub-line-2:oklch(96% .003 250);--hub-accent:oklch(55% .15 250);--hub-accent-soft:oklch(95% .04 250);--hub-ok:oklch(66% .15 145);--hub-warn:oklch(78% .13 80);--hub-err:oklch(62% .18 25);--hub-mono:"Geist Mono","JetBrains Mono",ui-monospace,SFMono-Regular,Menlo,monospace}.dark{--hub-bg:oklch(18% .005 250);--hub-bg-2:oklch(21% .005 250);--hub-surface:oklch(22% .005 250);--hub-surface-hover:oklch(25% .005 250);--hub-ink:oklch(97% .005 250);--hub-ink-2:oklch(78% .005 250);--hub-ink-3:oklch(55% .005 250);--hub-line:oklch(30% .005 250);--hub-line-2:oklch(26% .005 250);--hub-accent-soft:oklch(32% .06 250)}.hub-card{background:var(--hub-surface);border:1px solid var(--hub-line);border-radius:10px}.hub-card-pad{padding:16px}.hub-surface{background:var(--hub-surface)}.hub-bg-2{background:var(--hub-bg-2)}.hub-border{border:1px solid var(--hub-line)}.hub-border-b{border-bottom:1px solid var(--hub-line-2)}.hub-border-t,.hub-divider>*+*{border-top:1px solid var(--hub-line-2)}.hub-mono{font-family:var(--hub-mono);font-feature-settings:"ss01";letter-spacing:-.01em}.hub-num{font-variant-numeric:tabular-nums}.hub-h1{letter-spacing:-.018em;color:var(--hub-ink);margin:0;font-size:22px;font-weight:600}.hub-sub{color:var(--hub-ink-3);margin:4px 0 0;font-size:13px}.hub-sect{color:var(--hub-ink-3);text-transform:uppercase;letter-spacing:.08em;font-size:11px;font-weight:500}.hub-card-title{color:var(--hub-ink);margin:0;font-size:13px;font-weight:500}.hub-status{color:var(--hub-ink-2);white-space:nowrap;align-items:center;gap:6px;font-size:12px;display:inline-flex}.hub-status-label{white-space:nowrap;text-overflow:ellipsis;min-width:0;overflow:hidden}.hub-dot{background:var(--hub-ink-3);border-radius:50%;flex-shrink:0;width:6px;height:6px}.hub-status.ok{color:#005813;color:oklch(40% .13 145)}.hub-status.ok .hub-dot{background:var(--hub-ok);box-shadow:0 0 0 3px #4ea95426}.hub-status.warn{color:#704e00;color:oklch(45% .13 80)}.hub-status.warn .hub-dot{background:var(--hub-warn);box-shadow:0 0 0 3px #e3ad4b2e}.hub-status.err{color:#a20519}.hub-status.err .hub-dot{background:var(--hub-err);box-shadow:0 0 0 3px #de4e4b26}.hub-status.muted{color:var(--hub-ink-3)}.hub-status.muted .hub-dot{background:var(--hub-ink-3)}.dark .hub-status.ok{color:#80cd82}.dark .hub-status.warn{color:#edbb64}.dark .hub-status.err{color:#ff958d;color:oklch(78% .15 25)}.hub-tag{color:var(--hub-ink-2);background:var(--hub-bg-2);border:1px solid var(--hub-line);font-size:11px;font-family:var(--hub-mono);white-space:nowrap;text-overflow:ellipsis;border-radius:5px;align-items:center;max-width:100%;padding:1px 7px;display:inline-flex;overflow:hidden}.hub-tag.accent{color:var(--hub-accent);background:var(--hub-accent-soft);border-color:#0000}.hub-tag.muted{color:var(--hub-ink-3)}.hub-kbd{font-family:var(--hub-mono);border:1px solid var(--hub-line);color:var(--hub-ink-3);background:var(--hub-surface);border-radius:4px;padding:1px 5px;font-size:11px}.hub-row{border-top:1px solid var(--hub-line-2);align-items:center;gap:12px;padding:11px 14px;display:grid}.hub-row:first-child{border-top:0}.hub-row.head{color:var(--hub-ink-3);text-transform:uppercase;letter-spacing:.08em;background:var(--hub-bg-2);padding:9px 14px;font-size:11px}.hub-row.hover:hover{background:var(--hub-surface-hover)}.hub-btn{border:1px solid var(--hub-line);background:var(--hub-surface);height:30px;color:var(--hub-ink);border-radius:7px;align-items:center;gap:6px;padding:0 12px;font-size:13px;font-weight:500;transition:background .15s,border-color .15s;display:inline-flex}.hub-btn:hover{background:var(--hub-surface-hover)}.hub-btn:disabled{opacity:.5;cursor:not-allowed}.hub-btn.primary{background:var(--hub-ink);color:var(--hub-bg);border-color:var(--hub-ink)}.hub-btn.primary:hover{background:#25292e}.dark .hub-btn.primary{color:#101214}.hub-btn.ghost{border-color:#0000}.hub-btn.ghost:hover{background:var(--hub-surface-hover);border-color:var(--hub-line)}.hub-btn.danger{color:var(--hub-err)}.hub-btn.danger:hover{background:#ffedeb;background:oklch(96% .04 25);border-color:#ffbab3;border-color:oklch(85% .1 25)}.dark .hub-btn.danger:hover{background:#4f1a18}.hub-btn.sm{height:26px;padding:0 9px;font-size:12px}.hub-icon-btn{width:30px;height:30px;color:var(--hub-ink-2);cursor:pointer;background:0 0;border:1px solid #0000;border-radius:7px;place-items:center;transition:background .15s,border-color .15s;display:inline-grid}.hub-icon-btn:hover{background:var(--hub-surface-hover);border-color:var(--hub-line)}.hub-icon-btn.sm{border-radius:6px;width:26px;height:26px}.hub-input{border:1px solid var(--hub-line);background:var(--hub-surface);height:32px;color:var(--hub-ink);border-radius:7px;outline:0;width:100%;padding:0 10px;font-size:13px}.hub-input:focus{border-color:var(--hub-ink-2)}.hub-input::-moz-placeholder{color:var(--hub-ink-3)}.hub-input::placeholder{color:var(--hub-ink-3)}.hub-input.mono{font-family:var(--hub-mono);font-size:12.5px}.hub-switch{background:var(--hub-line);cursor:pointer;border:0;border-radius:9px;flex:0 0 30px;width:30px;height:18px;padding:0;transition:background .15s;position:relative}.hub-switch:after{content:"";background:#fff;border-radius:50%;width:14px;height:14px;transition:transform .15s;position:absolute;top:2px;left:2px;box-shadow:0 1px 2px #0000001f}.hub-switch.on{background:var(--hub-ink)}.hub-switch:disabled{opacity:.5;cursor:not-allowed}.hub-server-card-row{grid-template-columns:minmax(136px,196px) fit-content(92px) fit-content(72px) minmax(94px,108px) repeat(3,88px) 44px 28px;justify-content:space-between;align-items:center;gap:10px;display:grid}.hub-server-card-row>*{min-width:0}.hub-server-card-visibility{justify-self:start;width:100%}.hub-status.hub-server-card-status{gap:5px;font-size:11.5px}.hub-status.hub-server-card-status .hub-dot{width:5px;height:5px}.hub-status.hub-server-card-status.ok .hub-dot{box-shadow:0 0 0 2px #4ea9541f}.hub-status.hub-server-card-status.warn .hub-dot{box-shadow:0 0 0 2px #e3ad4b24}.hub-status.hub-server-card-status.err .hub-dot{box-shadow:0 0 0 2px #de4e4b1f}.hub-server-card-transport-tag{letter-spacing:.02em;border-radius:999px;height:24px;padding:0 7px;font-size:10.5px}.hub-server-card-select,.hub-server-card-visibility-badge{height:30px}.hub-server-card-select{border-radius:7px;padding:0 26px 0 9px!important;font-size:11px!important}.hub-server-card-visibility-badge{border-radius:7px;padding:0 9px;font-size:11px}.hub-server-capability-stat{border:1px solid var(--hub-line-2);background:var(--hub-bg-2);min-width:0;height:26px;color:var(--hub-ink-2);border-radius:6px;grid-template-columns:14px minmax(0,1fr);justify-self:stretch;align-items:center;gap:5px;padding:0 6px;font-size:11px;line-height:1;display:grid}.hub-server-capability-stat.is-empty{color:var(--hub-ink-3);opacity:.56;background:0 0;border-color:#0000}.hub-server-capability-icon{flex-shrink:0;justify-content:center;align-items:center;width:14px;height:14px;line-height:0;display:inline-flex}.hub-server-capability-icon svg{display:block}.hub-server-capability-value{white-space:nowrap;text-overflow:clip;min-width:-moz-max-content;min-width:max-content;overflow:visible}@media(max-width:1440px){.hub-server-card-row{grid-template-columns:minmax(128px,180px) fit-content(88px) fit-content(66px) minmax(90px,102px) repeat(3,80px) 44px 28px;gap:9px}.hub-server-capability-stat{gap:5px;padding:0 6px}}.hub-endpoint{border:1px solid var(--hub-line);background:var(--hub-bg-2);border-radius:8px;align-items:center;gap:0;min-width:0;height:32px;display:flex;overflow:hidden}.hub-endpoint .hub-endpoint-label{border-right:1px solid var(--hub-line);height:100%;color:var(--hub-ink-3);font-size:11px;font-family:var(--hub-mono);text-transform:uppercase;letter-spacing:.05em;flex:none;align-items:center;padding:0 10px;display:flex}.hub-endpoint .hub-endpoint-url{font-family:var(--hub-mono);color:var(--hub-ink-2);white-space:nowrap;text-overflow:ellipsis;letter-spacing:-.01em;flex:1;min-width:0;padding:0 10px;font-size:12.5px;overflow:hidden}.hub-endpoint .hub-endpoint-copy{border-left:1px solid var(--hub-line);width:32px;height:100%;color:var(--hub-ink-3);cursor:pointer;background:0 0;border-top:0;border-bottom:0;border-right:0;border-radius:0;place-items:center;transition:background .15s;display:inline-grid}.hub-endpoint .hub-endpoint-copy:hover{background:var(--hub-surface-hover)}.hub-endpoint .hub-endpoint-copy.copied{color:var(--hub-ok)}.page-card .bg-gray-50,.page-card .dark\:bg-gray-800.rounded-md{background:var(--hub-bg-2)!important}.hub-sr-fields>div{border:1px solid var(--hub-line)!important;background:var(--hub-bg-2)!important;box-shadow:none!important;border-radius:8px!important;padding:12px 14px!important}.hub-sr-fields h3{color:var(--hub-ink)!important;font-size:12.5px!important;font-weight:500!important}.hub-sr-fields h3 .text-red-500{color:var(--hub-err)!important}.hub-sr-fields p{color:var(--hub-ink-3)!important}.hub-sr-fields input,.hub-sr-fields select{border:1px solid var(--hub-line)!important;background:var(--hub-surface)!important;height:32px!important;color:var(--hub-ink)!important;box-shadow:none!important;border-radius:7px!important;outline:0!important;margin-top:0!important;padding:0 10px!important;font-size:13px!important}.hub-sr-fields input.mono,.hub-sr-fields select.mono{font-family:var(--hub-mono)!important}.hub-sr-fields input:focus,.hub-sr-fields select:focus{border-color:var(--hub-ink-2)!important;box-shadow:none!important}.page-card,.dashboard-card{background:var(--hub-surface)!important;border:1px solid var(--hub-line)!important;box-shadow:none!important;border-radius:10px!important;transition:background .15s,border-color .15s!important}.page-card:hover,.dashboard-card:hover{box-shadow:none!important;transform:none!important}.dark .page-card,.dark .dashboard-card{background:var(--hub-surface)!important;border-color:var(--hub-line)!important;box-shadow:none!important}.dark .bg-white,.dark .dark\:bg-gray-800{background:var(--hub-surface)!important}.loading-container{background:var(--hub-surface)!important;border:1px solid var(--hub-line)!important;box-shadow:none!important;border-radius:10px!important}.empty-state{background:var(--hub-surface)!important;border:1px solid var(--hub-line)!important;text-align:center!important;border-radius:10px!important;padding:2.5rem 1.5rem!important}.empty-state p{color:var(--hub-ink-3)!important}.error-box{color:#8a0012!important;color:oklch(40% .18 25)!important;box-shadow:none!important;background:#fff1f0!important;background:oklch(97% .03 25)!important;border:1px solid oklch(85% .1 25)!important;border-radius:8px!important}.dark .error-box{background:#4f1a18!important;border-color:#972527!important}.error-box h3{color:#8a0012!important;color:oklch(40% .18 25)!important}.btn-primary{background:var(--hub-ink)!important;color:var(--hub-bg)!important;border:1px solid var(--hub-ink)!important;box-shadow:none!important;border-radius:7px!important;font-weight:500!important;transition:background .15s!important}.btn-primary:hover{color:var(--hub-bg)!important;box-shadow:none!important;background:#25292e!important;transform:none!important}.dark .btn-primary{background:var(--hub-ink)!important;color:#101214!important;border-color:var(--hub-ink)!important}.dark .btn-primary:hover{color:#101214!important;box-shadow:none!important;background:#e2e5e8!important;transform:none!important}.btn-secondary{background:var(--hub-surface)!important;color:var(--hub-ink)!important;border:1px solid var(--hub-line)!important;border-radius:7px!important;font-weight:500!important}.btn-secondary:hover{background:var(--hub-surface-hover)!important;color:var(--hub-ink)!important;border-color:var(--hub-line)!important;box-shadow:none!important;transform:none!important}.dark .btn-secondary,.dark .btn-secondary:hover{background:var(--hub-surface)!important;color:var(--hub-ink)!important;border-color:var(--hub-line)!important}.dark .btn-secondary:hover{background:var(--hub-surface-hover)!important}.btn-warning{color:#704e00!important;color:oklch(45% .13 80)!important;background:#fff0d7!important;background:oklch(96% .06 80)!important;border:1px solid oklch(85% .12 80)!important;border-radius:7px!important}.btn-warning:hover{color:#5f4200!important;color:oklch(40% .13 80)!important;background:#ffe4b7!important;background:oklch(93% .08 80)!important}.dark .btn-warning{color:#edbb64!important;background:#3e2a00!important;background:oklch(30% .08 80)!important;border-color:#704e00!important;border-color:oklch(45% .1 80)!important}.btn-danger{background:var(--hub-surface)!important;color:var(--hub-err)!important;border:1px solid var(--hub-line)!important;border-radius:7px!important}.btn-danger:hover{color:#8a0012!important;color:oklch(40% .18 25)!important;box-shadow:none!important;background:#fff1f0!important;background:oklch(97% .03 25)!important;border-color:#ffbab3!important;border-color:oklch(85% .1 25)!important;transform:none!important}.dark .btn-danger{background:var(--hub-surface)!important;color:#ff958d!important;color:oklch(78% .15 25)!important;border-color:var(--hub-line)!important}.dark .btn-danger:hover{background:#4f1a18!important;border-color:#972527!important}.form-input,input.form-input,select.form-input,textarea.form-input{background:var(--hub-surface)!important;border:1px solid var(--hub-line)!important;color:var(--hub-ink)!important;box-shadow:none!important;border-radius:7px!important;transition:border-color .15s!important}.form-input:focus,input.form-input:focus,select.form-input:focus,textarea.form-input:focus{border-color:var(--hub-ink-2)!important;box-shadow:none!important;outline:none!important}.dark .form-input,.dark input.form-input,.dark select.form-input,.dark textarea.form-input{background:var(--hub-surface)!important;border-color:var(--hub-line)!important;color:var(--hub-ink)!important}.status-badge-online,.status-badge-offline,.status-badge-connecting,.status-badge-oauth-required{background:0 0!important;border:0!important;border-radius:0!important;align-items:center!important;gap:6px!important;padding:0!important;font-size:12px!important;font-weight:500!important;line-height:1.4!important;display:inline-flex!important}.status-badge-online:before,.status-badge-offline:before,.status-badge-connecting:before,.status-badge-oauth-required:before{content:"";border-radius:50%;flex-shrink:0;width:6px;height:6px}.status-badge-online{color:#005813!important;color:oklch(40% .13 145)!important}.status-badge-online:before{background:var(--hub-ok);box-shadow:0 0 0 3px #4ea95426}.status-badge-offline{color:#a20519!important}.status-badge-offline:before{background:var(--hub-err);box-shadow:0 0 0 3px #de4e4b26}.status-badge-connecting{color:#704e00!important;color:oklch(45% .13 80)!important}.status-badge-connecting:before{background:var(--hub-warn);box-shadow:0 0 0 3px #e3ad4b2e}.status-badge-oauth-required{color:var(--hub-accent)!important}.status-badge-oauth-required:before{background:var(--hub-accent);box-shadow:0 0 0 3px #0f74c52e}.dark .status-badge-online,.dark .status-badge-offline,.dark .status-badge-connecting,.dark .status-badge-oauth-required{background:0 0!important;border:0!important}.dark .status-badge-online{color:#80cd82!important}.dark .status-badge-offline{color:#ff958d!important;color:oklch(78% .15 25)!important}.dark .status-badge-connecting{color:#edbb64!important}.status-icon-blue{background:var(--hub-accent-soft)!important;color:var(--hub-accent)!important}.status-icon-green{color:#005813!important;color:oklch(40% .13 145)!important;background:#dbf8da!important}.status-icon-red{color:#a20519!important;background:#ffedeb!important;background:oklch(96% .04 25)!important}.status-icon-yellow{color:#704e00!important;color:oklch(45% .13 80)!important;background:#fff0d7!important;background:oklch(96% .06 80)!important}.dark .status-icon-blue{color:#95c9ff!important;color:oklch(82% .1 250)!important;background:#193550!important}.dark .status-icon-green{color:#9bd69c!important;background:#1d341e!important}.dark .status-icon-red{color:#ff958d!important;color:oklch(78% .15 25)!important;background:#4f1a18!important}.dark .status-icon-yellow{color:#edbb64!important;background:#3d2a02!important}.table-container{overflow:hidden;box-shadow:none!important;border:1px solid var(--hub-line)!important;border-radius:10px!important}.dark .table-container{background:var(--hub-surface)!important;border-color:var(--hub-line)!important;box-shadow:none!important}.dark thead{background:var(--hub-bg-2)!important}.login-card{box-shadow:none!important}.hub-topbar{border-bottom:1px solid var(--hub-line);background:var(--hub-bg);align-items:center;gap:14px;height:48px;padding:0 22px;display:flex}.hub-crumb{color:var(--hub-ink-3);font-size:13px}.hub-crumb b{color:var(--hub-ink);font-weight:500}.hub-crumb .sep{color:var(--hub-ink-3);opacity:.5;margin:0 6px}body{-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;margin:0;font-family:Inter,PingFang SC,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,Fira Sans,Droid Sans,Helvetica Neue,sans-serif}.dark body{color:#e5e7eb;background-color:#1f2a37}.dark .bg-white{background-color:#1f2937!important}.dark .text-gray-900{color:#f9fafb!important}.dark .text-gray-800{color:#f3f4f6!important}.dark .text-gray-700{color:#e5e7eb!important}.dark .text-gray-600{color:#d1d5db!important}.dark .border-gray-300,.dark .border-gray-200,.dark .divide-gray-200>:not([hidden])~:not([hidden]){border-color:#2f3b4c!important}.dark .bg-gray-100{background-color:#374151!important}.dark .hover\:bg-gray-100:hover{background-color:#6e7f9c26!important}.dark .hover\:text-gray-900:hover{color:#bebcb9!important}.dark .bg-gray-50{background-color:#1f2937!important}.dark .shadow{box-shadow:0 4px 12px #00000026,0 2px 6px #0000001a!important}.bg-blue-300{background-color:var(--color-blue-300)}.bg-custom-blue{background-color:#4a90e2}.text-custom-white{color:#fff}.status-badge-online{border:1px solid #a6d7b7;color:#81c784e6!important;background-color:#fff!important}.dark .status-badge-online{border:1px solid #4caf504d;color:#81c784e6!important;background-color:#4caf5026!important}.status-badge-offline{border:1px solid #d1d5db;color:#6b7280e6!important;background-color:#fff!important}.dark .status-badge-offline{border:1px solid #6b72804d;color:#9ca3afe6!important;background-color:#6b728026!important}.status-badge-connecting{border:1px solid #ffd57f;color:#ffd54fe6!important;background-color:#fff!important}.dark .status-badge-connecting{border:1px solid #ffc1074d;color:#ffd54fe6!important;background-color:#ffc10726!important}.status-badge-oauth-required{border:1px solid #ba68c8;color:#9c27b0e6!important;background-color:#fff!important}.dark .status-badge-oauth-required{border:1px solid #9c27b04d;color:#ba68c8e6!important;background-color:#9c27b026!important}.dark .status-icon-blue{color:#60a5fae6!important;background-color:#3b82f626!important}.dark .status-icon-green{color:#81c784e6!important;background-color:#4caf5026!important}.dark .status-icon-red{color:#ef9a9ae6!important;background-color:#f4433626!important}.dark .status-icon-yellow{color:#ffd54fe6!important;background-color:#ffc10726!important}.dashboard-card{border-radius:12px;transition:all .3s}.dashboard-card:hover{transform:translateY(-2px);box-shadow:0 8px 25px #0003,0 4px 12px #00000026!important}.icon-container{transition:all .3s}.icon-container:hover{filter:brightness(1.1);transform:scale(1.05)}.progress-bar-online{background:linear-gradient(90deg,#4caf50cc,#81c78499)}.progress-bar-offline{background:linear-gradient(90deg,#f44336cc,#ef9a9a99)}.progress-bar-connecting{background:linear-gradient(90deg,#ffc107cc,#ffd54f99)}.dark .table-container{border-radius:12px;overflow:hidden;box-shadow:0 4px 12px #00000026}.dark thead{background-color:#252d3a!important}.dark tbody tr{border-bottom:1px solid #2f3b4c}tbody tr:hover{transition:background-color .2s;background-color:var(--color-gray-100)!important}.dark tbody tr:hover{transition:background-color .2s;background-color:#37415180!important}.dark .error-box{border-radius:12px;box-shadow:0 4px 12px #f443361a;background-color:#f443361a!important;border-color:#f443364d!important}.dark .error-box h3{color:#ef9a9ae6!important}.dark .error-box p{color:#d1d5db!important}.loading-container{-webkit-backdrop-filter:blur(10px);backdrop-filter:blur(10px);border-radius:12px}.dark .loading-container{border:1px solid #2f3b4c;background-color:#1f2937cc!important}.label-primary{background-color:var(--color-blue-50)!important;color:var(--color-blue-500)!important}.dark .label-primary{color:#60a5fae6!important;background-color:#3b82f626!important}.label-secondary{background-color:var(--color-green-50)!important;color:var(--color-green-500)!important}.dark .label-secondary{color:#81c784e6!important;background-color:#4caf5026!important}.btn-primary{border:none;border-radius:8px;transition:all .3s;box-shadow:0 2px 4px #60a5fa33;color:#fff!important;background-color:#60a5fa!important}.btn-primary:hover{transform:translateY(-1px);box-shadow:0 4px 12px #3b82f64d;color:#fff!important;background-color:#3b82f6!important}.dark .btn-primary{border:1px solid #3b82f64d;transition:all .3s;color:#60a5fae6!important;background-color:#3b82f626!important}.dark .btn-primary:hover{transform:translateY(-1px);box-shadow:0 4px 12px #3b82f633;color:#60a5fa!important;background-color:#3b82f640!important}.btn-secondary{border-radius:8px;font-size:.875rem;color:#374151!important;background-color:#f9fafb!important;border:1px solid #d1d5db!important}.btn-secondary:hover{transform:translateY(-1px);box-shadow:0 4px 12px #0000001a;color:#374151!important;background-color:#e5e7eb!important}.dark .btn-secondary{transition:all .3s;color:#9ca3afe6!important;background-color:#6b728026!important;border:1px solid #6b72804d!important}.dark .btn-secondary:hover{transform:translateY(-1px);color:#9ca3af!important;background-color:#6b728040!important}.btn-warning{border:none;border-radius:8px;transition:all .3s;background-color:var(--color-yellow-100)!important;color:var(--color-yellow-800)!important}.btn-warning:hover{background-color:var(--color-yellow-200)!important;color:var(--color-yellow-800)!important}.dark .btn-warning{border:1px solid #eab3084d;transition:all .3s;color:#facc15e6!important;background-color:#eab30826!important}.dark .btn-warning:hover{transform:translateY(-1px);color:#facc15!important;background-color:#eab30840!important}.btn-danger{border:none;border-radius:8px;transition:all .3s;background-color:var(--color-red-100)!important;color:var(--color-red-800)!important}.btn-danger:hover{background-color:var(--color-red-200)!important;color:var(--color-red-800)!important}.dark .btn-danger{border:1px solid #f443364d;transition:all .3s;color:#ef9a9ae6!important;background-color:#f4433626!important}.dark .btn-danger:hover{transform:translateY(-1px);box-shadow:0 4px 12px #f4433633;color:#ef9a9a!important;background-color:#f4433640!important}.form-input{border-radius:8px;transition:all .3s;color:#374151!important;background-color:#f9fafb!important;border-color:#d1d5db!important}.form-input:focus{border-color:#b8c1cf80;box-shadow:0 0 0 3px #3b82f61a}.dark .form-input{border-radius:8px;color:#e5e7eb!important;background-color:#1f2937!important;border-color:#2f3b4c!important}.dark .form-input:focus{border-color:#3b82f680!important;box-shadow:0 0 0 3px #3b82f61a!important}.dark .form-input::-moz-placeholder{color:#9ca3af!important}.dark .form-input::placeholder{color:#9ca3af!important}.page-card{border-radius:12px;transition:all .3s}.page-card:hover{transform:translateY(-1px)}.dark .page-card{border:1px solid #2f3b4c;box-shadow:0 4px 12px #00000026,0 2px 6px #0000001a;background-color:#1f2937!important}.text-status-red{color:#991b1b}.dark .text-status-red{color:#ef9a9ae6!important}.external-link{cursor:pointer;border-bottom:1px solid #0000;text-decoration:none;transition:all .2s ease-in-out;color:#2563eb!important}.external-link:hover{border-bottom-color:#1d4ed8;text-decoration:none;color:#1d4ed8!important}.dark .external-link{color:#60a5fa!important}.dark .external-link:hover{border-bottom-color:#93c5fd;color:#93c5fd!important}.border-red{border-color:#937d7d}.dark .border-red{border-color:#bca1a1e6!important}.dark .text-status-green{color:#81c784e6!important}.dark .empty-state{text-align:center;border:1px solid #2f3b4c;border-radius:12px;padding:3rem 2rem;background-color:#1f2937!important}.dark .empty-state p{color:#9ca3af!important}.dark .login-container{background-color:#1f2a37!important}.dark .login-card{border:1px solid #2f3b4c;border-radius:12px;box-shadow:0 8px 25px #0003,0 4px 12px #00000026;background-color:#1f2937!important}button{transition:transform .15s,opacity .15s}button:not(:disabled):active{transform:scale(.96)}button.is-loading{color:#0000!important;pointer-events:none!important;position:relative!important}button.is-loading>*{opacity:0!important}button.is-loading:after{content:"";border:2px solid #80808066;border-top-color:#666;border-radius:50%;width:1.2rem;height:1.2rem;margin-top:-.6rem;margin-left:-.6rem;animation:.6s linear infinite button-spinner;position:absolute;top:50%;left:50%;visibility:visible!important}button.bg-blue-600.is-loading:after,button.bg-blue-500.is-loading:after,button.bg-red-500.is-loading:after,button.bg-red-600.is-loading:after,button.btn-primary.is-loading:after,button.text-white.is-loading:after{border:2px solid #ffffff4d!important;border-top-color:#fff!important}@keyframes button-spinner{to{transform:rotate(360deg)}}@property --tw-translate-x{syntax:"*";inherits:false;initial-value:0}@property --tw-translate-y{syntax:"*";inherits:false;initial-value:0}@property --tw-translate-z{syntax:"*";inherits:false;initial-value:0}@property --tw-rotate-x{syntax:"*";inherits:false}@property --tw-rotate-y{syntax:"*";inherits:false}@property --tw-rotate-z{syntax:"*";inherits:false}@property --tw-skew-x{syntax:"*";inherits:false}@property --tw-skew-y{syntax:"*";inherits:false}@property --tw-space-y-reverse{syntax:"*";inherits:false;initial-value:0}@property --tw-space-x-reverse{syntax:"*";inherits:false;initial-value:0}@property --tw-divide-y-reverse{syntax:"*";inherits:false;initial-value:0}@property --tw-border-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-gradient-position{syntax:"*";inherits:false}@property --tw-gradient-from{syntax:"<color>";inherits:false;initial-value:#0000}@property --tw-gradient-via{syntax:"<color>";inherits:false;initial-value:#0000}@property --tw-gradient-to{syntax:"<color>";inherits:false;initial-value:#0000}@property --tw-gradient-stops{syntax:"*";inherits:false}@property --tw-gradient-via-stops{syntax:"*";inherits:false}@property --tw-gradient-from-position{syntax:"<length-percentage>";inherits:false;initial-value:0%}@property --tw-gradient-via-position{syntax:"<length-percentage>";inherits:false;initial-value:50%}@property --tw-gradient-to-position{syntax:"<length-percentage>";inherits:false;initial-value:100%}@property --tw-leading{syntax:"*";inherits:false}@property --tw-font-weight{syntax:"*";inherits:false}@property --tw-tracking{syntax:"*";inherits:false}@property --tw-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-shadow-color{syntax:"*";inherits:false}@property --tw-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-inset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-shadow-color{syntax:"*";inherits:false}@property --tw-inset-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-ring-color{syntax:"*";inherits:false}@property --tw-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-ring-color{syntax:"*";inherits:false}@property --tw-inset-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-ring-inset{syntax:"*";inherits:false}@property --tw-ring-offset-width{syntax:"<length>";inherits:false;initial-value:0}@property --tw-ring-offset-color{syntax:"*";inherits:false;initial-value:#fff}@property --tw-ring-offset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-outline-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-blur{syntax:"*";inherits:false}@property --tw-brightness{syntax:"*";inherits:false}@property --tw-contrast{syntax:"*";inherits:false}@property --tw-grayscale{syntax:"*";inherits:false}@property --tw-hue-rotate{syntax:"*";inherits:false}@property --tw-invert{syntax:"*";inherits:false}@property --tw-opacity{syntax:"*";inherits:false}@property --tw-saturate{syntax:"*";inherits:false}@property --tw-sepia{syntax:"*";inherits:false}@property --tw-drop-shadow{syntax:"*";inherits:false}@property --tw-drop-shadow-color{syntax:"*";inherits:false}@property --tw-drop-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-drop-shadow-size{syntax:"*";inherits:false}@property --tw-duration{syntax:"*";inherits:false}@property --tw-ease{syntax:"*";inherits:false}@property --tw-scale-x{syntax:"*";inherits:false;initial-value:1}@property --tw-scale-y{syntax:"*";inherits:false;initial-value:1}@property --tw-scale-z{syntax:"*";inherits:false;initial-value:1}@keyframes spin{to{transform:rotate(360deg)}}@keyframes pulse{50%{opacity:.5}}