@protobase/ui 0.60.1 → 0.62.0

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 (37) hide show
  1. package/dist/app/app.js +7 -3
  2. package/dist/app/marks/mark-people.js +24 -0
  3. package/dist/app/pages/merge-ui.d.ts +2 -1
  4. package/dist/app/pages/merge-ui.js +4 -1
  5. package/dist/app/pages/project-ui.d.ts +7 -1
  6. package/dist/app/use-nav-recent.js +7 -2
  7. package/dist/app-shell/nav.d.ts +4 -1
  8. package/dist/app-shell/record-marks.js +21 -2
  9. package/dist/app-shell/sidebar-records.js +7 -1
  10. package/dist/index.d.ts +3 -2
  11. package/dist/index.js +3 -2
  12. package/dist/organizations/members-page.js +11 -5
  13. package/dist/package.js +1 -1
  14. package/dist/presence/presence-dot.js +17 -0
  15. package/dist/presence/presence-provider.js +36 -0
  16. package/dist/presence/presence.d.ts +14 -0
  17. package/dist/presence/presence.js +31 -0
  18. package/dist/shell/assets/{app-DTBU_zpR.js → app-Dk6Wz4uU.js} +7 -7
  19. package/dist/shell/assets/index-Iii7afo2.css +2 -0
  20. package/dist/shell/assets/{index-Jqqke1wV.js → index-Qko7VXeJ.js} +2 -2
  21. package/dist/shell/assets/{records-map-BbFggRwi.js → records-map-DMtWYUIm.js} +2 -2
  22. package/dist/shell/assets/shared-protobase-ui-DJI957cu.js +2 -0
  23. package/dist/shell/index.html +4 -4
  24. package/dist/shell/protobase.shell.json +2 -2
  25. package/dist/shell/protobase.sw.js +2 -2
  26. package/dist/shell-source-maps/assets/app-Dk6Wz4uU.js.map +1 -0
  27. package/dist/shell-source-maps/assets/{index-Jqqke1wV.js.map → index-Qko7VXeJ.js.map} +1 -1
  28. package/dist/shell-source-maps/assets/{records-map-BbFggRwi.js.map → records-map-DMtWYUIm.js.map} +1 -1
  29. package/dist/shell-source-maps/assets/shared-protobase-ui-DJI957cu.js.map +1 -0
  30. package/dist/status/messages.js +6 -2
  31. package/dist/status/status-mark.d.ts +4 -4
  32. package/dist/status/status-mark.js +3 -2
  33. package/package.json +4 -4
  34. package/dist/shell/assets/index-D0sx7n9i.css +0 -2
  35. package/dist/shell/assets/shared-protobase-ui-BgSucvf-.js +0 -2
  36. package/dist/shell-source-maps/assets/app-DTBU_zpR.js.map +0 -1
  37. package/dist/shell-source-maps/assets/shared-protobase-ui-BgSucvf-.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"index-Jqqke1wV.js","names":["createRoot","StrictMode","projectUi","__exportAll","__toESM","require_react","require_client","require_jsx_runtime","uiFromModule","nativeBridgeOf","App","relList","link","processPreload","mutation","mutations","node","getFetchOpts","fetchOpts","import_react","import_client","_virtual_protobase_project_ui_exports","_virtual_protobase_project_ui_default","apiOriginMeta","showKeyboardAccessoryBar","bridge","nativeViewport","content","part","applyNativeViewport","meta","doc","apiOriginOf","contents","value","url","pageApiOrigin","import_jsx_runtime","root","nativeBridge","browserLocale"],"sources":["../../../../schema/src/api-origin-meta.ts","../../../src/app/native-keyboard.ts","../../../src/app/native-viewport.ts","../../../src/app/page-api-origin.ts","../../../src/app/main.tsx"],"sourcesContent":["/**\n * The `<meta name>` whose `content` names the origin of the API the shell calls, such as `https://shop.example.com`, for\n * a page served from elsewhere: `protobase mobile` writes it into the app's `index.html`. Without it, the shell calls\n * the API on its own origin.\n */\nexport const apiOriginMeta = 'protobase-api-origin'\n","import type { NativeBridge } from './native-auth-fetch'\n\n/**\n * Gives the iOS app's keyboard back the bar above it, with the arrows to the previous and next field and Done, which\n * Capacitor's keyboard plugin hides when it loads and has no setting for. A binary built before it had the plugin,\n * and Android, which has no such bar, are left as they are.\n */\nexport const showKeyboardAccessoryBar = async (bridge: NativeBridge) => {\n if (bridge.getPlatform() !== 'ios' || !bridge.isPluginAvailable('Keyboard')) return\n await bridge.nativePromise('Keyboard', 'setAccessoryBarVisible', { isVisible: true })\n}\n","/**\n * The viewport of the iOS and Android app: as the page's, at a scale of one. Safari on iOS zooms into an input whose\n * text is smaller than 16px when it is focused, and in the app the page then stays zoomed with its right side cut off;\n * an app does not zoom, so its viewport stays at that scale, under a pinch too. The page in a browser keeps its zoom.\n */\nexport const nativeViewport = (content: string) => {\n const kept = content.split(',').map((part) => part.trim()).filter((part) => part && !/^maximum-scale\\s*=/.test(part))\n return [...kept, 'maximum-scale=1'].join(', ')\n}\n\n/** Gives the document's viewport the app's scale; a document without a viewport tag needs none. */\nexport const applyNativeViewport = (doc: Document) => {\n const meta = doc.querySelector('meta[name=\"viewport\"]')\n if (!meta) return\n meta.setAttribute('content', nativeViewport(meta.getAttribute('content') ?? ''))\n}\n","import { apiOriginMeta } from '@protobase/schema/internal'\n\n/**\n * The API origin the page's `<meta name=\"protobase-api-origin\">` tags name: `undefined` without one. Anything but one\n * tag holding exactly an http or https origin, such as `https://shop.example.com`, is an error.\n */\nexport const apiOriginOf = (contents: string[]) => {\n if (contents.length === 0) return undefined\n if (contents.length > 1) throw new Error(`The page has ${contents.length} ${apiOriginMeta} meta tags; it may have one`)\n const value = contents[0]!\n const url = URL.canParse(value) ? new URL(value) : undefined\n if (!url || (url.protocol !== 'http:' && url.protocol !== 'https:') || url.origin !== value) {\n throw new Error(`The page's ${apiOriginMeta} meta tag holds \"${value}\", which is not an http or https origin such as https://shop.example.com`)\n }\n return value\n}\n\n/** The API origin this page names in its `<meta name=\"protobase-api-origin\">` (see `apiOriginOf`). */\nexport const pageApiOrigin = () =>\n apiOriginOf([...document.querySelectorAll<HTMLMetaElement>(`meta[name=\"${apiOriginMeta}\"]`)].map((meta) => meta.content))\n","import { StrictMode } from 'react'\nimport { createRoot } from 'react-dom/client'\nimport * as projectUi from 'virtual:protobase-project-ui'\nimport '../styles.css'\nimport { browserLocale } from '../locale/active-locale'\nimport { App } from './app'\nimport { nativeBridgeOf, type NativeBridge } from './native-auth-fetch'\nimport { showKeyboardAccessoryBar } from './native-keyboard'\nimport { applyNativeViewport } from './native-viewport'\nimport { pageApiOrigin } from './page-api-origin'\nimport { uiFromModule } from './pages/ui-from-module'\n\nconst root = document.getElementById('root')\nif (!root) throw new Error('index.html needs an element with id \"root\"')\n\nconst nativeBridge = nativeBridgeOf(window as { Capacitor?: NativeBridge })\nif (nativeBridge) {\n applyNativeViewport(document)\n void showKeyboardAccessoryBar(nativeBridge)\n}\n\ncreateRoot(root).render(\n <StrictMode>\n <App baseUrl={`${pageApiOrigin() ?? ''}/api/v1`} ui={uiFromModule(projectUi)} locale={browserLocale()} nativeBridge={nativeBridge} />\n </StrictMode>,\n)\n"],"mappings":"85BAKauB,EAAgB,uBCEhBC,EAA2B,KAAO,IAAyB,CAClEC,EAAO,YAAY,IAAM,OAAUA,EAAO,kBAAkB,UAAU,GAC1E,MAAMA,EAAO,cAAc,WAAY,yBAA0B,CAAE,UAAW,EAAK,CAAC,CACtF,ECLaC,EAAkB,GAEtB,CAAC,GADKC,EAAQ,MAAM,GAAG,CAAC,CAAC,IAAK,GAASC,EAAK,KAAK,CAAC,CAAC,CAAC,OAAQ,GAASA,GAAQ,CAAC,qBAAqB,KAAKA,CAAI,CACxG,EAAM,iBAAiB,CAAC,CAAC,KAAK,IAAI,EAIlCC,EAAuB,GAAkB,CACpD,IAAMC,EAAOC,EAAI,cAAc,uBAAuB,EACjDD,GACLA,EAAK,aAAa,UAAWJ,EAAeI,EAAK,aAAa,SAAS,GAAK,EAAE,CAAC,CACjF,ECTaE,EAAe,GAAuB,CACjD,GAAIC,EAAS,SAAW,EAAG,OAC3B,GAAIA,EAAS,OAAS,EAAG,MAAU,MAAM,gBAAgBA,EAAS,OAAO,GAAGV,EAAc,4BAA4B,EACtH,IAAMW,EAAQD,EAAS,GACjBE,EAAM,IAAI,SAASD,CAAK,EAAI,IAAI,IAAIA,CAAK,EAAI,IAAA,GACnD,GAAI,CAACC,GAAQA,EAAI,WAAa,SAAWA,EAAI,WAAa,UAAaA,EAAI,SAAWD,EACpF,MAAU,MAAM,cAAcX,EAAc,mBAAmBW,EAAM,yEAAyE,EAEhJ,OAAOA,CACT,EAGaE,MACXJ,EAAY,CAAC,GAAG,SAAS,iBAAkC,cAAcT,EAAc,GAAG,CAAC,CAAC,CAAC,IAAK,GAASO,EAAK,OAAO,CAAC,aCPpHQ,EAAO,SAAS,eAAe,MAAM,EAC3C,GAAI,CAACA,EAAM,MAAU,MAAM,4CAA4C,EAEvE,IAAMC,EAAe9B,EAAe,MAAsC,EACtE8B,IACFV,EAAoB,QAAQ,EAC5BL,EAA8Be,CAAY,IAG5CvC,EAAAA,EAAAA,WAAAA,CAAWsC,CAAI,CAAC,CAAC,QACf,EAAAD,EAAA,IAAA,CAACpC,EAAAA,WAAD,CAAA,UACE,EAAAoC,EAAA,IAAA,CAAC3B,EAAD,CAAK,QAAS,GAAG0B,EAAc,GAAK,GAAG,SAAU,GAAI5B,EAAaN,CAAS,EAAG,OAAQsC,EAAc,EAAiB,cAAe,CAAA,CAC1H,CAAA,CACd","debugId":"09aaa91e-d705-42eb-a101-ca5b8d300bcf"}
1
+ {"version":3,"file":"index-Qko7VXeJ.js","names":["createRoot","StrictMode","projectUi","__exportAll","__toESM","require_react","require_client","require_jsx_runtime","uiFromModule","nativeBridgeOf","App","relList","link","processPreload","mutation","mutations","node","getFetchOpts","fetchOpts","import_react","import_client","_virtual_protobase_project_ui_exports","_virtual_protobase_project_ui_default","apiOriginMeta","showKeyboardAccessoryBar","bridge","nativeViewport","content","part","applyNativeViewport","meta","doc","apiOriginOf","contents","value","url","pageApiOrigin","import_jsx_runtime","root","nativeBridge","browserLocale"],"sources":["../../../../schema/src/api-origin-meta.ts","../../../src/app/native-keyboard.ts","../../../src/app/native-viewport.ts","../../../src/app/page-api-origin.ts","../../../src/app/main.tsx"],"sourcesContent":["/**\n * The `<meta name>` whose `content` names the origin of the API the shell calls, such as `https://shop.example.com`, for\n * a page served from elsewhere: `protobase mobile` writes it into the app's `index.html`. Without it, the shell calls\n * the API on its own origin.\n */\nexport const apiOriginMeta = 'protobase-api-origin'\n","import type { NativeBridge } from './native-auth-fetch'\n\n/**\n * Gives the iOS app's keyboard back the bar above it, with the arrows to the previous and next field and Done, which\n * Capacitor's keyboard plugin hides when it loads and has no setting for. A binary built before it had the plugin,\n * and Android, which has no such bar, are left as they are.\n */\nexport const showKeyboardAccessoryBar = async (bridge: NativeBridge) => {\n if (bridge.getPlatform() !== 'ios' || !bridge.isPluginAvailable('Keyboard')) return\n await bridge.nativePromise('Keyboard', 'setAccessoryBarVisible', { isVisible: true })\n}\n","/**\n * The viewport of the iOS and Android app: as the page's, at a scale of one. Safari on iOS zooms into an input whose\n * text is smaller than 16px when it is focused, and in the app the page then stays zoomed with its right side cut off;\n * an app does not zoom, so its viewport stays at that scale, under a pinch too. The page in a browser keeps its zoom.\n */\nexport const nativeViewport = (content: string) => {\n const kept = content.split(',').map((part) => part.trim()).filter((part) => part && !/^maximum-scale\\s*=/.test(part))\n return [...kept, 'maximum-scale=1'].join(', ')\n}\n\n/** Gives the document's viewport the app's scale; a document without a viewport tag needs none. */\nexport const applyNativeViewport = (doc: Document) => {\n const meta = doc.querySelector('meta[name=\"viewport\"]')\n if (!meta) return\n meta.setAttribute('content', nativeViewport(meta.getAttribute('content') ?? ''))\n}\n","import { apiOriginMeta } from '@protobase/schema/internal'\n\n/**\n * The API origin the page's `<meta name=\"protobase-api-origin\">` tags name: `undefined` without one. Anything but one\n * tag holding exactly an http or https origin, such as `https://shop.example.com`, is an error.\n */\nexport const apiOriginOf = (contents: string[]) => {\n if (contents.length === 0) return undefined\n if (contents.length > 1) throw new Error(`The page has ${contents.length} ${apiOriginMeta} meta tags; it may have one`)\n const value = contents[0]!\n const url = URL.canParse(value) ? new URL(value) : undefined\n if (!url || (url.protocol !== 'http:' && url.protocol !== 'https:') || url.origin !== value) {\n throw new Error(`The page's ${apiOriginMeta} meta tag holds \"${value}\", which is not an http or https origin such as https://shop.example.com`)\n }\n return value\n}\n\n/** The API origin this page names in its `<meta name=\"protobase-api-origin\">` (see `apiOriginOf`). */\nexport const pageApiOrigin = () =>\n apiOriginOf([...document.querySelectorAll<HTMLMetaElement>(`meta[name=\"${apiOriginMeta}\"]`)].map((meta) => meta.content))\n","import { StrictMode } from 'react'\nimport { createRoot } from 'react-dom/client'\nimport * as projectUi from 'virtual:protobase-project-ui'\nimport '../styles.css'\nimport { browserLocale } from '../locale/active-locale'\nimport { App } from './app'\nimport { nativeBridgeOf, type NativeBridge } from './native-auth-fetch'\nimport { showKeyboardAccessoryBar } from './native-keyboard'\nimport { applyNativeViewport } from './native-viewport'\nimport { pageApiOrigin } from './page-api-origin'\nimport { uiFromModule } from './pages/ui-from-module'\n\nconst root = document.getElementById('root')\nif (!root) throw new Error('index.html needs an element with id \"root\"')\n\nconst nativeBridge = nativeBridgeOf(window as { Capacitor?: NativeBridge })\nif (nativeBridge) {\n applyNativeViewport(document)\n void showKeyboardAccessoryBar(nativeBridge)\n}\n\ncreateRoot(root).render(\n <StrictMode>\n <App baseUrl={`${pageApiOrigin() ?? ''}/api/v1`} ui={uiFromModule(projectUi)} locale={browserLocale()} nativeBridge={nativeBridge} />\n </StrictMode>,\n)\n"],"mappings":"85BAKauB,EAAgB,uBCEhBC,EAA2B,KAAO,IAAyB,CAClEC,EAAO,YAAY,IAAM,OAAUA,EAAO,kBAAkB,UAAU,GAC1E,MAAMA,EAAO,cAAc,WAAY,yBAA0B,CAAE,UAAW,EAAK,CAAC,CACtF,ECLaC,EAAkB,GAEtB,CAAC,GADKC,EAAQ,MAAM,GAAG,CAAC,CAAC,IAAK,GAASC,EAAK,KAAK,CAAC,CAAC,CAAC,OAAQ,GAASA,GAAQ,CAAC,qBAAqB,KAAKA,CAAI,CACxG,EAAM,iBAAiB,CAAC,CAAC,KAAK,IAAI,EAIlCC,EAAuB,GAAkB,CACpD,IAAMC,EAAOC,EAAI,cAAc,uBAAuB,EACjDD,GACLA,EAAK,aAAa,UAAWJ,EAAeI,EAAK,aAAa,SAAS,GAAK,EAAE,CAAC,CACjF,ECTaE,EAAe,GAAuB,CACjD,GAAIC,EAAS,SAAW,EAAG,OAC3B,GAAIA,EAAS,OAAS,EAAG,MAAU,MAAM,gBAAgBA,EAAS,OAAO,GAAGV,EAAc,4BAA4B,EACtH,IAAMW,EAAQD,EAAS,GACjBE,EAAM,IAAI,SAASD,CAAK,EAAI,IAAI,IAAIA,CAAK,EAAI,IAAA,GACnD,GAAI,CAACC,GAAQA,EAAI,WAAa,SAAWA,EAAI,WAAa,UAAaA,EAAI,SAAWD,EACpF,MAAU,MAAM,cAAcX,EAAc,mBAAmBW,EAAM,yEAAyE,EAEhJ,OAAOA,CACT,EAGaE,MACXJ,EAAY,CAAC,GAAG,SAAS,iBAAkC,cAAcT,EAAc,GAAG,CAAC,CAAC,CAAC,IAAK,GAASO,EAAK,OAAO,CAAC,aCPpHQ,EAAO,SAAS,eAAe,MAAM,EAC3C,GAAI,CAACA,EAAM,MAAU,MAAM,4CAA4C,EAEvE,IAAMC,EAAe9B,EAAe,MAAsC,EACtE8B,IACFV,EAAoB,QAAQ,EAC5BL,EAA8Be,CAAY,IAG5CvC,EAAAA,EAAAA,WAAAA,CAAWsC,CAAI,CAAC,CAAC,QACf,EAAAD,EAAA,IAAA,CAACpC,EAAAA,WAAD,CAAA,UACE,EAAAoC,EAAA,IAAA,CAAC3B,EAAD,CAAK,QAAS,GAAG0B,EAAc,GAAK,GAAG,SAAU,GAAI5B,EAAaN,CAAS,EAAG,OAAQsC,EAAc,EAAiB,cAAe,CAAA,CAC1H,CAAA,CACd","debugId":"10928ed5-5de2-40d2-9785-767be0f10fc0"}
@@ -1 +1 @@
1
- {"version":3,"file":"records-map-BbFggRwi.js","names":["useRef","useState","__toESM","require_react","require_jsx_runtime","cachedFormat","groupPoints","MapPin","Source","MapLayerSwitch","Marker","Layer","Map","mapLib","cn","import_react","worldPixels","mercatorLimit","fadeFrom","zooms","zoom","positionsOf","geometry","mercatorY","radians","latitude","zoomZeroSpan","positions","longitudes","longitude","ys","width","height","areaFeatures","features","points","point","kind","selected","feature","fadeIn","full","import_jsx_runtime","areaLayerId","polygons","lines","chosen","yes","no","PositionAreas","data","color","colors","themeColor","probe","token","element","resolved","canvas","context","red","green","blue","alpha","groupRadius","fitOptions","bucketOptions","markerHeight","compact","tag","corners","bounds","RecordsMap","ref","groups","setGroups","setColors","byKey","pointKeys","fitKey","fit","regroup","map","report","center","onMove","fitNow","onFitted","chosenAt","group","key","at","covered","open","y","style","initial","container","onClear","NavigationControl","buckets","bucket","bucketLabel","event","approximate","markerLabel","onSelect"],"sources":["../../../src/app/map/area-features.ts","../../../src/app/map/position-areas.tsx","../../../src/app/map/theme-color.ts","../../../src/app/map/records-map.tsx"],"sourcesContent":["import type { ExpressionSpecification } from 'maplibre-gl'\nimport type { MapPoint } from '../displays/map-groups'\nimport type { AreaGeometry } from './approximate-position'\n\n/** An area as the map's GeoJSON source holds it: whose it is, whether it is filled or a line, its size, and whether its record is chosen. */\nexport type AreaFeature = {\n type: 'Feature'\n geometry: AreaGeometry\n properties: { key: string; kind: 'polygon' | 'line'; span: number; chosen: boolean }\n}\n\n// MapLibre draws the whole world 512 pixels across at zoom 0, each zoom level twice as wide as the one before.\nconst worldPixels = 512\n// The furthest north and south Web Mercator draws.\nconst mercatorLimit = 85.051129\n// An area fades in as it grows from about half a marker to a marker and a half across, smaller it says nothing the marker does not.\nconst fadeFrom = 16\nconst fadeTo = 48\nconst zooms = Array.from({ length: 23 }, (_, zoom) => zoom)\n\nconst positionsOf = (geometry: AreaGeometry): [number, number][] => {\n if (geometry.type === 'LineString') return geometry.coordinates\n if (geometry.type === 'MultiPolygon') return geometry.coordinates.flat(2)\n return geometry.coordinates.flat()\n}\n\n// How far down the world a latitude is drawn, from 0 at the top to 1 at the bottom.\nconst mercatorY = (latitude: number) => {\n const radians = (Math.max(-mercatorLimit, Math.min(mercatorLimit, latitude)) * Math.PI) / 180\n return 0.5 - Math.log(Math.tan(Math.PI / 4 + radians / 2)) / (2 * Math.PI)\n}\n\n/** How many pixels across the area is drawn at zoom 0, the larger of its width and height; twice as many each zoom level in. */\nexport const zoomZeroSpan = (geometry: AreaGeometry) => {\n const positions = positionsOf(geometry)\n const longitudes = positions.map(([longitude]) => longitude)\n const ys = positions.map(([, latitude]) => mercatorY(latitude))\n const width = ((Math.max(...longitudes) - Math.min(...longitudes)) / 360) * worldPixels\n const height = (Math.max(...ys) - Math.min(...ys)) * worldPixels\n return Math.max(width, height)\n}\n\n/** The areas of the points that have one, those of the chosen records last so they are drawn on top. */\nexport const areaFeatures = (points: MapPoint[], selected: string[] | undefined): { type: 'FeatureCollection'; features: AreaFeature[] } => {\n const features = points.flatMap((point): AreaFeature[] => {\n if (!point.area) return []\n const kind = point.area.type === 'LineString' || point.area.type === 'MultiLineString' ? 'line' : 'polygon'\n return [{ type: 'Feature', geometry: point.area, properties: { key: point.key, kind, span: zoomZeroSpan(point.area), chosen: selected?.includes(point.key) ?? false } }]\n })\n return { type: 'FeatureCollection', features: [...features.filter((feature) => !feature.properties.chosen), ...features.filter((feature) => feature.properties.chosen)] }\n}\n\n/**\n * An opacity of `full` for an area drawn large enough to mean something at the zoom, fading in as it grows to that\n * size: at each whole zoom level its share of `full` follows from its span, and MapLibre blends between the levels.\n */\nexport const fadeIn = (full: number | ExpressionSpecification): ExpressionSpecification =>\n [\n 'interpolate',\n ['linear'],\n ['zoom'],\n ...zooms.flatMap((zoom) => [zoom, ['*', full, ['min', 1, ['max', 0, ['/', ['-', ['*', ['get', 'span'], 2 ** zoom], fadeFrom], fadeTo - fadeFrom]]]]]),\n ] as ExpressionSpecification\n","import type { ExpressionSpecification, FilterSpecification } from 'maplibre-gl'\nimport { Layer, Source } from 'react-map-gl/maplibre'\nimport type { MapPoint } from '../displays/map-groups'\nimport { areaFeatures, fadeIn } from './area-features'\n\n/** The colours of the areas, as MapLibre reads them: the markers' own, and the chosen marker's. */\nexport type AreaColors = { area: string; chosen: string }\n\n/** The areas' lowest layer, which a layer of tiles goes under. */\nexport const areaLayerId = 'position-area-fills'\n\nconst polygons: FilterSpecification = ['==', ['get', 'kind'], 'polygon']\nconst lines: FilterSpecification = ['==', ['get', 'kind'], 'line']\nconst chosen = (yes: number, no: number): ExpressionSpecification => ['case', ['get', 'chosen'], yes, no]\n\n/**\n * The areas around the approximate positions among `points`, drawn under the markers in the markers' colour: a polygon\n * filled faintly within a dashed outline, a line such as a street as a wide stroke. Each fades in as the map zooms close\n * enough for it to be larger than a marker, and the chosen records' areas are drawn darker. Nothing without areas.\n */\nexport const PositionAreas = ({ points, selected, colors }: { points: MapPoint[]; selected: string[] | undefined; colors: AreaColors }) => {\n const data = areaFeatures(points, selected)\n if (data.features.length === 0) return null\n const color: ExpressionSpecification = ['case', ['get', 'chosen'], colors.chosen, colors.area]\n return (\n <Source id=\"position-areas\" type=\"geojson\" data={data}>\n <Layer id={areaLayerId} type=\"fill\" filter={polygons} paint={{ 'fill-color': color, 'fill-opacity': fadeIn(chosen(0.15, 0.1)) }} />\n <Layer id=\"position-area-outlines\" type=\"line\" filter={polygons} paint={{ 'line-color': color, 'line-width': 1.5, 'line-dasharray': [3, 2], 'line-opacity': fadeIn(0.8) }} />\n <Layer id=\"position-area-lines\" type=\"line\" filter={lines} layout={{ 'line-cap': 'round', 'line-join': 'round' }} paint={{ 'line-color': color, 'line-width': 6, 'line-opacity': fadeIn(chosen(0.6, 0.35)) }} />\n </Source>\n )\n}\n","/**\n * The colour a theme token such as `--primary` holds where `element` is, as `rgba()`, which MapLibre's paint reads\n * whatever the theme writes it in: the browser resolves the token, and a pixel painted with it gives its channels.\n */\nexport const themeColor = (element: HTMLElement, token: string) => {\n const probe = document.createElement('span')\n probe.style.color = `var(${token})`\n element.append(probe)\n const resolved = getComputedStyle(probe).color\n probe.remove()\n const canvas = document.createElement('canvas')\n canvas.width = 1\n canvas.height = 1\n const context = canvas.getContext('2d', { willReadFrequently: true })\n if (!context) return resolved\n context.fillStyle = resolved\n context.fillRect(0, 0, 1, 1)\n const [red, green, blue, alpha] = context.getImageData(0, 0, 1, 1).data\n return `rgba(${red}, ${green}, ${blue}, ${alpha! / 255})`\n}\n","import { useEffect, useRef, useState } from 'react'\nimport { MapPin } from 'lucide-react'\nimport { Map, Marker, NavigationControl, type MapRef } from 'react-map-gl/maplibre'\nimport type { MapBounds, MapBucket, MapLayerModel } from '@protobase/client'\nimport type { MapView } from '@protobase/schema'\nimport { cn } from '../../lib/cn'\nimport { groupPoints, type MapGroup, type MapPoint } from '../displays/map-groups'\nimport type { MapArea } from './map-area'\nimport { MapLayerSwitch } from './map-layer-switch'\nimport { mapLib } from './maplibre'\nimport { areaLayerId, PositionAreas, type AreaColors } from './position-areas'\nimport { themeColor } from './theme-color'\nimport { cachedFormat } from '../../format/intl-cache'\n\n// How close, in pixels, records are drawn under one marker, about a marker's width.\nconst groupRadius = 28\nconst fitOptions = { padding: 48, maxZoom: 15, duration: 0 }\n// A bucket opens far enough in for the server to send its records: it does from zoom 16 on.\nconst bucketOptions = { padding: 48, maxZoom: 16, duration: 300 }\nconst markerHeight = 32\nconst compact = () => cachedFormat('compact', (tag) => new Intl.NumberFormat(tag, { notation: 'compact', maximumFractionDigits: 1 }))\n\nconst corners = (bounds: MapBounds): [[number, number], [number, number]] => [\n [bounds.west, bounds.south],\n [bounds.east, bounds.north],\n]\n\ntype RecordsMapProps = {\n style: string\n /** The layers the map may switch to in place of the style's. */\n layers?: MapLayerModel[]\n /** Where the map looks when it opens; the whole world without it. */\n initial: MapView | undefined\n points: MapPoint[]\n /** Counts of records in parts of the map, drawn as circles in place of their records. */\n buckets: MapBucket[]\n /** Bounds to move the map to, each time they change; `onFitted` says it moved there. */\n fit: MapBounds | undefined\n onFitted: () => void\n /** The map's area and view, each time it comes to rest. */\n onMove: (area: MapArea, view: MapView) => void\n /** The records whose marker is chosen, if any. */\n selected: string[] | undefined\n /** How many pixels at the map's bottom something covers, such as the chosen record's card. */\n covered: number\n onSelect: (keys: string[]) => void\n onClear: () => void\n /** What a marker for these records says to a screen reader. */\n markerLabel: (keys: string[]) => string\n /** What a bucket of this many records says to a screen reader. */\n bucketLabel: (count: number) => string\n}\n\n/**\n * A map of `style` with a marker for each group of records that lie close together at the zoom, showing how many it\n * stands for, and a circle with the count of each bucket, which zooms in on its records when chosen. A marker whose\n * records' positions are all approximate is drawn hollow with a dashed edge, over the areas around them. Choosing a\n * marker selects its records; choosing the map elsewhere clears the selection. A chosen marker the covered bottom would\n * hide moves up into the open part of the map.\n */\nexport const RecordsMap = ({ style, layers, initial, points, buckets, fit, onFitted, onMove, selected, covered, onSelect, onClear, markerLabel, bucketLabel }: RecordsMapProps) => {\n const ref = useRef<MapRef>(null)\n const [groups, setGroups] = useState<MapGroup[]>([])\n const [colors, setColors] = useState<AreaColors>()\n const byKey = new globalThis.Map(points.map((point) => [point.key, point]))\n const pointKeys = points.map((point) => point.key).join(',')\n const fitKey = fit && JSON.stringify(fit)\n\n // The groups as the map is drawn now: only the zoom changes which records lie close together\n const regroup = () => {\n const map = ref.current?.getMap()\n if (!map) return\n setGroups(\n groupPoints(\n points.map((point) => ({ key: point.key, ...map.project([point.longitude, point.latitude]) })),\n groupRadius,\n ),\n )\n }\n\n const report = () => {\n const map = ref.current?.getMap()\n if (!map) return\n const bounds = map.getBounds()\n const center = map.getCenter()\n onMove({ bounds: { south: bounds.getSouth(), west: bounds.getWest(), north: bounds.getNorth(), east: bounds.getEast() }, zoom: map.getZoom() }, { latitude: center.lat, longitude: center.lng, zoom: map.getZoom() })\n }\n\n const fitNow = () => {\n const map = ref.current?.getMap()\n if (!map || !fit) return\n map.fitBounds(corners(fit), fitOptions)\n onFitted()\n report()\n }\n\n // Other records are grouped at the zoom the map is at\n useEffect(regroup, [pointKeys])\n useEffect(fitNow, [fitKey])\n\n // The chosen marker in view above what covers the map's bottom\n const chosenAt = groups.find((group) => selected !== undefined && group.keys.some((key) => selected.includes(key)))?.at\n useEffect(() => {\n const map = ref.current?.getMap()\n const at = chosenAt === undefined ? undefined : byKey.get(chosenAt)\n if (!map || !at || covered === 0) return\n const { y } = map.project([at.longitude, at.latitude])\n const open = map.getContainer().clientHeight - covered\n if (y > markerHeight && y < open) return\n map.easeTo({ center: [at.longitude, at.latitude], offset: [0, (markerHeight - covered) / 2], duration: 300 })\n // A new choice or a new cover moves the map, not every new group\n }, [chosenAt, covered])\n\n return (\n <Map\n ref={ref}\n mapLib={mapLib}\n mapStyle={style}\n initialViewState={initial ?? { latitude: 0, longitude: 0, zoom: 1 }}\n style={{ width: '100%', height: '100%' }}\n onLoad={() => {\n const container = ref.current!.getMap().getContainer()\n setColors({ area: themeColor(container, '--primary'), chosen: themeColor(container, '--foreground') })\n regroup()\n if (fit) fitNow()\n else report()\n }}\n onZoomEnd={regroup}\n onMoveEnd={report}\n onClick={onClear}\n >\n <NavigationControl showCompass={false} />\n <MapLayerSwitch layers={layers} below={areaLayerId} />\n {colors && <PositionAreas points={points} selected={selected} colors={colors} />}\n {buckets.map((bucket) => (\n <Marker key={`${bucket.latitude},${bucket.longitude}`} latitude={bucket.latitude} longitude={bucket.longitude} anchor=\"center\">\n <button\n type=\"button\"\n aria-label={bucketLabel(bucket.count)}\n className=\"flex size-10 cursor-pointer items-center justify-center rounded-full border-2 border-background bg-primary text-xs font-semibold text-primary-foreground tabular-nums shadow\"\n onClick={(event) => {\n event.stopPropagation()\n ref.current?.getMap().fitBounds(corners(bucket.bounds), bucketOptions)\n }}\n >\n {compact().format(bucket.count)}\n </button>\n </Marker>\n ))}\n {groups.map((group) => {\n const at = byKey.get(group.at)\n if (!at) return null\n const chosen = selected !== undefined && group.keys.some((key) => selected.includes(key))\n const approximate = group.keys.every((key) => byKey.get(key)?.approximate)\n return (\n <Marker key={group.at} latitude={at.latitude} longitude={at.longitude} anchor=\"bottom\" style={{ zIndex: chosen ? 1 : 0 }}>\n <button\n type=\"button\"\n aria-label={markerLabel(group.keys)}\n aria-pressed={chosen}\n className=\"relative block cursor-pointer\"\n onClick={(event) => {\n event.stopPropagation()\n onSelect(group.keys)\n }}\n >\n <MapPin\n aria-hidden\n data-approximate={approximate || undefined}\n className={cn('size-8 drop-shadow', approximate ? (chosen ? 'fill-background text-foreground' : 'fill-background text-primary') : chosen ? 'fill-foreground text-background' : 'fill-primary text-primary-foreground')}\n strokeWidth={approximate ? 2 : 1.5}\n strokeDasharray={approximate ? '3 2' : undefined}\n />\n {group.keys.length > 1 && (\n <span className=\"absolute -right-2 -top-1 min-w-5 rounded-full border border-background bg-foreground px-1 text-center text-[11px] font-medium leading-4 text-background tabular-nums\">\n {group.keys.length}\n </span>\n )}\n </button>\n </Marker>\n )\n })}\n </Map>\n )\n}\n"],"mappings":"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","debugId":"5b160811-c22f-46bd-9123-4b44bd488ae9"}
1
+ {"version":3,"file":"records-map-DMtWYUIm.js","names":["useRef","useState","__toESM","require_react","require_jsx_runtime","groupPoints","cachedFormat","MapPin","Source","MapLayerSwitch","Marker","Layer","Map","mapLib","cn","import_react","worldPixels","mercatorLimit","fadeFrom","zooms","zoom","positionsOf","geometry","mercatorY","radians","latitude","zoomZeroSpan","positions","longitudes","longitude","ys","width","height","areaFeatures","features","points","point","kind","selected","feature","fadeIn","full","import_jsx_runtime","areaLayerId","polygons","lines","chosen","yes","no","PositionAreas","data","color","colors","themeColor","probe","token","element","resolved","canvas","context","red","green","blue","alpha","groupRadius","fitOptions","bucketOptions","markerHeight","compact","tag","corners","bounds","RecordsMap","ref","groups","setGroups","setColors","byKey","pointKeys","fitKey","fit","regroup","map","report","center","onMove","fitNow","onFitted","chosenAt","group","key","at","covered","open","y","style","initial","container","onClear","NavigationControl","buckets","bucket","bucketLabel","event","approximate","markerLabel","onSelect"],"sources":["../../../src/app/map/area-features.ts","../../../src/app/map/position-areas.tsx","../../../src/app/map/theme-color.ts","../../../src/app/map/records-map.tsx"],"sourcesContent":["import type { ExpressionSpecification } from 'maplibre-gl'\nimport type { MapPoint } from '../displays/map-groups'\nimport type { AreaGeometry } from './approximate-position'\n\n/** An area as the map's GeoJSON source holds it: whose it is, whether it is filled or a line, its size, and whether its record is chosen. */\nexport type AreaFeature = {\n type: 'Feature'\n geometry: AreaGeometry\n properties: { key: string; kind: 'polygon' | 'line'; span: number; chosen: boolean }\n}\n\n// MapLibre draws the whole world 512 pixels across at zoom 0, each zoom level twice as wide as the one before.\nconst worldPixels = 512\n// The furthest north and south Web Mercator draws.\nconst mercatorLimit = 85.051129\n// An area fades in as it grows from about half a marker to a marker and a half across, smaller it says nothing the marker does not.\nconst fadeFrom = 16\nconst fadeTo = 48\nconst zooms = Array.from({ length: 23 }, (_, zoom) => zoom)\n\nconst positionsOf = (geometry: AreaGeometry): [number, number][] => {\n if (geometry.type === 'LineString') return geometry.coordinates\n if (geometry.type === 'MultiPolygon') return geometry.coordinates.flat(2)\n return geometry.coordinates.flat()\n}\n\n// How far down the world a latitude is drawn, from 0 at the top to 1 at the bottom.\nconst mercatorY = (latitude: number) => {\n const radians = (Math.max(-mercatorLimit, Math.min(mercatorLimit, latitude)) * Math.PI) / 180\n return 0.5 - Math.log(Math.tan(Math.PI / 4 + radians / 2)) / (2 * Math.PI)\n}\n\n/** How many pixels across the area is drawn at zoom 0, the larger of its width and height; twice as many each zoom level in. */\nexport const zoomZeroSpan = (geometry: AreaGeometry) => {\n const positions = positionsOf(geometry)\n const longitudes = positions.map(([longitude]) => longitude)\n const ys = positions.map(([, latitude]) => mercatorY(latitude))\n const width = ((Math.max(...longitudes) - Math.min(...longitudes)) / 360) * worldPixels\n const height = (Math.max(...ys) - Math.min(...ys)) * worldPixels\n return Math.max(width, height)\n}\n\n/** The areas of the points that have one, those of the chosen records last so they are drawn on top. */\nexport const areaFeatures = (points: MapPoint[], selected: string[] | undefined): { type: 'FeatureCollection'; features: AreaFeature[] } => {\n const features = points.flatMap((point): AreaFeature[] => {\n if (!point.area) return []\n const kind = point.area.type === 'LineString' || point.area.type === 'MultiLineString' ? 'line' : 'polygon'\n return [{ type: 'Feature', geometry: point.area, properties: { key: point.key, kind, span: zoomZeroSpan(point.area), chosen: selected?.includes(point.key) ?? false } }]\n })\n return { type: 'FeatureCollection', features: [...features.filter((feature) => !feature.properties.chosen), ...features.filter((feature) => feature.properties.chosen)] }\n}\n\n/**\n * An opacity of `full` for an area drawn large enough to mean something at the zoom, fading in as it grows to that\n * size: at each whole zoom level its share of `full` follows from its span, and MapLibre blends between the levels.\n */\nexport const fadeIn = (full: number | ExpressionSpecification): ExpressionSpecification =>\n [\n 'interpolate',\n ['linear'],\n ['zoom'],\n ...zooms.flatMap((zoom) => [zoom, ['*', full, ['min', 1, ['max', 0, ['/', ['-', ['*', ['get', 'span'], 2 ** zoom], fadeFrom], fadeTo - fadeFrom]]]]]),\n ] as ExpressionSpecification\n","import type { ExpressionSpecification, FilterSpecification } from 'maplibre-gl'\nimport { Layer, Source } from 'react-map-gl/maplibre'\nimport type { MapPoint } from '../displays/map-groups'\nimport { areaFeatures, fadeIn } from './area-features'\n\n/** The colours of the areas, as MapLibre reads them: the markers' own, and the chosen marker's. */\nexport type AreaColors = { area: string; chosen: string }\n\n/** The areas' lowest layer, which a layer of tiles goes under. */\nexport const areaLayerId = 'position-area-fills'\n\nconst polygons: FilterSpecification = ['==', ['get', 'kind'], 'polygon']\nconst lines: FilterSpecification = ['==', ['get', 'kind'], 'line']\nconst chosen = (yes: number, no: number): ExpressionSpecification => ['case', ['get', 'chosen'], yes, no]\n\n/**\n * The areas around the approximate positions among `points`, drawn under the markers in the markers' colour: a polygon\n * filled faintly within a dashed outline, a line such as a street as a wide stroke. Each fades in as the map zooms close\n * enough for it to be larger than a marker, and the chosen records' areas are drawn darker. Nothing without areas.\n */\nexport const PositionAreas = ({ points, selected, colors }: { points: MapPoint[]; selected: string[] | undefined; colors: AreaColors }) => {\n const data = areaFeatures(points, selected)\n if (data.features.length === 0) return null\n const color: ExpressionSpecification = ['case', ['get', 'chosen'], colors.chosen, colors.area]\n return (\n <Source id=\"position-areas\" type=\"geojson\" data={data}>\n <Layer id={areaLayerId} type=\"fill\" filter={polygons} paint={{ 'fill-color': color, 'fill-opacity': fadeIn(chosen(0.15, 0.1)) }} />\n <Layer id=\"position-area-outlines\" type=\"line\" filter={polygons} paint={{ 'line-color': color, 'line-width': 1.5, 'line-dasharray': [3, 2], 'line-opacity': fadeIn(0.8) }} />\n <Layer id=\"position-area-lines\" type=\"line\" filter={lines} layout={{ 'line-cap': 'round', 'line-join': 'round' }} paint={{ 'line-color': color, 'line-width': 6, 'line-opacity': fadeIn(chosen(0.6, 0.35)) }} />\n </Source>\n )\n}\n","/**\n * The colour a theme token such as `--primary` holds where `element` is, as `rgba()`, which MapLibre's paint reads\n * whatever the theme writes it in: the browser resolves the token, and a pixel painted with it gives its channels.\n */\nexport const themeColor = (element: HTMLElement, token: string) => {\n const probe = document.createElement('span')\n probe.style.color = `var(${token})`\n element.append(probe)\n const resolved = getComputedStyle(probe).color\n probe.remove()\n const canvas = document.createElement('canvas')\n canvas.width = 1\n canvas.height = 1\n const context = canvas.getContext('2d', { willReadFrequently: true })\n if (!context) return resolved\n context.fillStyle = resolved\n context.fillRect(0, 0, 1, 1)\n const [red, green, blue, alpha] = context.getImageData(0, 0, 1, 1).data\n return `rgba(${red}, ${green}, ${blue}, ${alpha! / 255})`\n}\n","import { useEffect, useRef, useState } from 'react'\nimport { MapPin } from 'lucide-react'\nimport { Map, Marker, NavigationControl, type MapRef } from 'react-map-gl/maplibre'\nimport type { MapBounds, MapBucket, MapLayerModel } from '@protobase/client'\nimport type { MapView } from '@protobase/schema'\nimport { cn } from '../../lib/cn'\nimport { groupPoints, type MapGroup, type MapPoint } from '../displays/map-groups'\nimport type { MapArea } from './map-area'\nimport { MapLayerSwitch } from './map-layer-switch'\nimport { mapLib } from './maplibre'\nimport { areaLayerId, PositionAreas, type AreaColors } from './position-areas'\nimport { themeColor } from './theme-color'\nimport { cachedFormat } from '../../format/intl-cache'\n\n// How close, in pixels, records are drawn under one marker, about a marker's width.\nconst groupRadius = 28\nconst fitOptions = { padding: 48, maxZoom: 15, duration: 0 }\n// A bucket opens far enough in for the server to send its records: it does from zoom 16 on.\nconst bucketOptions = { padding: 48, maxZoom: 16, duration: 300 }\nconst markerHeight = 32\nconst compact = () => cachedFormat('compact', (tag) => new Intl.NumberFormat(tag, { notation: 'compact', maximumFractionDigits: 1 }))\n\nconst corners = (bounds: MapBounds): [[number, number], [number, number]] => [\n [bounds.west, bounds.south],\n [bounds.east, bounds.north],\n]\n\ntype RecordsMapProps = {\n style: string\n /** The layers the map may switch to in place of the style's. */\n layers?: MapLayerModel[]\n /** Where the map looks when it opens; the whole world without it. */\n initial: MapView | undefined\n points: MapPoint[]\n /** Counts of records in parts of the map, drawn as circles in place of their records. */\n buckets: MapBucket[]\n /** Bounds to move the map to, each time they change; `onFitted` says it moved there. */\n fit: MapBounds | undefined\n onFitted: () => void\n /** The map's area and view, each time it comes to rest. */\n onMove: (area: MapArea, view: MapView) => void\n /** The records whose marker is chosen, if any. */\n selected: string[] | undefined\n /** How many pixels at the map's bottom something covers, such as the chosen record's card. */\n covered: number\n onSelect: (keys: string[]) => void\n onClear: () => void\n /** What a marker for these records says to a screen reader. */\n markerLabel: (keys: string[]) => string\n /** What a bucket of this many records says to a screen reader. */\n bucketLabel: (count: number) => string\n}\n\n/**\n * A map of `style` with a marker for each group of records that lie close together at the zoom, showing how many it\n * stands for, and a circle with the count of each bucket, which zooms in on its records when chosen. A marker whose\n * records' positions are all approximate is drawn hollow with a dashed edge, over the areas around them. Choosing a\n * marker selects its records; choosing the map elsewhere clears the selection. A chosen marker the covered bottom would\n * hide moves up into the open part of the map.\n */\nexport const RecordsMap = ({ style, layers, initial, points, buckets, fit, onFitted, onMove, selected, covered, onSelect, onClear, markerLabel, bucketLabel }: RecordsMapProps) => {\n const ref = useRef<MapRef>(null)\n const [groups, setGroups] = useState<MapGroup[]>([])\n const [colors, setColors] = useState<AreaColors>()\n const byKey = new globalThis.Map(points.map((point) => [point.key, point]))\n const pointKeys = points.map((point) => point.key).join(',')\n const fitKey = fit && JSON.stringify(fit)\n\n // The groups as the map is drawn now: only the zoom changes which records lie close together\n const regroup = () => {\n const map = ref.current?.getMap()\n if (!map) return\n setGroups(\n groupPoints(\n points.map((point) => ({ key: point.key, ...map.project([point.longitude, point.latitude]) })),\n groupRadius,\n ),\n )\n }\n\n const report = () => {\n const map = ref.current?.getMap()\n if (!map) return\n const bounds = map.getBounds()\n const center = map.getCenter()\n onMove({ bounds: { south: bounds.getSouth(), west: bounds.getWest(), north: bounds.getNorth(), east: bounds.getEast() }, zoom: map.getZoom() }, { latitude: center.lat, longitude: center.lng, zoom: map.getZoom() })\n }\n\n const fitNow = () => {\n const map = ref.current?.getMap()\n if (!map || !fit) return\n map.fitBounds(corners(fit), fitOptions)\n onFitted()\n report()\n }\n\n // Other records are grouped at the zoom the map is at\n useEffect(regroup, [pointKeys])\n useEffect(fitNow, [fitKey])\n\n // The chosen marker in view above what covers the map's bottom\n const chosenAt = groups.find((group) => selected !== undefined && group.keys.some((key) => selected.includes(key)))?.at\n useEffect(() => {\n const map = ref.current?.getMap()\n const at = chosenAt === undefined ? undefined : byKey.get(chosenAt)\n if (!map || !at || covered === 0) return\n const { y } = map.project([at.longitude, at.latitude])\n const open = map.getContainer().clientHeight - covered\n if (y > markerHeight && y < open) return\n map.easeTo({ center: [at.longitude, at.latitude], offset: [0, (markerHeight - covered) / 2], duration: 300 })\n // A new choice or a new cover moves the map, not every new group\n }, [chosenAt, covered])\n\n return (\n <Map\n ref={ref}\n mapLib={mapLib}\n mapStyle={style}\n initialViewState={initial ?? { latitude: 0, longitude: 0, zoom: 1 }}\n style={{ width: '100%', height: '100%' }}\n onLoad={() => {\n const container = ref.current!.getMap().getContainer()\n setColors({ area: themeColor(container, '--primary'), chosen: themeColor(container, '--foreground') })\n regroup()\n if (fit) fitNow()\n else report()\n }}\n onZoomEnd={regroup}\n onMoveEnd={report}\n onClick={onClear}\n >\n <NavigationControl showCompass={false} />\n <MapLayerSwitch layers={layers} below={areaLayerId} />\n {colors && <PositionAreas points={points} selected={selected} colors={colors} />}\n {buckets.map((bucket) => (\n <Marker key={`${bucket.latitude},${bucket.longitude}`} latitude={bucket.latitude} longitude={bucket.longitude} anchor=\"center\">\n <button\n type=\"button\"\n aria-label={bucketLabel(bucket.count)}\n className=\"flex size-10 cursor-pointer items-center justify-center rounded-full border-2 border-background bg-primary text-xs font-semibold text-primary-foreground tabular-nums shadow\"\n onClick={(event) => {\n event.stopPropagation()\n ref.current?.getMap().fitBounds(corners(bucket.bounds), bucketOptions)\n }}\n >\n {compact().format(bucket.count)}\n </button>\n </Marker>\n ))}\n {groups.map((group) => {\n const at = byKey.get(group.at)\n if (!at) return null\n const chosen = selected !== undefined && group.keys.some((key) => selected.includes(key))\n const approximate = group.keys.every((key) => byKey.get(key)?.approximate)\n return (\n <Marker key={group.at} latitude={at.latitude} longitude={at.longitude} anchor=\"bottom\" style={{ zIndex: chosen ? 1 : 0 }}>\n <button\n type=\"button\"\n aria-label={markerLabel(group.keys)}\n aria-pressed={chosen}\n className=\"relative block cursor-pointer\"\n onClick={(event) => {\n event.stopPropagation()\n onSelect(group.keys)\n }}\n >\n <MapPin\n aria-hidden\n data-approximate={approximate || undefined}\n className={cn('size-8 drop-shadow', approximate ? (chosen ? 'fill-background text-foreground' : 'fill-background text-primary') : chosen ? 'fill-foreground text-background' : 'fill-primary text-primary-foreground')}\n strokeWidth={approximate ? 2 : 1.5}\n strokeDasharray={approximate ? '3 2' : undefined}\n />\n {group.keys.length > 1 && (\n <span className=\"absolute -right-2 -top-1 min-w-5 rounded-full border border-background bg-foreground px-1 text-center text-[11px] font-medium leading-4 text-background tabular-nums\">\n {group.keys.length}\n </span>\n )}\n </button>\n </Marker>\n )\n })}\n </Map>\n )\n}\n"],"mappings":"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","debugId":"ccb56614-2268-42ba-8777-404f89a2080f"}
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shared-protobase-ui-DJI957cu.js","names":["useMemo","useState","__toESM","require_react","require_jsx_runtime","keepPreviousData","useQuery","useQueryClient","AvailabilityMark","text","viewerZone","allowDelayMs","useClient","Composer","shownImage","mentionedIds","useFieldControl","emptyDraft","Input","usePlugin","buttonClass","MenuSelect","useArmedAfterFocus","keys","mergeUi","useAdminMeta","useOptionalListDisplay","uiFromModule","Spinner","useApiToken","ResponsiveDialog","pluginApi","Dialog","ChatThread","formatWeekdayDate","protobaseVersion","Button","SignInPrompt","CodeForm","useMeta","SidePanel","useAppAddress","MentionBox","Field","useGuardedPress","useOptionalAuth","isFramed","useResourceClient","AuthLayout","CarouselTrack","useCarousel","CarouselControls","diffStats","useOwnStatus","useMarkNotificationsRead","useSeries","FieldList","Textarea","usePresence","Markdown","useAssistant","OtpInput","StatusMark","AssistantDock","RelationPicker","DiffView","statusRefreshMs","StepList","useMembers","useInbox","useHistogram","useRecord","ChatMessage","dayIn","Form","Token","PartView","defineUi","isConflict","fetchLabels","useUnreadNotifications","useLayoutRecord","useBackendData","definePlugin","useListDisplay","useUpdateRecord","useFacets","usePushNotifications","ActionInputError","App","LogoMark","useAssistantClient","FileImage","parseDiff","useStatuses","MentionedText","Section","ActionCard","AppLink","CompactTable","useList","ResendCodeButton","ApiProvider","Segmented","cn","dayBefore","day","sameChatDay","a","zone","b","chatDayLabel","time","today","now","import_jsx_runtime","ChatDivider","shown","label","line","tone","RecordLink","rest","display","around","name","resource","row","recordKey","import_react","signedInUserOf","state","useSignedInUser","box","carouselSlides","images","image","Carousel","slides","carousel","className","fit","Choices","options","option","value","onChange","usePickedLabels","client","queryClient","sorted","ids","target","view","RecordPicker","resources","props","views","known","setKnown","fetched","labelOf","key","remember","current","chosen"],"sources":["../../../src/chat/chat-day.ts","../../../src/chat/chat-divider.tsx","../../../src/app/displays/record-link.tsx","../../../src/auth/use-signed-in-user.ts","../../../src/carousel/carousel-images.ts","../../../src/carousel/carousel.tsx","../../../src/primitives/choices.tsx","../../../src/app/use-picked-labels.ts","../../../src/app/record-picker.tsx"],"sourcesContent":["import { formatWeekdayDate } from '../format/date'\nimport { dayIn, viewerZone } from '../format/zone'\nimport { text } from './messages'\n\nconst dayBefore = (day: string) => new Date(Date.parse(`${day}T00:00:00Z`) - 86_400_000).toISOString().slice(0, 10)\n\n/** Whether two ISO timestamps fall on the same day in `zone`, the viewer's unless given: a day divider goes between two messages that do not. */\nexport const sameChatDay = (a: string, b: string, zone = viewerZone()) => dayIn(Date.parse(a), zone) === dayIn(Date.parse(b), zone)\n\n/** The label of the divider above a day's first message, sent at `time`: \"Today\", \"Yesterday\" or \"Mon, 26 Oct 2026\", as the viewer's calendar in `zone` has it. */\nexport const chatDayLabel = (time: string, now = Date.now(), zone = viewerZone()) => {\n const day = dayIn(Date.parse(time), zone)\n const today = dayIn(now, zone)\n if (day === today) return text('today')\n if (day === dayBefore(today)) return text('yesterday')\n return formatWeekdayDate(Date.parse(`${day}T00:00:00Z`))\n}\n","import { cn } from '../lib/cn'\nimport { text } from './messages'\n\nexport type ChatDividerProps =\n /** A muted line between the messages of two days, labelled with the later one, such as by `chatDayLabel`. */\n | { tone?: 'day'; label: string }\n /** A line above the first message the reader has not seen, \"New messages\" unless labelled otherwise. */\n | { tone: 'new'; label?: string }\n\n/**\n * A line across a chat with a label in its middle, between the messages of two days or above the new ones. Marked\n * `data-chat-divider`, so a thread keeps the reader's place on the message below it, not on the divider.\n */\nexport const ChatDivider = ({ tone = 'day', label }: ChatDividerProps) => {\n const shown = label ?? text('newMessages')\n const line = cn('h-px flex-1', tone === 'new' ? 'bg-danger' : 'bg-border')\n return (\n <div role=\"separator\" aria-label={shown} data-tone={tone} data-chat-divider=\"\" className=\"flex items-center gap-3 text-xs font-medium\">\n <span className={line} />\n <span className={tone === 'new' ? 'text-danger' : 'text-muted-foreground'}>{shown}</span>\n <span className={line} />\n </div>\n )\n}\n","import type { AnchorHTMLAttributes } from 'react'\nimport type { KeyValue } from '@protobase/schema'\nimport { useLayoutRecord } from '../pages/record-scope'\nimport { AppLink } from '../use-app-address'\nimport { useOptionalListDisplay } from './display-context'\nimport type { ListDisplayRow } from './list-displays'\n\ntype Target = { row: ListDisplayRow; resource?: never; recordKey?: never } | { row?: never; resource?: string; recordKey: KeyValue | readonly KeyValue[] }\n\n/**\n * A link to a record's page, through the app's addresses: a list display's `row`, or a `recordKey` of `resource`. The\n * resource defaults to the list display's or the record's around it, so a custom component never writes a path.\n */\nexport const RecordLink = ({ row, resource, recordKey, ...rest }: AnchorHTMLAttributes<HTMLAnchorElement> & Target) => {\n const display = useOptionalListDisplay()\n const around = useLayoutRecord()\n const name = resource ?? display?.resource ?? around?.model.name\n if (name === undefined) throw new Error('RecordLink needs a resource outside a list display or a record')\n return <AppLink to={{ kind: 'record', resource: name, key: row ? row.key : recordKey }} {...rest} />\n}\n","import { useMemo } from 'react'\nimport { useOptionalAuth, type AuthState } from './auth-provider'\n\n/** Who is signed in: their user id, the id `.author()` stores and mentions hold, and their name. */\nexport type SignedInUser = { id: string; name?: string }\n\n/** The signed-in person of an auth state; none while it loads, for a visitor, and before the sign-in finished. */\nexport const signedInUserOf = (state: AuthState | undefined): SignedInUser | undefined => {\n if (state?.kind !== 'signed-in') return\n const { id, name } = state.user\n return { id, ...(name && { name }) }\n}\n\n/**\n * The signed-in person, from the session the app already holds, such as for a filter on their own user id;\n * `undefined` while the session loads, for a visitor and when nobody is signed in.\n */\nexport const useSignedInUser = (): SignedInUser | undefined => {\n const state = useOptionalAuth()?.state\n return useMemo(() => signedInUserOf(state), [state])\n}\n","import type { StoredFile } from '@protobase/client'\nimport { shownImage } from '../live/file-values'\n\n/** An image a carousel shows: a link with what it shows, or a file field's value, as records carry it. */\nexport type CarouselImage = { src: string; alt: string } | (StoredFile & { alt?: string })\n\n// A frame up to about half a page wide: of a file's variants, the smallest that covers it is drawn, the file itself when none does\nconst box = { width: 640, height: 480 }\n\n/** What each slide draws, in order: a file that is missing or is no raster image is left out. */\nexport const carouselSlides = (images: readonly CarouselImage[]) =>\n images.flatMap((image) => {\n if ('src' in image) return [{ image: { url: image.src }, alt: image.alt }]\n const shown = shownImage(image, box)\n return shown ? [{ image: shown, alt: image.alt ?? '' }] : []\n })\n","import { cn } from '../lib/cn'\nimport { FileImage } from '../live/file-image'\nimport { CarouselControls } from './carousel-controls'\nimport { carouselSlides, type CarouselImage } from './carousel-images'\nimport { CarouselTrack } from './carousel-track'\nimport { useCarousel } from './use-carousel'\n\nexport type CarouselProps = {\n /** The images in order: links with what each shows, or file field values. */\n images: readonly CarouselImage[]\n /** What the images are, read out with the carousel. */\n label?: string\n /** `cover` fills the frame and crops what overflows it, the default; `contain` shows each image whole. */\n fit?: 'cover' | 'contain'\n /** Whether a swipe steps through the images; off, it scrolls what the carousel sits in, such as a row that scrolls sideways. */\n swipe?: boolean\n /** The frame's classes, such as its aspect ratio, border and rounding. */\n className?: string\n}\n\n/**\n * Images side by side in a frame that snaps image by image, swiped on a touch screen or moved by arrows on hover, with\n * dots marking the one in view; the record cards' photos step the same way. A single image shows without arrows or dots.\n */\nexport const Carousel = ({ images, label, fit = 'cover', swipe = true, className }: CarouselProps) => {\n const slides = carouselSlides(images)\n const carousel = useCarousel(slides.length)\n return (\n <div role=\"group\" aria-roledescription=\"carousel\" aria-label={label} className={cn('group/carousel relative overflow-hidden', className)}>\n <CarouselTrack\n data-carousel-track\n carousel={carousel}\n swipe={swipe}\n slides={slides.map(({ image, alt }) => (\n <FileImage image={image} alt={alt} loading=\"lazy\" className={cn('size-full', fit === 'cover' ? 'object-cover' : 'object-contain')} />\n ))}\n />\n <CarouselControls carousel={carousel} count={slides.length} swipe={swipe} reveal=\"group-hover/carousel:opacity-100\" className=\"inset-0\" />\n </div>\n )\n}\n","import type { ReactNode } from 'react'\nimport { cn } from '../lib/cn'\n\nexport type ChoiceOption<T extends string> = { value: T; label: string; description?: ReactNode; disabled?: boolean }\n\n/**\n * `name` groups the radio buttons, so that the arrow keys move between them; `label` names the group for screen\n * readers. A disabled option shows and cannot be chosen.\n */\nexport type ChoicesProps<T extends string> = { name: string; label?: string; options: Array<ChoiceOption<T>>; value: T | undefined; onChange: (value: T) => void }\n\n/** One of a few options, each a card of its own row with a line that says what it means; the chosen one is outlined. */\nexport const Choices = <T extends string>({ name, label, options, value, onChange }: ChoicesProps<T>) => (\n <div role=\"radiogroup\" aria-label={label} className=\"flex flex-col gap-2\">\n {options.map((option) => (\n <label\n key={option.value}\n className={cn(\n 'block rounded-lg border p-3 transition-colors has-[:focus-visible]:outline-2 has-[:focus-visible]:outline-offset-2 has-[:focus-visible]:outline-primary',\n option.disabled ? 'cursor-default bg-background opacity-60' : option.value === value ? 'cursor-pointer border-primary bg-primary-soft' : 'cursor-pointer bg-background hover:bg-surface',\n )}\n >\n <input type=\"radio\" name={name} value={option.value} checked={option.value === value} disabled={option.disabled} onChange={() => onChange(option.value)} className=\"sr-only\" />\n <span className={cn('block font-medium', option.value === value && 'text-primary-text')}>{option.label}</span>\n {option.description && <span className=\"mt-0.5 block text-xs leading-snug text-muted-foreground\">{option.description}</span>}\n </label>\n ))}\n </div>\n)\n","import { keepPreviousData, useQuery, useQueryClient } from '@tanstack/react-query'\nimport type { ResourceModel, ViewModel } from '@protobase/schema'\nimport { useClient } from '../data/api-provider'\nimport { keys } from '../data/query-keys'\nimport { fetchLabels, type Labels } from '../live/relation-labels'\n\n/** The names of the chosen records, fetched in one list call; the previous names stay while the next ones load. */\nexport const usePickedLabels = (target: ResourceModel, view: ViewModel | undefined, ids: string[]): Labels => {\n const client = useClient()\n const queryClient = useQueryClient()\n const sorted = [...new Set(ids)].sort()\n const labels = useQuery({\n queryKey: keys.pickedLabels(target.name, sorted.join(',')),\n enabled: sorted.length > 0,\n placeholderData: keepPreviousData,\n queryFn: () => fetchLabels(queryClient, client, target, sorted, view),\n })\n return labels.data ?? new Map()\n}\n","import { useState } from 'react'\nimport { Token } from '../primitives/token'\nimport { useAdminMeta } from './meta-gate'\nimport { RelationPicker } from './relation-picker'\nimport { usePickedLabels } from './use-picked-labels'\n\ntype One = {\n multiple?: false\n /** The chosen record's key, as text; `undefined` for none. */\n value: string | undefined\n onChange: (key: string) => void\n}\n\ntype Several = {\n multiple: true\n /** The chosen records' keys, as text. */\n value: string[]\n onChange: (keys: string[]) => void\n}\n\nexport type RecordPickerProps = (One | Several) & {\n /** The name of the resource whose records it picks. */\n resource: string\n invalid?: boolean\n}\n\n/**\n * Picks records of a resource of the app with the create form's relation picker: type to narrow them by their search\n * fields or title, scroll for more, choose with the mouse or the keyboard. With `multiple`, each choice is added as a\n * token that can be taken off again, and choosing a chosen record takes it off.\n */\nexport const RecordPicker = (props: RecordPickerProps) => {\n const { resources, views } = useAdminMeta()\n const target = resources[props.resource]\n if (!target) throw new Error(`RecordPicker: the app has no resource named \"${props.resource}\"`)\n if (target.primaryKey.length !== 1) throw new Error(`RecordPicker: \"${props.resource}\" has a composite key, which a picker cannot name`)\n const view = views[props.resource]\n const keys = props.multiple ? props.value : props.value === undefined ? [] : [props.value]\n // The names of records chosen here, so a choice shows its name before the names are fetched.\n const [known, setKnown] = useState<Record<string, string>>({})\n const fetched = usePickedLabels(target, view, keys)\n const labelOf = (key: string) => known[key] ?? fetched.get(key) ?? key\n const remember = (key: string, label: string) => setKnown((current) => ({ ...current, [key]: label }))\n\n if (!props.multiple) {\n const { value, onChange } = props\n return (\n <RelationPicker\n target={target}\n view={view}\n value={value ?? ''}\n label={value === undefined ? undefined : labelOf(value)}\n invalid={props.invalid}\n onChange={(key, label) => {\n remember(key, label)\n onChange(key)\n }}\n />\n )\n }\n\n const { value, onChange } = props\n return (\n <div className=\"flex flex-col gap-2\">\n <RelationPicker\n target={target}\n view={view}\n value=\"\"\n chosen={value}\n several\n invalid={props.invalid}\n onChange={(key, label) => {\n remember(key, label)\n onChange(value.includes(key) ? value.filter((chosen) => chosen !== key) : [...value, key])\n }}\n />\n {value.length > 0 && (\n <div className=\"flex flex-wrap gap-1\">\n {value.map((key) => (\n <Token key={key} label={labelOf(key)} onRemove={() => onChange(value.filter((chosen) => chosen !== key))} />\n ))}\n </div>\n )}\n </div>\n )\n}\n"],"mappings":"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","debugId":"c923de7b-72e3-4685-b5ff-c27abe3a1c42"}
@@ -25,7 +25,9 @@ const text = defineMessages({
25
25
  cancel: "Cancel",
26
26
  clear: "Clear status",
27
27
  couldNotSave: "Could not save your status",
28
- until: (time) => `Until ${time}`
28
+ until: (time) => `Until ${time}`,
29
+ online: "Online",
30
+ away: "Away"
29
31
  },
30
32
  nl: {
31
33
  setStatus: "Status instellen",
@@ -51,7 +53,9 @@ const text = defineMessages({
51
53
  cancel: "Annuleren",
52
54
  clear: "Status wissen",
53
55
  couldNotSave: "Je status kon niet worden opgeslagen",
54
- until: (time) => `Tot ${time}`
56
+ until: (time) => `Tot ${time}`,
57
+ online: "Online",
58
+ away: "Afwezig"
55
59
  }
56
60
  });
57
61
  //#endregion
@@ -1,11 +1,11 @@
1
- import { ReactNode } from "react";
1
+ import { Presence } from "../presence/presence.js";
2
2
  import { PersonStatus } from "@protobase/schema/internal";
3
3
  //#region src/status/status-mark.d.ts
4
4
  export type StatusMarkProps = {
5
5
  /** The person's status, as `useMembers()` or `client.status` gives it; nothing shows once its clear time has passed. */
6
6
  status?: Pick<PersonStatus, 'availability' | 'text' | 'clearsAt'> | null | undefined;
7
- /** The app's own mark, such as its online or away dot from its presence, drawn first. */
8
- presence?: ReactNode;
7
+ /** Whether the person is online or away, from the app's presence (see `usePresence`), drawn first as a dot; none without. */
8
+ presence?: Presence | null | undefined;
9
9
  /** The custom text in `full`, or only on `hover` of the mark, as a tooltip; default `full`. */
10
10
  textShown?: 'full' | 'hover';
11
11
  className?: string;
@@ -16,7 +16,7 @@ export declare const AvailabilityMark: ({ availability, title }: {
16
16
  title?: string;
17
17
  }) => import("react").JSX.Element | null;
18
18
  /**
19
- * A person's status beside their name: the app's `presence` mark first, then a mark for busy or do not disturb, then
19
+ * A person's status beside their name: their `presence` dot first, then a mark for busy or do not disturb, then
20
20
  * the custom text, as text and never HTML, cut short with an ellipsis and in full on hover. Draws only `presence` when
21
21
  * the person has no status that holds now.
22
22
  */
@@ -1,5 +1,6 @@
1
1
  import { cn } from "../lib/cn.js";
2
2
  import { text } from "./messages.js";
3
+ import { PresenceDot } from "../presence/presence-dot.js";
3
4
  import { CircleMinus, Clock } from "lucide-react";
4
5
  import { heldStatus } from "@protobase/schema/internal";
5
6
  import { jsx, jsxs } from "react/jsx-runtime";
@@ -18,7 +19,7 @@ const AvailabilityMark = ({ availability, title }) => {
18
19
  });
19
20
  };
20
21
  /**
21
- * A person's status beside their name: the app's `presence` mark first, then a mark for busy or do not disturb, then
22
+ * A person's status beside their name: their `presence` dot first, then a mark for busy or do not disturb, then
22
23
  * the custom text, as text and never HTML, cut short with an ellipsis and in full on hover. Draws only `presence` when
23
24
  * the person has no status that holds now.
24
25
  */
@@ -30,7 +31,7 @@ const StatusMark = ({ status, presence, textShown = "full", className }) => {
30
31
  className: cn("inline-flex min-w-0 items-center gap-1 text-muted-foreground", className),
31
32
  title: words,
32
33
  children: [
33
- presence,
34
+ presence && /* @__PURE__ */ jsx(PresenceDot, { presence }),
34
35
  held && /* @__PURE__ */ jsx(AvailabilityMark, {
35
36
  availability: held.availability,
36
37
  ...textShown === "hover" && words && { title: words }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@protobase/ui",
3
- "version": "0.60.1",
3
+ "version": "0.62.0",
4
4
  "description": "The Protobase admin app and the React hooks and components for custom UI.",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {
@@ -39,9 +39,9 @@
39
39
  "dependencies": {
40
40
  "@dnd-kit/core": "^6.3.1",
41
41
  "@dnd-kit/sortable": "^10.0.0",
42
- "@protobase/client": "0.60.1",
43
- "@protobase/layout": "0.60.1",
44
- "@protobase/schema": "0.60.1",
42
+ "@protobase/client": "0.62.0",
43
+ "@protobase/layout": "0.62.0",
44
+ "@protobase/schema": "0.62.0",
45
45
  "@sentry/browser": "^11.7.0",
46
46
  "@tanstack/react-query": "^5.104.1",
47
47
  "@tanstack/react-table": "^9.2.6",
@@ -1,2 +0,0 @@
1
- /*! tailwindcss v4.3.3 | MIT License | https://tailwindcss.com */
2
- @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-pan-x:initial;--tw-pan-y:initial;--tw-pinch-zoom:initial;--tw-scroll-snap-strictness:proximity;--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-ordinal:initial;--tw-slashed-zero:initial;--tw-numeric-figure:initial;--tw-numeric-spacing:initial;--tw-numeric-fraction: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-content:""}}}@layer theme{:root,:host{--font-sans:var(--font,ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif);--color-white:#fff;--spacing:.25rem;--container-xs:20rem;--container-sm:24rem;--container-md:28rem;--container-lg:32rem;--container-xl:36rem;--container-3xl:48rem;--text-xs:.75rem;--text-xs--line-height:calc(1 / .75);--text-sm:.875rem;--text-sm--line-height:calc(1.25 / .875);--text-base:1rem;--text-base--line-height:calc(1.5 / 1);--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);--font-weight-normal:400;--font-weight-medium:500;--font-weight-semibold:600;--font-weight-bold:700;--tracking-tight:-.025em;--tracking-wide:.025em;--tracking-widest:.1em;--leading-tight:1.25;--leading-snug:1.375;--animate-spin:spin 1s linear infinite;--animate-ping:ping 1s cubic-bezier(0, 0, .2, 1) 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,ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif);--default-mono-font-family:var(--font-code,ui-monospace, "SF Mono", Menlo, Consolas, monospace);--shadow-pop:var(--shadow-pop)}}@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%;tab-size:4;line-height:1.5;font-family:var(--default-font-family,-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", "Noto Sans", Arial, 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;-webkit-text-decoration:inherit;-webkit-text-decoration: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:where(:not(iframe)){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}::placeholder{opacity:1}@supports (not ((-webkit-appearance:-apple-pay-button))) or (contain-intrinsic-size:1px){::placeholder{color:currentColor}@supports (color:color-mix(in lab, red, red)){::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]){appearance:button}::file-selector-button{appearance:button}::-webkit-inner-spin-button{height:auto}::-webkit-outer-spin-button{height:auto}[hidden]:where(:not([hidden=until-found])){display:none!important}:root{--background:#fff;--surface:#fafafa;--muted:#f4f4f5;--border:#e4e4e7;--border-strong:#d4d4d8;--foreground:#18181b;--muted-foreground:#71717a;--faint-foreground:#a1a1aa;--primary:#2563eb;--primary-hover:#1d4ed8;--primary-foreground:#fff;--primary-soft:#eff6ff;--primary-border:#bfdbfe;--primary-text:#1d4ed8;--success:#16a34a;--success-soft:#f0fdf4;--success-text:#15803d;--warning:#d97706;--warning-soft:#fffbeb;--warning-text:#b45309;--danger:#dc2626;--danger-soft:#fef2f2;--danger-text:#b91c1c;--violet:#7c3aed;--violet-soft:#f5f3ff;--violet-text:#6d28d9;--sidebar:#f8f8f9;--chart-1:#2a78d6;--chart-2:#eb6834;--chart-3:#1baf7a;--chart-4:#eda100;--chart-5:#e87ba4;--chart-6:#008300;--chart-7:#4a3aa7;--chart-8:#e34948;--shadow-pop:0 8px 24px -4px #0000001f, 0 2px 6px #0000000f;--backdrop:#18181b;--radius:6px;--font:ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;--font-code:ui-monospace, "SF Mono", Menlo, Consolas, monospace}[data-theme=dark]{--background:#0f0f11;--surface:#151518;--muted:#1f1f23;--border:#27272b;--border-strong:#3a3a40;--foreground:#f4f4f5;--muted-foreground:#a1a1aa;--faint-foreground:#71717a;--primary:#3b82f6;--primary-hover:#60a5fa;--primary-foreground:#fff;--primary-soft:#172036;--primary-border:#1e3a6e;--primary-text:#93c5fd;--success:#22c55e;--success-soft:#0f2418;--success-text:#86efac;--warning:#f59e0b;--warning-soft:#2a1f0a;--warning-text:#fcd34d;--danger:#ef4444;--danger-soft:#2a1214;--danger-text:#fca5a5;--violet:#8b5cf6;--violet-soft:#20173a;--violet-text:#c4b5fd;--sidebar:#121215;--chart-1:#3987e5;--chart-2:#d95926;--chart-3:#199e70;--chart-4:#c98500;--chart-5:#d55181;--chart-6:#008300;--chart-7:#9085e9;--chart-8:#e66767;--shadow-pop:0 8px 24px -4px #0009, 0 2px 6px #0006;--backdrop:#000}html{--lightningcss-light:initial;--lightningcss-dark: ;color-scheme:light;font-size:16px}html[data-theme=dark]{--lightningcss-light: ;--lightningcss-dark:initial;color-scheme:dark}:root{--pb-safe-top:var(--safe-area-inset-top,env(safe-area-inset-top,0px));--pb-safe-right:var(--safe-area-inset-right,env(safe-area-inset-right,0px));--pb-safe-bottom:var(--safe-area-inset-bottom,env(safe-area-inset-bottom,0px));--pb-safe-left:var(--safe-area-inset-left,env(safe-area-inset-left,0px))}html[data-pb-scroll-locked]{scrollbar-gutter:stable}body{background:var(--background);color:var(--foreground);font-family:var(--font-sans);-webkit-font-smoothing:antialiased;font-size:14px;line-height:1.5}button{cursor:pointer}@media (prefers-reduced-motion:reduce){*,:before,:after{scroll-behavior:auto!important;transition-duration:.01ms!important;animation-duration:.01ms!important;animation-iteration-count:1!important}}*{border-color:var(--border)}}@layer components;@layer utilities{.pointer-events-auto{pointer-events:auto}.pointer-events-none{pointer-events:none}.collapse{visibility:collapse}.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}.static{position:static}.sticky{position:sticky}.inset-0{inset:0}.inset-x-0{inset-inline:0}.inset-x-3{inset-inline:calc(var(--spacing) * 3)}.inset-x-4{inset-inline:calc(var(--spacing) * 4)}.inset-x-\[calc\(0\.75rem\+1px\)\]{inset-inline:calc(.75rem + 1px)}.inset-x-px{inset-inline:1px}.inset-y-0{inset-block:0}.-top-1{top:calc(var(--spacing) * -1)}.top-0{top:0}.top-1\.5{top:calc(var(--spacing) * 1.5)}.top-1\/2{top:50%}.top-2{top:calc(var(--spacing) * 2)}.top-2\.5{top:calc(var(--spacing) * 2.5)}.top-3{top:calc(var(--spacing) * 3)}.top-\[calc\(var\(--pb-sticky-top\,0px\)\+1rem\)\]{top:calc(var(--pb-sticky-top,0px) + 1rem)}.top-\[var\(--pb-sticky-top\,0px\)\]{top:var(--pb-sticky-top,0px)}.top-full{top:100%}.top-px{top:1px}.-right-1\.5{right:calc(var(--spacing) * -1.5)}.-right-2{right:calc(var(--spacing) * -2)}.-right-3{right:calc(var(--spacing) * -3)}.right-0{right:0}.right-1{right:var(--spacing)}.right-1\.5{right:calc(var(--spacing) * 1.5)}.right-2{right:calc(var(--spacing) * 2)}.right-3{right:calc(var(--spacing) * 3)}.right-4{right:calc(var(--spacing) * 4)}.right-\[var\(--pb-safe-right\)\]{right:var(--pb-safe-right)}.bottom-0{bottom:0}.bottom-2{bottom:calc(var(--spacing) * 2)}.bottom-3{bottom:calc(var(--spacing) * 3)}.bottom-4{bottom:calc(var(--spacing) * 4)}.bottom-\[calc\(0\.75rem\+1px\)\]{bottom:calc(.75rem + 1px)}.bottom-\[calc\(6rem\+var\(--pb-safe-bottom\)\)\]{bottom:calc(6rem + var(--pb-safe-bottom))}.bottom-\[var\(--pb-sticky-bottom\,0px\)\]{bottom:var(--pb-sticky-bottom,0px)}.bottom-full{bottom:100%}.-left-3{left:calc(var(--spacing) * -3)}.left-0{left:0}.left-1\/2{left:50%}.left-2{left:calc(var(--spacing) * 2)}.left-2\.5{left:calc(var(--spacing) * 2.5)}.left-3{left:calc(var(--spacing) * 3)}.left-\[var\(--pb-safe-left\)\]{left:var(--pb-safe-left)}.left-full{left:100%}.z-10{z-index:10}.z-20{z-index:20}.z-30{z-index:30}.z-40{z-index:40}.z-50{z-index:50}.z-\[60\]{z-index:60}.z-\[80\]{z-index:80}.z-\[90\]{z-index:90}.z-\[100\]{z-index:100}.col-span-2{grid-column:span 2/span 2}.col-span-4{grid-column:span 4/span 4}.row-span-2{grid-row:span 2/span 2}.container{width:100%}@media (width>=40rem){.container{max-width:40rem}}@media (width>=48rem){.container{max-width:48rem}}@media (width>=64rem){.container{max-width:64rem}}@media (width>=80rem){.container{max-width:80rem}}@media (width>=96rem){.container{max-width:96rem}}.m-1{margin:var(--spacing)}.m-2{margin:calc(var(--spacing) * 2)}.m-auto{margin:auto}.-mx-2{margin-inline:calc(var(--spacing) * -2)}.-mx-3{margin-inline:calc(var(--spacing) * -3)}.-mx-4{margin-inline:calc(var(--spacing) * -4)}.mx-1{margin-inline:var(--spacing)}.mx-auto{margin-inline:auto}.-my-0\.5{margin-block:calc(var(--spacing) * -.5)}.-my-3{margin-block:calc(var(--spacing) * -3)}.my-4{margin-block:calc(var(--spacing) * 4)}.-mt-3{margin-top:calc(var(--spacing) * -3)}.-mt-4{margin-top:calc(var(--spacing) * -4)}.mt-0\.5{margin-top:calc(var(--spacing) * .5)}.mt-1{margin-top:var(--spacing)}.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)}.mt-40{margin-top:calc(var(--spacing) * 40)}.mt-auto{margin-top:auto}.-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-4{margin-right:calc(var(--spacing) * 4)}.mr-auto{margin-right:auto}.-mb-2{margin-bottom:calc(var(--spacing) * -2)}.-mb-3{margin-bottom:calc(var(--spacing) * -3)}.-mb-px{margin-bottom:-1px}.mb-1{margin-bottom:var(--spacing)}.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-6{margin-bottom:calc(var(--spacing) * 6)}.-ml-2{margin-left:calc(var(--spacing) * -2)}.-ml-3{margin-left:calc(var(--spacing) * -3)}.ml-0\.5{margin-left:calc(var(--spacing) * .5)}.ml-1{margin-left:var(--spacing)}.ml-2{margin-left:calc(var(--spacing) * 2)}.ml-3{margin-left:calc(var(--spacing) * 3)}.ml-6{margin-left:calc(var(--spacing) * 6)}.ml-8{margin-left:calc(var(--spacing) * 8)}.ml-\[17px\]{margin-left:17px}.ml-\[20px\]{margin-left:20px}.ml-auto{margin-left:auto}.line-clamp-2{-webkit-line-clamp:2;-webkit-box-orient:vertical;display:-webkit-box;overflow:hidden}.line-clamp-3{-webkit-line-clamp:3;-webkit-box-orient:vertical;display:-webkit-box;overflow:hidden}.\!inline{display:inline!important}.block{display:block}.contents{display:contents}.flex{display:flex}.grid{display:grid}.hidden{display:none}.inline{display:inline}.inline-block{display:inline-block}.inline-flex{display:inline-flex}.table{display:table}.aspect-\[4\/3\]{aspect-ratio:4/3}.aspect-\[8\/5\]{aspect-ratio:8/5}.size-1\.5{width:calc(var(--spacing) * 1.5);height:calc(var(--spacing) * 1.5)}.size-2{width:calc(var(--spacing) * 2);height:calc(var(--spacing) * 2)}.size-2\.5{width:calc(var(--spacing) * 2.5);height:calc(var(--spacing) * 2.5)}.size-3{width:calc(var(--spacing) * 3);height:calc(var(--spacing) * 3)}.size-3\.5{width:calc(var(--spacing) * 3.5);height:calc(var(--spacing) * 3.5)}.size-4{width:calc(var(--spacing) * 4);height:calc(var(--spacing) * 4)}.size-5{width:calc(var(--spacing) * 5);height:calc(var(--spacing) * 5)}.size-6{width:calc(var(--spacing) * 6);height:calc(var(--spacing) * 6)}.size-7{width:calc(var(--spacing) * 7);height:calc(var(--spacing) * 7)}.size-8{width:calc(var(--spacing) * 8);height:calc(var(--spacing) * 8)}.size-9{width:calc(var(--spacing) * 9);height:calc(var(--spacing) * 9)}.size-10{width:calc(var(--spacing) * 10);height:calc(var(--spacing) * 10)}.size-11{width:calc(var(--spacing) * 11);height:calc(var(--spacing) * 11)}.size-12{width:calc(var(--spacing) * 12);height:calc(var(--spacing) * 12)}.size-36{width:calc(var(--spacing) * 36);height:calc(var(--spacing) * 36)}.size-44{width:calc(var(--spacing) * 44);height:calc(var(--spacing) * 44)}.size-\[18px\]{width:18px;height:18px}.size-full{width:100%;height:100%}.h-1{height:var(--spacing)}.h-1\.5{height:calc(var(--spacing) * 1.5)}.h-2{height:calc(var(--spacing) * 2)}.h-2\.5{height:calc(var(--spacing) * 2.5)}.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-9{height:calc(var(--spacing) * 9)}.h-12{height:calc(var(--spacing) * 12)}.h-20{height:calc(var(--spacing) * 20)}.h-24{height:calc(var(--spacing) * 24)}.h-36{height:calc(var(--spacing) * 36)}.h-40{height:calc(var(--spacing) * 40)}.h-48{height:calc(var(--spacing) * 48)}.h-56{height:calc(var(--spacing) * 56)}.h-64{height:calc(var(--spacing) * 64)}.h-80{height:calc(var(--spacing) * 80)}.h-96{height:calc(var(--spacing) * 96)}.h-\[480px\]{height:480px}.h-\[600px\]{height:600px}.h-\[760px\]{height:760px}.h-\[3000px\]{height:3000px}.h-\[calc\(3rem\+var\(--pb-safe-top\)\)\]{height:calc(3rem + var(--pb-safe-top))}.h-\[var\(--pb-sticky-bottom\)\]{height:var(--pb-sticky-bottom)}.h-\[var\(--pb-sticky-top\)\]{height:var(--pb-sticky-top)}.h-dvh{height:100dvh}.h-full{height:100%}.h-px{height:1px}.h-screen{height:100vh}.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-\[85vh\]{max-height:85vh}.max-h-\[calc\(100dvh-var\(--pb-sticky-top\,0px\)-var\(--pb-sticky-bottom\,0px\)-2rem\)\]{max-height:calc(100dvh - var(--pb-sticky-top,0px) - var(--pb-sticky-bottom,0px) - 2rem)}.max-h-\[min\(32rem\,calc\(100dvh-var\(--pb-sticky-top\,3rem\)-1rem\)\)\]{max-height:min(32rem, calc(100dvh - var(--pb-sticky-top,3rem) - 1rem))}.max-h-\[min\(90vh\,100\%\)\]{max-height:min(90vh,100%)}.max-h-full{max-height:100%}.min-h-0{min-height:0}.min-h-6{min-height:calc(var(--spacing) * 6)}.min-h-8{min-height:calc(var(--spacing) * 8)}.min-h-9{min-height:calc(var(--spacing) * 9)}.min-h-10{min-height:calc(var(--spacing) * 10)}.min-h-11{min-height:calc(var(--spacing) * 11)}.min-h-24{min-height:calc(var(--spacing) * 24)}.min-h-28{min-height:calc(var(--spacing) * 28)}.min-h-48{min-height:calc(var(--spacing) * 48)}.min-h-\[7\.5rem\]{min-height:7.5rem}.min-h-\[36rem\]{min-height:36rem}.min-h-\[49px\]{min-height:49px}.min-h-dvh{min-height:100dvh}.min-h-full{min-height:100%}.min-h-screen{min-height:100vh}.w-0\.5{width:calc(var(--spacing) * .5)}.w-1\/2{width:50%}.w-1\/3{width:33.3333%}.w-2{width:calc(var(--spacing) * 2)}.w-2\/3{width:66.6667%}.w-2\/5{width:40%}.w-3{width:calc(var(--spacing) * 3)}.w-3\/4{width:75%}.w-5\/6{width:83.3333%}.w-6{width:calc(var(--spacing) * 6)}.w-7{width:calc(var(--spacing) * 7)}.w-8{width:calc(var(--spacing) * 8)}.w-9{width:calc(var(--spacing) * 9)}.w-14{width:calc(var(--spacing) * 14)}.w-16{width:calc(var(--spacing) * 16)}.w-24{width:calc(var(--spacing) * 24)}.w-32{width:calc(var(--spacing) * 32)}.w-48{width:calc(var(--spacing) * 48)}.w-52{width:calc(var(--spacing) * 52)}.w-56{width:calc(var(--spacing) * 56)}.w-60{width:calc(var(--spacing) * 60)}.w-64{width:calc(var(--spacing) * 64)}.w-72{width:calc(var(--spacing) * 72)}.w-80{width:calc(var(--spacing) * 80)}.w-96{width:calc(var(--spacing) * 96)}.w-\[22rem\]{width:22rem}.w-\[76px\]{width:76px}.w-\[320px\]{width:320px}.w-\[348px\]{width:348px}.w-\[360px\]{width:360px}.w-\[380px\]{width:380px}.w-\[560px\]{width:560px}.w-\[700px\]{width:700px}.w-\[760px\]{width:760px}.w-\[900px\]{width:900px}.w-\[1100px\]{width:1100px}.w-\[calc\(15rem\+var\(--pb-safe-left\)\)\]{width:calc(15rem + var(--pb-safe-left))}.w-\[min\(22rem\,calc\(100\%-0\.5rem\)\)\]{width:min(22rem,100% - .5rem)}.w-auto{width:auto}.w-full{width:100%}.w-px{width:1px}.w-screen{width:100vw}.max-w-3xl{max-width:var(--container-3xl)}.max-w-12{max-width:calc(var(--spacing) * 12)}.max-w-48{max-width:calc(var(--spacing) * 48)}.max-w-60{max-width:calc(var(--spacing) * 60)}.max-w-80{max-width:calc(var(--spacing) * 80)}.max-w-\[16rem\]{max-width:16rem}.max-w-\[85vw\]{max-width:85vw}.max-w-\[760px\]{max-width:760px}.max-w-\[1100px\]{max-width:1100px}.max-w-\[1200px\]{max-width:1200px}.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)}.max-w-xl{max-width:var(--container-xl)}.min-w-0{min-width:0}.min-w-4{min-width:calc(var(--spacing) * 4)}.min-w-5{min-width:calc(var(--spacing) * 5)}.min-w-6{min-width:calc(var(--spacing) * 6)}.min-w-16{min-width:calc(var(--spacing) * 16)}.min-w-32{min-width:calc(var(--spacing) * 32)}.min-w-36{min-width:calc(var(--spacing) * 36)}.min-w-40{min-width:calc(var(--spacing) * 40)}.min-w-48{min-width:calc(var(--spacing) * 48)}.min-w-64{min-width:calc(var(--spacing) * 64)}.min-w-72{min-width:calc(var(--spacing) * 72)}.min-w-\[560px\]{min-width:560px}.flex-1{flex:1}.flex-auto{flex:auto}.shrink{flex-shrink:1}.shrink-0{flex-shrink:0}.grow{flex-grow:1}.basis-full{flex-basis:100%}.border-collapse{border-collapse:collapse}.-translate-x-1\/2{--tw-translate-x:calc(calc(1 / 2 * 100%) * -1);translate:var(--tw-translate-x) var(--tw-translate-y)}.translate-x-0\.5{--tw-translate-x:calc(var(--spacing) * .5);translate:var(--tw-translate-x) var(--tw-translate-y)}.translate-x-\[18px\]{--tw-translate-x:18px;translate:var(--tw-translate-x) var(--tw-translate-y)}.-translate-y-1\/2{--tw-translate-y:calc(calc(1 / 2 * 100%) * -1);translate:var(--tw-translate-x) var(--tw-translate-y)}.rotate-90{rotate:90deg}.transform{transform:var(--tw-rotate-x,) var(--tw-rotate-y,) var(--tw-rotate-z,) var(--tw-skew-x,) var(--tw-skew-y,)}.\[animation\:none\]{animation:none}.\[animation\:pb-shimmer_1\.4s_ease-in-out_infinite\]{animation:1.4s ease-in-out infinite pb-shimmer}.\[animation\:pb-slide-in_160ms_ease-out\]{animation:.16s ease-out pb-slide-in}.animate-ping{animation:var(--animate-ping)}.animate-pulse{animation:var(--animate-pulse)}.animate-spin{animation:var(--animate-spin)}.cursor-col-resize{cursor:col-resize}.cursor-default{cursor:default}.cursor-grab{cursor:grab}.cursor-pointer{cursor:pointer}.cursor-text{cursor:text}.touch-pan-y{--tw-pan-y:pan-y;touch-action:var(--tw-pan-x,) var(--tw-pan-y,) var(--tw-pinch-zoom,)}.touch-manipulation{touch-action:manipulation}.touch-none{touch-action:none}.resize{resize:both}.resize-none{resize:none}.resize-y{resize:vertical}.snap-x{scroll-snap-type:x var(--tw-scroll-snap-strictness)}.snap-mandatory{--tw-scroll-snap-strictness:mandatory}.snap-start{scroll-snap-align:start}.snap-always{scroll-snap-stop:always}.scroll-mt-\[calc\(var\(--pb-sticky-top\,0px\)\+2rem\)\]{scroll-margin-top:calc(var(--pb-sticky-top,0px) + 2rem)}.scroll-mb-\[calc\(var\(--pb-sticky-bottom\,0px\)\+3rem\)\]{scroll-margin-bottom:calc(var(--pb-sticky-bottom,0px) + 3rem)}.\[scrollbar-width\:none\]{scrollbar-width:none}.auto-cols-\[minmax\(12rem\,1fr\)\]{grid-auto-columns:minmax(12rem,1fr)}.grid-flow-col{grid-auto-flow:column}.grid-cols-1{grid-template-columns:repeat(1,minmax(0,1fr))}.grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.grid-cols-4{grid-template-columns:repeat(4,minmax(0,1fr))}.grid-cols-7{grid-template-columns:repeat(7,minmax(0,1fr))}.grid-cols-\[1fr_auto\]{grid-template-columns:1fr auto}.grid-cols-\[28px_minmax\(0\,1fr\)_88px_112px_112px_32px\]{grid-template-columns:28px minmax(0,1fr) 88px 112px 112px 32px}.grid-cols-\[72px_1fr\]{grid-template-columns:72px 1fr}.grid-cols-\[96px_1fr\]{grid-template-columns:96px 1fr}.grid-cols-\[auto_1fr\]{grid-template-columns:auto 1fr}.grid-cols-\[auto_minmax\(0\,1fr\)\]{grid-template-columns:auto minmax(0,1fr)}.grid-cols-\[minmax\(0\,1\.2fr\)_minmax\(0\,1\.8fr\)_150px_110px_minmax\(0\,1fr\)_110px_100px\]{grid-template-columns:minmax(0,1.2fr) minmax(0,1.8fr) 150px 110px minmax(0,1fr) 110px 100px}.grid-cols-\[minmax\(0\,1fr\)\]{grid-template-columns:minmax(0,1fr)}.grid-cols-\[minmax\(0\,1fr\)_300px\]{grid-template-columns:minmax(0,1fr) 300px}.grid-cols-\[minmax\(0\,2fr\)_minmax\(0\,3fr\)\]{grid-template-columns:minmax(0,2fr) minmax(0,3fr)}.grid-cols-\[minmax\(0\,auto\)_minmax\(0\,1fr\)\]{grid-template-columns:minmax(0,auto) minmax(0,1fr)}.grid-cols-\[minmax\(6rem\,35\%\)_1fr_auto\]{grid-template-columns:minmax(6rem,35%) 1fr auto}.grid-cols-\[repeat\(auto-fill\,minmax\(15rem\,1fr\)\)\]{grid-template-columns:repeat(auto-fill,minmax(15rem,1fr))}.grid-rows-2{grid-template-rows:repeat(2,minmax(0,1fr))}.grid-rows-\[minmax\(0\,1fr\)\]{grid-template-rows:minmax(0,1fr)}.flex-col{flex-direction:column}.flex-col-reverse{flex-direction:column-reverse}.flex-nowrap{flex-wrap:nowrap}.flex-wrap{flex-wrap:wrap}.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:var(--spacing)}.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-4{gap:calc(var(--spacing) * 4)}.gap-5{gap:calc(var(--spacing) * 5)}.gap-6{gap:calc(var(--spacing) * 6)}.gap-8{gap:calc(var(--spacing) * 8)}.gap-12{gap:calc(var(--spacing) * 12)}.gap-px{gap:1px}:where(.space-y-0\.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-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-2\.5>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 2.5) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 2.5) * 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)))}.gap-x-2{column-gap:calc(var(--spacing) * 2)}.gap-x-3{column-gap:calc(var(--spacing) * 3)}.gap-x-4{column-gap:calc(var(--spacing) * 4)}.gap-x-6{column-gap:calc(var(--spacing) * 6)}:where(.-space-x-1>:not(:last-child)){--tw-space-x-reverse:0;margin-inline-start:calc(calc(var(--spacing) * -1) * var(--tw-space-x-reverse));margin-inline-end:calc(calc(var(--spacing) * -1) * calc(1 - var(--tw-space-x-reverse)))}.gap-y-0\.5{row-gap:calc(var(--spacing) * .5)}.gap-y-1{row-gap:var(--spacing)}.gap-y-1\.5{row-gap:calc(var(--spacing) * 1.5)}.gap-y-2{row-gap:calc(var(--spacing) * 2)}.gap-y-5{row-gap:calc(var(--spacing) * 5)}: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-border>:not(:last-child)){border-color:var(--border)}.self-center{align-self:center}.self-end{align-self:flex-end}.self-start{align-self:flex-start}.self-stretch{align-self:stretch}.truncate{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.overflow-auto{overflow:auto}.overflow-clip{overflow:clip}.overflow-hidden{overflow:hidden}.overflow-visible{overflow:visible}.overflow-x-auto{overflow-x:auto}.overflow-x-clip{overflow-x:clip}.overflow-x-hidden{overflow-x:hidden}.overflow-y-auto{overflow-y:auto}.overflow-y-hidden{overflow-y:hidden}.overscroll-contain{overscroll-behavior:contain}.overscroll-x-contain{overscroll-behavior-x:contain}.rounded{border-radius:.25rem}.rounded-full{border-radius:2147483647px}.rounded-lg{border-radius:calc(var(--radius,6px) + 2px)}.rounded-md{border-radius:var(--radius,6px)}.rounded-sm{border-radius:max(0px, calc(var(--radius,6px) - 2px))}.rounded-t-lg{border-top-left-radius:calc(var(--radius,6px) + 2px);border-top-right-radius:calc(var(--radius,6px) + 2px)}.rounded-t-sm{border-top-left-radius:max(0px, calc(var(--radius,6px) - 2px));border-top-right-radius:max(0px, calc(var(--radius,6px) - 2px))}.rounded-t-xl{border-top-left-radius:calc(var(--radius,6px) + 6px);border-top-right-radius:calc(var(--radius,6px) + 6px)}.rounded-l-none{border-top-left-radius:0;border-bottom-left-radius:0}.rounded-l-sm{border-top-left-radius:max(0px, calc(var(--radius,6px) - 2px));border-bottom-left-radius:max(0px, calc(var(--radius,6px) - 2px))}.rounded-r{border-top-right-radius:.25rem;border-bottom-right-radius:.25rem}.rounded-r-none{border-top-right-radius:0;border-bottom-right-radius:0}.rounded-br-sm{border-bottom-right-radius:max(0px, calc(var(--radius,6px) - 2px))}.border{border-style:var(--tw-border-style);border-width:1px}.border-2{border-style:var(--tw-border-style);border-width:2px}.border-y{border-block-style:var(--tw-border-style);border-block-width:1px}.border-t{border-top-style:var(--tw-border-style);border-top-width:1px}.border-r{border-right-style:var(--tw-border-style);border-right-width:1px}.border-r-0{border-right-style:var(--tw-border-style);border-right-width:0}.border-b{border-bottom-style:var(--tw-border-style);border-bottom-width:1px}.border-b-2{border-bottom-style:var(--tw-border-style);border-bottom-width:2px}.border-l{border-left-style:var(--tw-border-style);border-left-width:1px}.border-l-0{border-left-style:var(--tw-border-style);border-left-width:0}.border-dashed{--tw-border-style:dashed;border-style:dashed}.border-background{border-color:var(--background)}.border-border{border-color:var(--border)}.border-border-strong{border-color:var(--border-strong)}.border-danger,.border-danger\/30{border-color:var(--danger)}@supports (color:color-mix(in lab, red, red)){.border-danger\/30{border-color:color-mix(in oklab, var(--danger) 30%, transparent)}}.border-danger\/40{border-color:var(--danger)}@supports (color:color-mix(in lab, red, red)){.border-danger\/40{border-color:color-mix(in oklab, var(--danger) 40%, transparent)}}.border-foreground{border-color:var(--foreground)}.border-primary{border-color:var(--primary)}.border-primary-border{border-color:var(--primary-border)}.border-success\/40{border-color:var(--success)}@supports (color:color-mix(in lab, red, red)){.border-success\/40{border-color:color-mix(in oklab, var(--success) 40%, transparent)}}.border-transparent{border-color:#0000}.border-warning,.border-warning\/30{border-color:var(--warning)}@supports (color:color-mix(in lab, red, red)){.border-warning\/30{border-color:color-mix(in oklab, var(--warning) 30%, transparent)}}.border-warning\/40{border-color:var(--warning)}@supports (color:color-mix(in lab, red, red)){.border-warning\/40{border-color:color-mix(in oklab, var(--warning) 40%, transparent)}}.bg-backdrop,.bg-backdrop\/30{background-color:var(--backdrop)}@supports (color:color-mix(in lab, red, red)){.bg-backdrop\/30{background-color:color-mix(in oklab, var(--backdrop) 30%, transparent)}}.bg-backdrop\/40{background-color:var(--backdrop)}@supports (color:color-mix(in lab, red, red)){.bg-backdrop\/40{background-color:color-mix(in oklab, var(--backdrop) 40%, transparent)}}.bg-backdrop\/55{background-color:var(--backdrop)}@supports (color:color-mix(in lab, red, red)){.bg-backdrop\/55{background-color:color-mix(in oklab, var(--backdrop) 55%, transparent)}}.bg-background,.bg-background\/70{background-color:var(--background)}@supports (color:color-mix(in lab, red, red)){.bg-background\/70{background-color:color-mix(in oklab, var(--background) 70%, transparent)}}.bg-background\/85{background-color:var(--background)}@supports (color:color-mix(in lab, red, red)){.bg-background\/85{background-color:color-mix(in oklab, var(--background) 85%, transparent)}}.bg-border{background-color:var(--border)}.bg-border-strong{background-color:var(--border-strong)}.bg-danger{background-color:var(--danger)}.bg-danger-soft{background-color:var(--danger-soft)}.bg-faint-foreground{background-color:var(--faint-foreground)}.bg-foreground,.bg-foreground\/35{background-color:var(--foreground)}@supports (color:color-mix(in lab, red, red)){.bg-foreground\/35{background-color:color-mix(in oklab, var(--foreground) 35%, transparent)}}.bg-inherit{background-color:inherit}.bg-muted{background-color:var(--muted)}.bg-primary{background-color:var(--primary)}.bg-primary-soft,.bg-primary-soft\/60{background-color:var(--primary-soft)}@supports (color:color-mix(in lab, red, red)){.bg-primary-soft\/60{background-color:color-mix(in oklab, var(--primary-soft) 60%, transparent)}}.bg-primary\/5{background-color:var(--primary)}@supports (color:color-mix(in lab, red, red)){.bg-primary\/5{background-color:color-mix(in oklab, var(--primary) 5%, transparent)}}.bg-primary\/10{background-color:var(--primary)}@supports (color:color-mix(in lab, red, red)){.bg-primary\/10{background-color:color-mix(in oklab, var(--primary) 10%, transparent)}}.bg-primary\/60{background-color:var(--primary)}@supports (color:color-mix(in lab, red, red)){.bg-primary\/60{background-color:color-mix(in oklab, var(--primary) 60%, transparent)}}.bg-primary\/70{background-color:var(--primary)}@supports (color:color-mix(in lab, red, red)){.bg-primary\/70{background-color:color-mix(in oklab, var(--primary) 70%, transparent)}}.bg-sidebar{background-color:var(--sidebar)}.bg-success{background-color:var(--success)}.bg-success-soft{background-color:var(--success-soft)}.bg-surface{background-color:var(--surface)}.bg-transparent{background-color:#0000}.bg-violet{background-color:var(--violet)}.bg-violet-soft{background-color:var(--violet-soft)}.bg-warning{background-color:var(--warning)}.bg-warning-soft{background-color:var(--warning-soft)}.bg-white{background-color:var(--color-white)}.bg-gradient-to-l{--tw-gradient-position:to left in oklab;background-image:linear-gradient(var(--tw-gradient-stops))}.from-backdrop\/15{--tw-gradient-from:var(--backdrop)}@supports (color:color-mix(in lab, red, red)){.from-backdrop\/15{--tw-gradient-from:color-mix(in oklab, var(--backdrop) 15%, transparent)}}.from-backdrop\/15{--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-transparent{--tw-gradient-to:transparent;--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))}.fill-\[\#14161a\]{fill:#14161a}.fill-\[\#ff5a1f\]{fill:#ff5a1f}.fill-background{fill:var(--background)}.fill-current{fill:currentColor}.fill-foreground{fill:var(--foreground)}.fill-primary{fill:var(--primary)}.object-contain{object-fit:contain}.object-cover{object-fit:cover}.p-0\.5{padding:calc(var(--spacing) * .5)}.p-1{padding:var(--spacing)}.p-1\.5{padding:calc(var(--spacing) * 1.5)}.p-2{padding:calc(var(--spacing) * 2)}.p-3{padding:calc(var(--spacing) * 3)}.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)}.px-0{padding-inline:0}.px-0\.5{padding-inline:calc(var(--spacing) * .5)}.px-1{padding-inline:var(--spacing)}.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)}.px-10{padding-inline:calc(var(--spacing) * 10)}.px-\[7px\]{padding-inline:7px}.py-0{padding-block:0}.py-0\.5{padding-block:calc(var(--spacing) * .5)}.py-1{padding-block:var(--spacing)}.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-6{padding-block:calc(var(--spacing) * 6)}.py-8{padding-block:calc(var(--spacing) * 8)}.py-10{padding-block:calc(var(--spacing) * 10)}.pt-0\.5{padding-top:calc(var(--spacing) * .5)}.pt-1{padding-top:var(--spacing)}.pt-1\.5{padding-top:calc(var(--spacing) * 1.5)}.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)}.pt-8{padding-top:calc(var(--spacing) * 8)}.pt-\[calc\(0\.75rem\+var\(--pb-safe-top\)\)\]{padding-top:calc(.75rem + var(--pb-safe-top))}.pt-\[calc\(1\.25rem\+var\(--pb-safe-top\)\)\]{padding-top:calc(1.25rem + var(--pb-safe-top))}.pt-\[calc\(1rem\+var\(--pb-safe-top\)\)\]{padding-top:calc(1rem + var(--pb-safe-top))}.pt-\[calc\(2\.5rem\+var\(--pb-safe-top\)\)\]{padding-top:calc(2.5rem + var(--pb-safe-top))}.pt-\[var\(--pb-safe-top\)\]{padding-top:var(--pb-safe-top)}.pr-0\.5{padding-right:calc(var(--spacing) * .5)}.pr-1{padding-right:var(--spacing)}.pr-1\.5{padding-right:calc(var(--spacing) * 1.5)}.pr-2{padding-right:calc(var(--spacing) * 2)}.pr-3{padding-right:calc(var(--spacing) * 3)}.pr-4{padding-right:calc(var(--spacing) * 4)}.pr-8{padding-right:calc(var(--spacing) * 8)}.pr-\[calc\(1rem\+var\(--pb-safe-right\)\)\]{padding-right:calc(1rem + var(--pb-safe-right))}.pr-\[var\(--pb-safe-right\)\]{padding-right:var(--pb-safe-right)}.pb-0{padding-bottom:0}.pb-1{padding-bottom:var(--spacing)}.pb-2{padding-bottom:calc(var(--spacing) * 2)}.pb-3{padding-bottom:calc(var(--spacing) * 3)}.pb-6{padding-bottom:calc(var(--spacing) * 6)}.pb-8{padding-bottom:calc(var(--spacing) * 8)}.pb-16{padding-bottom:calc(var(--spacing) * 16)}.pb-\[calc\(0\.75rem\+var\(--pb-safe-bottom\)\)\]{padding-bottom:calc(.75rem + var(--pb-safe-bottom))}.pb-\[calc\(1\.5rem\+var\(--pb-safe-bottom\)\)\]{padding-bottom:calc(1.5rem + var(--pb-safe-bottom))}.pb-\[calc\(1rem\+var\(--pb-safe-bottom\)\)\]{padding-bottom:calc(1rem + var(--pb-safe-bottom))}.pb-\[calc\(2\.5rem\+var\(--pb-safe-bottom\)\)\]{padding-bottom:calc(2.5rem + var(--pb-safe-bottom))}.pb-\[var\(--pb-safe-bottom\)\]{padding-bottom:var(--pb-safe-bottom)}.pl-1\.5{padding-left:calc(var(--spacing) * 1.5)}.pl-2{padding-left:calc(var(--spacing) * 2)}.pl-2\.5{padding-left:calc(var(--spacing) * 2.5)}.pl-3{padding-left:calc(var(--spacing) * 3)}.pl-4{padding-left:calc(var(--spacing) * 4)}.pl-\[calc\(1rem\+var\(--pb-safe-left\)\)\]{padding-left:calc(1rem + var(--pb-safe-left))}.pl-\[var\(--pb-safe-left\)\]{padding-left:var(--pb-safe-left)}.text-center{text-align:center}.text-left{text-align:left}.text-right{text-align:right}.align-bottom{vertical-align:bottom}.font-mono{font-family:var(--font-code,ui-monospace, "SF Mono", Menlo, Consolas, monospace)}.font-sans{font-family:var(--font,ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif)}.text-2xl{font-size:var(--text-2xl);line-height:var(--tw-leading,var(--text-2xl--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-\[9px\]{font-size:9px}.text-\[10px\]{font-size:10px}.text-\[11px\]{font-size:11px}.text-\[15px\]{font-size:15px}.text-\[16px\]{font-size:16px}.text-body{font-size:14px}.leading-4{--tw-leading:calc(var(--spacing) * 4);line-height:calc(var(--spacing) * 4)}.leading-6{--tw-leading:calc(var(--spacing) * 6);line-height:calc(var(--spacing) * 6)}.leading-\[18px\]{--tw-leading:18px;line-height:18px}.leading-none{--tw-leading:1;line-height:1}.leading-snug{--tw-leading:var(--leading-snug);line-height:var(--leading-snug)}.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-wide{--tw-tracking:var(--tracking-wide);letter-spacing:var(--tracking-wide)}.tracking-widest{--tw-tracking:var(--tracking-widest);letter-spacing:var(--tracking-widest)}.break-words{overflow-wrap:break-word}.break-all{word-break:break-all}.whitespace-normal{white-space:normal}.whitespace-nowrap{white-space:nowrap}.whitespace-pre-line{white-space:pre-line}.whitespace-pre-wrap{white-space:pre-wrap}.text-background{color:var(--background)}.text-danger{color:var(--danger)}.text-danger-text{color:var(--danger-text)}.text-faint-foreground{color:var(--faint-foreground)}.text-foreground{color:var(--foreground)}.text-muted-foreground{color:var(--muted-foreground)}.text-primary{color:var(--primary)}.text-primary-foreground{color:var(--primary-foreground)}.text-primary-text,.text-primary-text\/80{color:var(--primary-text)}@supports (color:color-mix(in lab, red, red)){.text-primary-text\/80{color:color-mix(in oklab, var(--primary-text) 80%, transparent)}}.text-success{color:var(--success)}.text-success-text{color:var(--success-text)}.text-transparent{color:#0000}.text-violet-text{color:var(--violet-text)}.text-warning{color:var(--warning)}.text-warning-text{color:var(--warning-text)}.text-white{color:var(--color-white)}.lowercase{text-transform:lowercase}.uppercase{text-transform:uppercase}.italic{font-style:italic}.tabular-nums{--tw-numeric-spacing:tabular-nums;font-variant-numeric:var(--tw-ordinal,) var(--tw-slashed-zero,) var(--tw-numeric-figure,) var(--tw-numeric-spacing,) var(--tw-numeric-fraction,)}.line-through{text-decoration-line:line-through}.no-underline{text-decoration-line:none}.underline{text-decoration-line:underline}.underline-offset-2{text-underline-offset:2px}.caret-transparent{caret-color:#0000}.opacity-0{opacity:0}.opacity-40{opacity:.4}.opacity-50{opacity:.5}.opacity-60{opacity:.6}.opacity-70{opacity:.7}.opacity-80{opacity:.8}.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-\[1px_0_0_var\(--border\)\,4px_0_6px_-2px_rgb\(0_0_0\/0\.12\)\]{--tw-shadow:1px 0 0 var(--tw-shadow-color,var(--border)), 4px 0 6px -2px var(--tw-shadow-color,#0000001f);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.shadow-\[inset_0_0_0_2px_var\(--primary\)\]{--tw-shadow:inset 0 0 0 2px var(--tw-shadow-color,var(--primary));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-none{--tw-shadow:0 0 #0000;box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.shadow-pop{--tw-shadow:var(--shadow-pop);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)}.ring{--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-0{--tw-ring-shadow:var(--tw-ring-inset,) 0 0 0 calc(0px + 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-2{--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)}.ring-background{--tw-ring-color:var(--background)}.ring-danger\/20{--tw-ring-color:var(--danger)}@supports (color:color-mix(in lab, red, red)){.ring-danger\/20{--tw-ring-color:color-mix(in oklab, var(--danger) 20%, transparent)}}.ring-foreground\/30{--tw-ring-color:var(--foreground)}@supports (color:color-mix(in lab, red, red)){.ring-foreground\/30{--tw-ring-color:color-mix(in oklab, var(--foreground) 30%, transparent)}}.ring-primary\/20{--tw-ring-color:var(--primary)}@supports (color:color-mix(in lab, red, red)){.ring-primary\/20{--tw-ring-color:color-mix(in oklab, var(--primary) 20%, transparent)}}.ring-primary\/30{--tw-ring-color:var(--primary)}@supports (color:color-mix(in lab, red, red)){.ring-primary\/30{--tw-ring-color:color-mix(in oklab, var(--primary) 30%, transparent)}}.outline{outline-style:var(--tw-outline-style);outline-width:1px}.blur{--tw-blur:blur(8px);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,)}.drop-shadow{--tw-drop-shadow-size:drop-shadow(0 1px 2px var(--tw-drop-shadow-color,#0000001a)) drop-shadow(0 1px 1px var(--tw-drop-shadow-color,#0000000f));--tw-drop-shadow:drop-shadow(0 1px 2px #0000001a) drop-shadow(0 1px 1px #0000000f);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,)}.sepia{--tw-sepia:sepia(100%);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,)}.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,-webkit-backdrop-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\,box-shadow\]{transition-property:width,box-shadow;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-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-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-300{--tw-duration:.3s;transition-duration:.3s}.outline-none{--tw-outline-style:none;outline-style:none}.select-none{-webkit-user-select:none;user-select:none}.\[-webkit-overflow-scrolling\:touch\]{-webkit-overflow-scrolling:touch}.\[overflow-anchor\:none\]{overflow-anchor:none}.ring-inset{--tw-ring-inset:inset}:is(.\*\:w-\(--snap-item-width\)>*){width:var(--snap-item-width)}:is(.\*\:min-w-\[min\(100\%\,12rem\)\]>*){min-width:min(100%,12rem)}:is(.\*\:shrink-0>*){flex-shrink:0}:is(.\*\:snap-start>*){scroll-snap-align:start}.group-focus-within\/side\:opacity-100:is(:where(.group\/side):focus-within *){opacity:1}@media (hover:hover){.group-hover\:text-foreground:is(:where(.group):hover *){color:var(--foreground)}.group-hover\:text-primary-text:is(:where(.group):hover *){color:var(--primary-text)}.group-hover\/arrows\:opacity-100:is(:where(.group\/arrows):hover *),.group-hover\/carousel\:opacity-100:is(:where(.group\/carousel):hover *),.group-hover\/head\:opacity-100:is(:where(.group\/head):hover *){opacity:1}.group-hover\/resize\:bg-primary:is(:where(.group\/resize):hover *){background-color:var(--primary)}.group-hover\/side\:opacity-100:is(:where(.group\/side):hover *){opacity:1}.group-hover\/tile\:scale-\[1\.02\]:is(:where(.group\/tile):hover *){scale:1.02}.group-hover\/tooltip\:opacity-100:is(:where(.group\/tooltip):hover *){opacity:1}}.group-focus-visible\/resize\:bg-primary:is(:where(.group\/resize):focus-visible *),.group-active\/resize\:bg-primary:is(:where(.group\/resize):active *){background-color:var(--primary)}.group-has-\[\:focus-visible\]\/arrows\:opacity-100:is(:where(.group\/arrows):has(:focus-visible) *),.group-has-\[\[data-card-photos\]\:hover\]\/card\:opacity-100:is(:where(.group\/card):has([data-card-photos]:hover) *){opacity:1}.selection\:bg-transparent ::selection{background-color:#0000}.selection\:bg-transparent::selection{background-color:#0000}.file\:mr-3::file-selector-button{margin-right:calc(var(--spacing) * 3)}.file\:h-8::file-selector-button{height:calc(var(--spacing) * 8)}.file\:rounded-md::file-selector-button{border-radius:var(--radius,6px)}.file\:border::file-selector-button{border-style:var(--tw-border-style);border-width:1px}.file\:border-border-strong::file-selector-button{border-color:var(--border-strong)}.file\:bg-background::file-selector-button{background-color:var(--background)}.file\:px-3::file-selector-button{padding-inline:calc(var(--spacing) * 3)}.file\:font-medium::file-selector-button{--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium)}.file\:text-foreground::file-selector-button{color:var(--foreground)}.placeholder\:text-faint-foreground::placeholder{color:var(--faint-foreground)}.before\:absolute:before{content:var(--tw-content);position:absolute}.before\:inset-x-0:before{content:var(--tw-content);inset-inline:0}.before\:-top-1:before{content:var(--tw-content);top:calc(var(--spacing) * -1)}.before\:h-0\.5:before{content:var(--tw-content);height:calc(var(--spacing) * .5)}.before\:rounded-full:before{content:var(--tw-content);border-radius:2147483647px}.before\:bg-primary:before{content:var(--tw-content);background-color:var(--primary)}.before\:content-\[attr\(data-digit\)\]:before{--tw-content:attr(data-digit);content:var(--tw-content)}.after\:absolute:after{content:var(--tw-content);position:absolute}.after\:-inset-1:after{content:var(--tw-content);inset:calc(var(--spacing) * -1)}.after\:-inset-2:after{content:var(--tw-content);inset:calc(var(--spacing) * -2)}.after\:inset-0:after{content:var(--tw-content);inset:0}.after\:content-\[\"\"\]:after,.after\:content-\[\'\'\]:after{--tw-content:"";content:var(--tw-content)}.first\:pt-0:first-child{padding-top:0}.first\:pt-8:first-child{padding-top:calc(var(--spacing) * 8)}.last\:border-b-0:last-child{border-bottom-style:var(--tw-border-style);border-bottom-width:0}.last\:pb-0:last-child{padding-bottom:0}.focus-within\:w-60:focus-within{width:calc(var(--spacing) * 60)}.focus-within\:border-primary:focus-within{border-color:var(--primary)}.focus-within\:shadow-pop:focus-within{--tw-shadow:var(--shadow-pop);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.focus-within\:ring-2:focus-within{--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-within\:ring-primary\/20:focus-within{--tw-ring-color:var(--primary)}@supports (color:color-mix(in lab, red, red)){.focus-within\:ring-primary\/20:focus-within{--tw-ring-color:color-mix(in oklab, var(--primary) 20%, transparent)}}@media (hover:hover){.hover\:w-60:hover{width:calc(var(--spacing) * 60)}.hover\:border-border-strong:hover{border-color:var(--border-strong)}.hover\:border-faint-foreground:hover{border-color:var(--faint-foreground)}.hover\:bg-background:hover{background-color:var(--background)}.hover\:bg-danger-soft:hover{background-color:var(--danger-soft)}.hover\:bg-danger\/90:hover{background-color:var(--danger)}@supports (color:color-mix(in lab, red, red)){.hover\:bg-danger\/90:hover{background-color:color-mix(in oklab, var(--danger) 90%, transparent)}}.hover\:bg-muted:hover{background-color:var(--muted)}.hover\:bg-primary-border\/60:hover{background-color:var(--primary-border)}@supports (color:color-mix(in lab, red, red)){.hover\:bg-primary-border\/60:hover{background-color:color-mix(in oklab, var(--primary-border) 60%, transparent)}}.hover\:bg-primary-hover:hover{background-color:var(--primary-hover)}.hover\:bg-primary-soft:hover{background-color:var(--primary-soft)}.hover\:bg-surface:hover{background-color:var(--surface)}.hover\:bg-transparent:hover{background-color:#0000}.hover\:bg-warning\/10:hover{background-color:var(--warning)}@supports (color:color-mix(in lab, red, red)){.hover\:bg-warning\/10:hover{background-color:color-mix(in oklab, var(--warning) 10%, transparent)}}.hover\:bg-warning\/15:hover{background-color:var(--warning)}@supports (color:color-mix(in lab, red, red)){.hover\:bg-warning\/15:hover{background-color:color-mix(in oklab, var(--warning) 15%, transparent)}}.hover\:text-foreground:hover{color:var(--foreground)}.hover\:text-primary-text:hover{color:var(--primary-text)}.hover\:underline:hover{text-decoration-line:underline}.hover\:opacity-100:hover{opacity:1}.hover\:shadow-pop:hover{--tw-shadow:var(--shadow-pop);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}}.focus\:border-primary:focus{border-color:var(--primary)}.focus\:bg-background:focus{background-color:var(--background)}.focus\:bg-muted:focus{background-color:var(--muted)}.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-primary\/20:focus{--tw-ring-color:var(--primary)}@supports (color:color-mix(in lab, red, red)){.focus\:ring-primary\/20:focus{--tw-ring-color:color-mix(in oklab, var(--primary) 20%, transparent)}}.focus\:outline-none:focus{--tw-outline-style:none;outline-style:none}.focus-visible\:text-foreground:focus-visible{color:var(--foreground)}.focus-visible\:opacity-100:focus-visible{opacity:1}.focus-visible\:ring-2:focus-visible{--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-visible\:ring-primary:focus-visible,.focus-visible\:ring-primary\/30:focus-visible{--tw-ring-color:var(--primary)}@supports (color:color-mix(in lab, red, red)){.focus-visible\:ring-primary\/30:focus-visible{--tw-ring-color:color-mix(in oklab, var(--primary) 30%, transparent)}}.focus-visible\:ring-primary\/40:focus-visible{--tw-ring-color:var(--primary)}@supports (color:color-mix(in lab, red, red)){.focus-visible\:ring-primary\/40:focus-visible{--tw-ring-color:color-mix(in oklab, var(--primary) 40%, transparent)}}.focus-visible\:outline-2:focus-visible{outline-style:var(--tw-outline-style);outline-width:2px}.focus-visible\:-outline-offset-2:focus-visible{outline-offset:calc(2px * -1)}.focus-visible\:outline-offset-2:focus-visible{outline-offset:2px}.focus-visible\:outline-primary:focus-visible{outline-color:var(--primary)}.focus-visible\:outline-none:focus-visible{--tw-outline-style:none;outline-style:none}.focus-visible\:ring-inset:focus-visible{--tw-ring-inset:inset}.active\:cursor-grabbing:active{cursor:grabbing}.disabled\:cursor-default:disabled{cursor:default}.disabled\:cursor-not-allowed:disabled{cursor:not-allowed}.disabled\:text-faint-foreground:disabled{color:var(--faint-foreground)}.disabled\:opacity-60:disabled{opacity:.6}@media (hover:hover){.disabled\:hover\:bg-transparent:disabled:hover{background-color:#0000}}.has-\[\:focus-visible\]\:outline-2:has(:focus-visible){outline-style:var(--tw-outline-style);outline-width:2px}.has-\[\:focus-visible\]\:outline-offset-2:has(:focus-visible){outline-offset:2px}.has-\[\:focus-visible\]\:outline-primary:has(:focus-visible){outline-color:var(--primary)}.aria-disabled\:cursor-default[aria-disabled=true]{cursor:default}.aria-disabled\:opacity-40[aria-disabled=true]{opacity:.4}.aria-expanded\:bg-foreground[aria-expanded=true]{background-color:var(--foreground)}.aria-expanded\:text-background[aria-expanded=true]{color:var(--background)}.aria-expanded\:opacity-100[aria-expanded=true]{opacity:1}@media (prefers-reduced-motion:no-preference){.motion-safe\:scroll-smooth{scroll-behavior:smooth}}@media (prefers-reduced-motion:reduce){.motion-reduce\:animate-none{animation:none}}@media not all and (width>=48rem){.max-md\:sr-only{clip-path:inset(50%);white-space:nowrap;border-width:0;width:1px;height:1px;margin:-1px;padding:0;position:absolute;overflow:hidden}.max-md\:fixed{position:fixed}.max-md\:inset-0{inset:0}.max-md\:top-0{top:0}.max-md\:right-0{right:0}.max-md\:right-\[var\(--pb-safe-right\)\]{right:var(--pb-safe-right)}.max-md\:left-\[var\(--pb-safe-left\)\]{left:var(--pb-safe-left)}.max-md\:z-40{z-index:40}.max-md\:order-first{order:-9999}.max-md\:-mx-5{margin-inline:calc(var(--spacing) * -5)}.max-md\:-mb-4{margin-bottom:calc(var(--spacing) * -4)}.max-md\:hidden{display:none}.max-md\:size-5{width:calc(var(--spacing) * 5);height:calc(var(--spacing) * 5)}.max-md\:size-9{width:calc(var(--spacing) * 9);height:calc(var(--spacing) * 9)}.max-md\:min-h-0{min-height:0}.max-md\:min-h-11{min-height:calc(var(--spacing) * 11)}.max-md\:w-full{width:100%}.max-md\:flex-1{flex:1}.max-md\:rounded-none{border-radius:0}.max-md\:border-0{border-style:var(--tw-border-style);border-width:0}.max-md\:border-l-0{border-left-style:var(--tw-border-style);border-left-width:0}.max-md\:p-0{padding:0}}@media not all and (width>=40rem){.max-sm\:min-h-11{min-height:calc(var(--spacing) * 11)}.max-sm\:flex-1{flex:1}.max-sm\:file\:min-h-11::file-selector-button{min-height:calc(var(--spacing) * 11)}}@media (width>=40rem){.sm\:col-span-2{grid-column:span 2/span 2}.sm\:mr-auto{margin-right:auto}.sm\:block{display:block}.sm\:flex{display:flex}.sm\:inline{display:inline}.sm\:min-h-64{min-height:calc(var(--spacing) * 64)}.sm\:min-h-\[28rem\]{min-height:28rem}.sm\:w-48{width:calc(var(--spacing) * 48)}.sm\:w-72{width:calc(var(--spacing) * 72)}.sm\:w-auto{width:auto}.sm\:max-w-xs{max-width:var(--container-xs)}.sm\:flex-initial{flex:0 auto}.sm\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.sm\:grid-cols-4{grid-template-columns:repeat(4,minmax(0,1fr))}.sm\:grid-cols-7{grid-template-columns:repeat(7,minmax(0,1fr))}.sm\:grid-cols-\[12rem_minmax\(0\,1fr\)\]{grid-template-columns:12rem minmax(0,1fr)}.sm\:flex-row{flex-direction:row}.sm\:flex-wrap{flex-wrap:wrap}.sm\:items-center{align-items:center}.sm\:items-end{align-items:flex-end}.sm\:items-start{align-items:flex-start}.sm\:justify-between{justify-content:space-between}.sm\:justify-center{justify-content:center}.sm\:justify-end{justify-content:flex-end}.sm\:gap-4{gap:calc(var(--spacing) * 4)}.sm\:gap-6{gap:calc(var(--spacing) * 6)}.sm\:gap-x-10{column-gap:calc(var(--spacing) * 10)}.sm\:border-l{border-left-style:var(--tw-border-style);border-left-width:1px}.sm\:p-5{padding:calc(var(--spacing) * 5)}.sm\:py-1\.5{padding-block:calc(var(--spacing) * 1.5)}.sm\:py-16{padding-block:calc(var(--spacing) * 16)}}@media (width>=48rem){.md\:sticky{position:sticky}.md\:inset-x-auto{inset-inline:auto}.md\:top-0{top:0}.md\:top-\[var\(--pb-sticky-top\,0px\)\]{top:var(--pb-sticky-top,0px)}.md\:right-\[calc\(1rem\+var\(--pb-safe-right\)\)\]{right:calc(1rem + var(--pb-safe-right))}.md\:bottom-\[calc\(1rem\+var\(--pb-safe-bottom\)\)\]{bottom:calc(1rem + var(--pb-safe-bottom))}.md\:col-span-2{grid-column:span 2/span 2}.md\:col-span-4{grid-column:span 4/span 4}.md\:row-span-2{grid-row:span 2/span 2}.md\:mx-0{margin-inline:0}.md\:mt-0\.5{margin-top:calc(var(--spacing) * .5)}.md\:block{display:block}.md\:flex{display:flex}.md\:hidden{display:none}.md\:inline-flex{display:inline-flex}.md\:aspect-\[2\/1\]{aspect-ratio:2}.md\:h-80{height:calc(var(--spacing) * 80)}.md\:max-h-\[calc\(100dvh-var\(--pb-sticky-top\,0px\)-var\(--pb-sticky-bottom\,0px\)\)\]{max-height:calc(100dvh - var(--pb-sticky-top,0px) - var(--pb-sticky-bottom,0px))}.md\:min-h-0{min-height:0}.md\:w-full{width:100%}.md\:min-w-0{min-width:0}.md\:flex-1{flex:1}.md\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.md\:grid-cols-\[minmax\(0\,1fr\)_300px\]{grid-template-columns:minmax(0,1fr) 300px}.md\:flex-row{flex-direction:row}.md\:flex-nowrap{flex-wrap:nowrap}.md\:items-end{align-items:flex-end}.md\:items-start{align-items:flex-start}.md\:justify-between{justify-content:space-between}.md\:justify-end{justify-content:flex-end}.md\:gap-3{gap:calc(var(--spacing) * 3)}.md\:gap-4{gap:calc(var(--spacing) * 4)}.md\:gap-6{gap:calc(var(--spacing) * 6)}.md\:gap-12{gap:calc(var(--spacing) * 12)}:where(.md\: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(.md\:divide-border>:not(:last-child)){border-color:var(--border)}.md\:self-start{align-self:flex-start}.md\:overflow-y-auto{overflow-y:auto}.md\:rounded-none{border-radius:0}.md\:border-0{border-style:var(--tw-border-style);border-width:0}.md\:p-0{padding:0}.md\:px-0{padding-inline:0}.md\:px-4{padding-inline:calc(var(--spacing) * 4)}.md\:px-5{padding-inline:calc(var(--spacing) * 5)}.md\:px-6{padding-inline:calc(var(--spacing) * 6)}.md\:px-10{padding-inline:calc(var(--spacing) * 10)}.md\:px-16{padding-inline:calc(var(--spacing) * 16)}.md\:py-3{padding-block:calc(var(--spacing) * 3)}.md\:py-8{padding-block:calc(var(--spacing) * 8)}.md\:pt-8{padding-top:calc(var(--spacing) * 8)}.md\:pb-4{padding-bottom:calc(var(--spacing) * 4)}.md\:text-2xl{font-size:var(--text-2xl);line-height:var(--tw-leading,var(--text-2xl--line-height))}.md\:opacity-0{opacity:0}@media (hover:hover){.md\:group-hover\/cell\:opacity-100:is(:where(.group\/cell):hover *){opacity:1}}}@media (width>=80rem){.xl\:col-span-3{grid-column:span 3/span 3}.xl\:col-span-4{grid-column:span 4/span 4}.xl\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.xl\:grid-cols-4{grid-template-columns:repeat(4,minmax(0,1fr))}}.dark\:fill-\[\#f1f0ea\]:where([data-theme=dark],[data-theme=dark] *){fill:#f1f0ea}.dark\:fill-\[\#ff6a33\]:where([data-theme=dark],[data-theme=dark] *){fill:#ff6a33}@media (pointer:coarse){.pointer-coarse\:size-9{width:calc(var(--spacing) * 9);height:calc(var(--spacing) * 9)}.pointer-coarse\:size-11{width:calc(var(--spacing) * 11);height:calc(var(--spacing) * 11)}.pointer-coarse\:h-11{height:calc(var(--spacing) * 11)}.pointer-coarse\:min-h-11{min-height:calc(var(--spacing) * 11)}.pointer-coarse\:grid-cols-\[44px_minmax\(0\,1fr\)_88px_112px_112px_44px\]{grid-template-columns:44px minmax(0,1fr) 88px 112px 112px 44px}.pointer-coarse\:p-1\.5{padding:calc(var(--spacing) * 1.5)}.pointer-coarse\:after\:-inset-3\.5:after{content:var(--tw-content);inset:calc(var(--spacing) * -3.5)}}@media (height<=560px){.short\:mt-0{margin-top:0}.short\:mb-4{margin-bottom:calc(var(--spacing) * 4)}.short\:hidden{display:none}.short\:pt-\[calc\(1rem\+var\(--pb-safe-top\)\)\]{padding-top:calc(1rem + var(--pb-safe-top))}.short\:pb-\[calc\(1rem\+var\(--pb-safe-bottom\)\)\]{padding-bottom:calc(1rem + var(--pb-safe-bottom))}}.\[\&_\*\]\:my-0 *{margin-block:0}.\[\&_a\]\:text-primary-text a{color:var(--primary-text)}.\[\&_a\]\:underline a{text-decoration-line:underline}.\[\&_a\]\:underline-offset-2 a{text-underline-offset:2px}@media (hover:hover){.hover\:\[\&_a\]\:text-primary-hover:hover a{color:var(--primary-hover)}}.\[\&_blockquote\]\:my-2 blockquote{margin-block:calc(var(--spacing) * 2)}.\[\&_blockquote\]\:border-l-2 blockquote{border-left-style:var(--tw-border-style);border-left-width:2px}.\[\&_blockquote\]\:border-border-strong blockquote{border-color:var(--border-strong)}.\[\&_blockquote\]\:pl-3 blockquote{padding-left:calc(var(--spacing) * 3)}.\[\&_blockquote\]\:text-muted-foreground blockquote{color:var(--muted-foreground)}.\[\&_code\]\:rounded code{border-radius:.25rem}.\[\&_code\]\:bg-muted code{background-color:var(--muted)}.\[\&_code\]\:px-1 code{padding-inline:var(--spacing)}.\[\&_code\]\:py-0\.5 code{padding-block:calc(var(--spacing) * .5)}.\[\&_code\]\:font-mono code{font-family:var(--font-code,ui-monospace, "SF Mono", Menlo, Consolas, monospace)}.\[\&_code\]\:text-\[0\.9em\] code{font-size:.9em}.\[\&_del\]\:text-muted-foreground del{color:var(--muted-foreground)}.\[\&_h1\]\:mt-4 h1{margin-top:calc(var(--spacing) * 4)}.\[\&_h1\]\:mb-2 h1{margin-bottom:calc(var(--spacing) * 2)}.\[\&_h1\]\:text-lg h1{font-size:var(--text-lg);line-height:var(--tw-leading,var(--text-lg--line-height))}.\[\&_h1\]\:font-semibold h1{--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold)}.\[\&_h2\]\:mt-4 h2{margin-top:calc(var(--spacing) * 4)}.\[\&_h2\]\:mb-2 h2{margin-bottom:calc(var(--spacing) * 2)}.\[\&_h2\]\:text-base h2{font-size:var(--text-base);line-height:var(--tw-leading,var(--text-base--line-height))}.\[\&_h2\]\:font-semibold h2{--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold)}.\[\&_h3\]\:mt-3 h3{margin-top:calc(var(--spacing) * 3)}.\[\&_h3\]\:mb-1 h3{margin-bottom:var(--spacing)}.\[\&_h3\]\:font-semibold h3{--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold)}.\[\&_h4\]\:mt-3 h4{margin-top:calc(var(--spacing) * 3)}.\[\&_h4\]\:mb-1 h4{margin-bottom:var(--spacing)}.\[\&_h4\]\:font-semibold h4,.\[\&_h5\]\:font-semibold h5,.\[\&_h6\]\:font-semibold h6{--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold)}.\[\&_hr\]\:my-3 hr{margin-block:calc(var(--spacing) * 3)}.\[\&_hr\]\:border-border hr{border-color:var(--border)}.\[\&_img\]\:inline img{display:inline}.\[\&_img\]\:max-w-full img{max-width:100%}.\[\&_img\]\:rounded img{border-radius:.25rem}.\[\&_li\:has\(\>input\)\]\:list-none li:has(>input){list-style-type:none}.\[\&_li\>input\]\:mr-1\.5 li>input{margin-right:calc(var(--spacing) * 1.5)}.\[\&_li\>input\]\:-ml-5 li>input{margin-left:calc(var(--spacing) * -5)}.\[\&_li\>input\]\:align-middle li>input{vertical-align:middle}.\[\&_ol\]\:my-2 ol{margin-block:calc(var(--spacing) * 2)}.\[\&_ol\]\:list-inside ol{list-style-position:inside}.\[\&_ol\]\:list-decimal ol{list-style-type:decimal}.\[\&_ol\]\:pl-5 ol{padding-left:calc(var(--spacing) * 5)}.\[\&_p\]\:my-2 p,.\[\&_pre\]\:my-2 pre{margin-block:calc(var(--spacing) * 2)}.\[\&_pre\]\:rounded-md pre{border-radius:var(--radius,6px)}.\[\&_pre\]\:bg-muted pre{background-color:var(--muted)}.\[\&_pre\]\:p-3 pre{padding:calc(var(--spacing) * 3)}.\[\&_pre\]\:whitespace-pre-wrap pre{white-space:pre-wrap}.\[\&_pre_code\]\:bg-transparent pre code{background-color:#0000}.\[\&_pre_code\]\:p-0 pre code{padding:0}.\[\&_table\]\:my-2 table{margin-block:calc(var(--spacing) * 2)}.\[\&_table\]\:w-full table{width:100%}.\[\&_table\]\:border-collapse table{border-collapse:collapse}.\[\&_td\]\:border td{border-style:var(--tw-border-style);border-width:1px}.\[\&_td\]\:border-border td{border-color:var(--border)}.\[\&_td\]\:px-2 td{padding-inline:calc(var(--spacing) * 2)}.\[\&_td\]\:py-1 td{padding-block:var(--spacing)}.\[\&_td\]\:\[overflow-wrap\:anywhere\] td{overflow-wrap:anywhere}.\[\&_th\]\:border th{border-style:var(--tw-border-style);border-width:1px}.\[\&_th\]\:border-border th{border-color:var(--border)}.\[\&_th\]\:bg-surface th{background-color:var(--surface)}.\[\&_th\]\:px-2 th{padding-inline:calc(var(--spacing) * 2)}.\[\&_th\]\:py-1 th{padding-block:var(--spacing)}.\[\&_th\]\:text-left th{text-align:left}.\[\&_th\]\:font-semibold th{--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold)}.\[\&_ul\]\:my-2 ul{margin-block:calc(var(--spacing) * 2)}.\[\&_ul\]\:list-inside ul{list-style-position:inside}.\[\&_ul\]\:list-disc ul{list-style-type:disc}.\[\&_ul\]\:pl-5 ul{padding-left:calc(var(--spacing) * 5)}.\[\&\:\:-webkit-scrollbar\]\:hidden::-webkit-scrollbar{display:none}.\[\&\>\*\]\:min-h-10>*{min-height:calc(var(--spacing) * 10)}.\[\&\>\*\]\:min-h-11>*{min-height:calc(var(--spacing) * 11)}.\[\&\>\*\]\:w-full>*{width:100%}.\[\&\>\*\]\:shrink-0>*{flex-shrink:0}@media (width>=40rem){.sm\:\[\&\>\*\]\:min-h-0>*{min-height:0}}.\[\&\>\*\:first-child\]\:mt-0>:first-child{margin-top:0}.\[\&\>\*\:last-child\]\:mb-0>:last-child{margin-bottom:0}@media (hover:none){.\[\@media\(hover\:none\)\]\:opacity-100{opacity:1}}}@keyframes pb-shimmer{0%{opacity:1}50%{opacity:.45}to{opacity:1}}@keyframes pb-slide-in{0%{opacity:0;transform:translateY(8px)}to{opacity:1;transform:translateY(0)}}@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-pan-x{syntax:"*";inherits:false}@property --tw-pan-y{syntax:"*";inherits:false}@property --tw-pinch-zoom{syntax:"*";inherits:false}@property --tw-scroll-snap-strictness{syntax:"*";inherits:false;initial-value:proximity}@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-ordinal{syntax:"*";inherits:false}@property --tw-slashed-zero{syntax:"*";inherits:false}@property --tw-numeric-figure{syntax:"*";inherits:false}@property --tw-numeric-spacing{syntax:"*";inherits:false}@property --tw-numeric-fraction{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-content{syntax:"*";inherits:false;initial-value:""}@keyframes spin{to{transform:rotate(360deg)}}@keyframes ping{75%,to{opacity:0;transform:scale(2)}}@keyframes pulse{50%{opacity:.5}}
@@ -1,2 +0,0 @@
1
- import{r as e}from"./rolldown-runtime-hePW80VL.js";import{i as t,t as n}from"./react-CR5VJ85Q.js";import{G as r,V as i,q as a}from"./vendor-xNCj9Gc_.js";import{$ as o,A as s,B as c,Bt as l,C as u,Ct as d,D as f,Dt as p,E as m,Et as h,F as ee,Ft as te,G as ne,H as re,Ht as ie,I as ae,It as oe,J as se,K as ce,L as g,Lt as _,M as v,Mt as y,N as b,Nt as x,O as S,Ot as C,P as w,Pt as T,Q as E,R as D,Rt as O,S as k,St as A,T as j,Tt as M,U as N,V as P,Vt as F,W as I,X as L,Y as R,Z as z,_ as B,_t as V,a as H,at as U,b as W,bt as G,c as le,ct as ue,d as de,dt as K,et as fe,f as pe,ft as me,g as he,gt as ge,h as _e,ht as ve,i as ye,it as be,j as q,jt as xe,k as Se,kt as J,l as Ce,lt as we,m as Te,mt as Ee,n as De,nt as Oe,o as ke,ot as Ae,p as je,pt as Me,r as Ne,rt as Pe,s as Fe,st as Ie,t as Le,tt as Re,u as ze,ut as Be,v as Ve,vt as He,w as Ue,wt as We,x as Ge,xt as Ke,y as qe,yt as Je,z as Ye,zt as Y}from"./app-DTBU_zpR.js";import{n as Xe}from"./preload-helper-SYSsmQ2O.js";import{t as X}from"./cn-Bi0ZEjD9.js";var Z=e=>new Date(Date.parse(`${e}T00:00:00Z`)-864e5).toISOString().slice(0,10),Ze=(e,t,n=J())=>C(Date.parse(e),n)===C(Date.parse(t),n),Qe=(e,t=Date.now(),n=J())=>{let r=C(Date.parse(e),n),i=C(t,n);return r===i?q(`today`):r===Z(i)?q(`yesterday`):p(Date.parse(`${r}T00:00:00Z`))},Q=e(n(),1),$e=({tone:e=`day`,label:t})=>{let n=t??q(`newMessages`),r=X(`h-px flex-1`,e===`new`?`bg-danger`:`bg-border`);return(0,Q.jsxs)(`div`,{role:`separator`,"aria-label":n,"data-tone":e,"data-chat-divider":``,className:`flex items-center gap-3 text-xs font-medium`,children:[(0,Q.jsx)(`span`,{className:r}),(0,Q.jsx)(`span`,{className:e===`new`?`text-danger`:`text-muted-foreground`,children:n}),(0,Q.jsx)(`span`,{className:r})]})},et=({row:e,resource:t,recordKey:n,...r})=>{let i=R(),a=U(),o=t??i?.resource??a?.model.name;if(o===void 0)throw Error(`RecordLink needs a resource outside a list display or a record`);return(0,Q.jsx)(G,{to:{kind:`record`,resource:o,key:e?e.key:n},...r})},$=e(t(),1),tt=e=>{if(e?.kind!==`signed-in`)return;let{id:t,name:n}=e.user;return{id:t,...n&&{name:n}}},nt=()=>{let e=ie()?.state;return(0,$.useMemo)(()=>tt(e),[e])},rt={width:640,height:480},it=e=>e.flatMap(e=>{if(`src`in e)return[{image:{url:e.src},alt:e.alt}];let t=A(e,rt);return t?[{image:t,alt:e.alt??``}]:[]}),at=({images:e,label:t,fit:n=`cover`,swipe:r=!0,className:i})=>{let a=it(e),o=L(a.length);return(0,Q.jsxs)(`div`,{role:`group`,"aria-roledescription":`carousel`,"aria-label":t,className:X(`group/carousel relative overflow-hidden`,i),children:[(0,Q.jsx)(z,{"data-carousel-track":!0,carousel:o,swipe:r,slides:a.map(({image:e,alt:t})=>(0,Q.jsx)(we,{image:e,alt:t,loading:`lazy`,className:X(`size-full`,n===`cover`?`object-cover`:`object-contain`)}))}),(0,Q.jsx)(E,{carousel:o,count:a.length,swipe:r,reveal:`group-hover/carousel:opacity-100`,className:`inset-0`})]})},ot=({name:e,label:t,options:n,value:r,onChange:i})=>(0,Q.jsx)(`div`,{role:`radiogroup`,"aria-label":t,className:`flex flex-col gap-2`,children:n.map(t=>(0,Q.jsxs)(`label`,{className:X(`block rounded-lg border p-3 transition-colors has-[:focus-visible]:outline-2 has-[:focus-visible]:outline-offset-2 has-[:focus-visible]:outline-primary`,t.disabled?`cursor-default bg-background opacity-60`:t.value===r?`cursor-pointer border-primary bg-primary-soft`:`cursor-pointer bg-background hover:bg-surface`),children:[(0,Q.jsx)(`input`,{type:`radio`,name:e,value:t.value,checked:t.value===r,disabled:t.disabled,onChange:()=>i(t.value),className:`sr-only`}),(0,Q.jsx)(`span`,{className:X(`block font-medium`,t.value===r&&`text-primary-text`),children:t.label}),t.description&&(0,Q.jsx)(`span`,{className:`mt-0.5 block text-xs leading-snug text-muted-foreground`,children:t.description})]},t.value))}),st=(e,t,n)=>{let o=Y(),s=a(),c=[...new Set(n)].sort();return i({queryKey:F.pickedLabels(e.name,c.join(`,`)),enabled:c.length>0,placeholderData:r,queryFn:()=>Re(s,o,e,c,t)}).data??new Map},ct=e=>{let{resources:t,views:n}=te(),r=t[e.resource];if(!r)throw Error(`RecordPicker: the app has no resource named "${e.resource}"`);if(r.primaryKey.length!==1)throw Error(`RecordPicker: "${e.resource}" has a composite key, which a picker cannot name`);let i=n[e.resource],a=e.multiple?e.value:e.value===void 0?[]:[e.value],[o,s]=(0,$.useState)({}),c=st(r,i,a),l=e=>o[e]??c.get(e)??e,u=(e,t)=>s(n=>({...n,[e]:t}));if(!e.multiple){let{value:t,onChange:n}=e;return(0,Q.jsx)(K,{target:r,view:i,value:t??``,label:t===void 0?void 0:l(t),invalid:e.invalid,onChange:(e,t)=>{u(e,t),n(e)}})}let{value:d,onChange:f}=e;return(0,Q.jsxs)(`div`,{className:`flex flex-col gap-2`,children:[(0,Q.jsx)(K,{target:r,view:i,value:``,chosen:d,several:!0,invalid:e.invalid,onChange:(e,t)=>{u(e,t),f(d.includes(e)?d.filter(t=>t!==e):[...d,e])}}),d.length>0&&(0,Q.jsx)(`div`,{className:`flex flex-wrap gap-1`,children:d.map(e=>(0,Q.jsx)(ue,{label:l(e),onRemove:()=>f(d.filter(t=>t!==e))},e))})]})};export{k as ActionCard,Ae as ActionInputError,O as ApiProvider,Le as App,G as AppLink,je as AssistantDock,ne as AuthLayout,le as AvailabilityMark,x as Button,at as Carousel,$e as ChatDivider,s as ChatMessage,Se as ChatThread,ot as Choices,Ye as CodeForm,W as CompactTable,Ue as Composer,y as Dialog,B as DiffView,We as Field,Ge as FieldList,ze as Form,M as Input,fe as LogoMark,Ie as Markdown,m as MentionBox,j as MentionedText,ce as MenuSelect,Be as OtpInput,_e as PartView,et as RecordLink,ct as RecordPicker,c as ResendCodeButton,xe as ResponsiveDialog,d as Section,Xe as Segmented,u as SidePanel,o as SignInPrompt,oe as Spinner,Ce as StatusMark,he as StepList,Je as Textarea,P as allowDelayMs,T as buttonClass,Qe as chatDayLabel,me as definePlugin,Me as defineUi,Ve as diffStats,f as emptyDraft,De as isConflict,re as isFramed,S as mentionedIds,g as mergeUi,qe as parseDiff,w as pluginApi,ee as protobaseVersion,Ze as sameChatDay,ve as statusRefreshMs,D as uiFromModule,b as useApiToken,Ke as useAppAddress,N as useArmedAfterFocus,pe as useAssistant,de as useAssistantClient,Te as useBackendData,Y as useClient,Oe as useFacets,h as useFieldControl,I as useGuardedPress,Pe as useHistogram,ye as useInbox,U as useLayoutRecord,He as useList,se as useListDisplay,H as useMarkNotificationsRead,Ee as useMembers,_ as useMeta,ge as useOwnStatus,ae as usePlugin,Fe as usePushNotifications,v as useRecord,l as useResourceClient,be as useSeries,nt as useSignedInUser,V as useStatuses,ke as useUnreadNotifications,Ne as useUpdateRecord};
2
- //# debugId=604ae72f-7feb-4f3a-b8dd-a02672f1237b