@tangle-network/agent-app 0.60.184 → 0.60.185

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 (81) hide show
  1. package/dist/agent-profiles/d1.js +3 -3
  2. package/dist/agent-profiles/index.js +3 -3
  3. package/dist/assistant/index.js +9 -9
  4. package/dist/channels/index.js +1 -1
  5. package/dist/chat-react/index.js +4 -4
  6. package/dist/chat-routes/index.js +4 -4
  7. package/dist/{chunk-YXLN4PXK.js → chunk-2RCPPOQ4.js} +2 -2
  8. package/dist/{chunk-YESFGM56.js → chunk-5IS3GCMR.js} +3 -3
  9. package/dist/{chunk-3RHAF2P5.js → chunk-A3CUVYRZ.js} +3 -3
  10. package/dist/{chunk-LN5RBVGP.js → chunk-AVP5SNIG.js} +4 -4
  11. package/dist/{chunk-LN5RBVGP.js.map → chunk-AVP5SNIG.js.map} +1 -1
  12. package/dist/{chunk-7BYY7QKC.js → chunk-E65YV7VV.js} +5 -5
  13. package/dist/{chunk-7BYY7QKC.js.map → chunk-E65YV7VV.js.map} +1 -1
  14. package/dist/chunk-EZFBGW23.js +179 -0
  15. package/dist/chunk-EZFBGW23.js.map +1 -0
  16. package/dist/{chunk-UDLA3NGY.js → chunk-GNBBY3KN.js} +3 -3
  17. package/dist/{chunk-KOTNMTHV.js → chunk-HCFVEJQL.js} +3 -3
  18. package/dist/{chunk-YGBEGBJY.js → chunk-HEPEGY6Q.js} +2 -2
  19. package/dist/{chunk-AJZ3EJB5.js → chunk-IJAXOQJU.js} +2 -2
  20. package/dist/{chunk-EQRVOMMS.js → chunk-KMIDRUUH.js} +2 -2
  21. package/dist/{chunk-BBHVV37T.js → chunk-MSAGTFN4.js} +4 -4
  22. package/dist/chunk-OBKVNZPH.js +70 -0
  23. package/dist/chunk-OBKVNZPH.js.map +1 -0
  24. package/dist/{chunk-75ZIWV4U.js → chunk-QAF7ZTO3.js} +4 -4
  25. package/dist/{chunk-TJ4DYKF2.js → chunk-XG6FODYO.js} +3 -2
  26. package/dist/chunk-XG6FODYO.js.map +1 -0
  27. package/dist/{chunk-6O2NQ7WD.js → chunk-Y2SOQOJE.js} +3 -3
  28. package/dist/integrations-react/index.js +1 -1
  29. package/dist/{mention-editor-ZJAOUDEE.js → mention-editor-NOS5R3AU.js} +2 -2
  30. package/dist/preset-cloudflare/index.js +2 -2
  31. package/dist/sandbox/index.js +4 -4
  32. package/dist/settings-react/confirm-action.d.ts +51 -0
  33. package/dist/settings-react/delete-workspace-section.d.ts +31 -0
  34. package/dist/settings-react/export-section.d.ts +26 -0
  35. package/dist/settings-react/index.d.ts +20 -0
  36. package/dist/settings-react/index.js +1438 -0
  37. package/dist/settings-react/index.js.map +1 -0
  38. package/dist/settings-react/members-section.d.ts +66 -0
  39. package/dist/settings-react/save-status.d.ts +24 -0
  40. package/dist/settings-react/setting-outcome.d.ts +33 -0
  41. package/dist/settings-react/settings-layout.d.ts +71 -0
  42. package/dist/settings-react/settings-save-bar.d.ts +26 -0
  43. package/dist/settings-react/timezone-picker.d.ts +17 -0
  44. package/dist/settings-react/use-setting-field.d.ts +70 -0
  45. package/dist/stories/settings/settings-backend.d.ts +66 -0
  46. package/dist/stories/settings/settings-demo.d.ts +16 -0
  47. package/dist/stories/settings/team-panels-demo.d.ts +21 -0
  48. package/dist/studio-react/index.js +2 -2
  49. package/dist/teams-react/components/InviteForm.d.ts +2 -2
  50. package/dist/teams-react/components/MembersPanel.d.ts +9 -5
  51. package/dist/teams-react/components/RoleSelect.d.ts +10 -8
  52. package/dist/teams-react/components/invitation-detail.d.ts +8 -0
  53. package/dist/teams-react/components/member-access.d.ts +17 -0
  54. package/dist/teams-react/contracts.d.ts +2 -0
  55. package/dist/teams-react/index.js +119 -242
  56. package/dist/teams-react/index.js.map +1 -1
  57. package/dist/theme/tokens.css +43 -2
  58. package/dist/tools/index.js +4 -4
  59. package/dist/web-react/agent-profile-editor.js +4 -4
  60. package/dist/web-react/async/index.js +1 -1
  61. package/dist/web-react/controls.d.ts +4 -5
  62. package/dist/web-react/index.js +12 -12
  63. package/dist/work-product/index.js +2 -2
  64. package/dist/workspace-export/react.d.ts +26 -0
  65. package/dist/workspace-export/react.js +6 -169
  66. package/dist/workspace-export/react.js.map +1 -1
  67. package/dist/workspace-react/index.js +3 -3
  68. package/package.json +9 -4
  69. package/dist/chunk-TJ4DYKF2.js.map +0 -1
  70. /package/dist/{chunk-YXLN4PXK.js.map → chunk-2RCPPOQ4.js.map} +0 -0
  71. /package/dist/{chunk-YESFGM56.js.map → chunk-5IS3GCMR.js.map} +0 -0
  72. /package/dist/{chunk-3RHAF2P5.js.map → chunk-A3CUVYRZ.js.map} +0 -0
  73. /package/dist/{chunk-UDLA3NGY.js.map → chunk-GNBBY3KN.js.map} +0 -0
  74. /package/dist/{chunk-KOTNMTHV.js.map → chunk-HCFVEJQL.js.map} +0 -0
  75. /package/dist/{chunk-YGBEGBJY.js.map → chunk-HEPEGY6Q.js.map} +0 -0
  76. /package/dist/{chunk-AJZ3EJB5.js.map → chunk-IJAXOQJU.js.map} +0 -0
  77. /package/dist/{chunk-EQRVOMMS.js.map → chunk-KMIDRUUH.js.map} +0 -0
  78. /package/dist/{chunk-BBHVV37T.js.map → chunk-MSAGTFN4.js.map} +0 -0
  79. /package/dist/{chunk-75ZIWV4U.js.map → chunk-QAF7ZTO3.js.map} +0 -0
  80. /package/dist/{chunk-6O2NQ7WD.js.map → chunk-Y2SOQOJE.js.map} +0 -0
  81. /package/dist/{mention-editor-ZJAOUDEE.js.map → mention-editor-NOS5R3AU.js.map} +0 -0
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/teams-react/components/InviteForm.tsx","../../src/teams-react/components/RoleSelect.tsx","../../src/teams-react/components/MembersPanel.tsx","../../src/teams-react/components/InvitationsPanel.tsx","../../src/teams-react/components/InviteAcceptPage.tsx","../../src/teams-react/components/BrandMark.tsx"],"sourcesContent":["/**\n * The invite-by-email row both team panels share: address, role, Invite. The\n * address is checked with the same rule the invitations API enforces, so\n * Invite stays disabled until the address could be delivered to, and the\n * reason appears under the field once the person leaves it or tries to send.\n * On a narrow card the role and Invite wrap below the field together instead\n * of being pushed past the card's edge.\n */\n\nimport { Button, Input } from '@tangle-network/ui/primitives'\nimport { useId, useState } from 'react'\nimport type { WorkspaceRole } from '../../teams/roles'\nimport { INVITATION_EMAIL_HINT, isInvitationEmail } from '../../teams/invitations'\nimport { RoleSelect } from './RoleSelect'\n\ninterface InviteFormProps {\n label: string\n placeholder: string\n /** Send the invite; resolve true to clear the field, false to keep it for a retry. */\n onInvite(input: { email: string; role: WorkspaceRole }): Promise<boolean>\n}\n\nexport function InviteForm({ label, placeholder, onInvite }: InviteFormProps) {\n const id = useId()\n const [email, setEmail] = useState('')\n const [role, setRole] = useState<WorkspaceRole>('editor')\n const [inviting, setInviting] = useState(false)\n // Reward early, flag late: the hint waits until the person leaves the field\n // or tries to send, then follows every keystroke until the address is valid.\n const [checked, setChecked] = useState(false)\n\n const valid = isInvitationEmail(email)\n const showHint = checked && email.trim() !== '' && !valid\n\n async function submit() {\n if (inviting) return\n if (!valid) {\n setChecked(true)\n return\n }\n setInviting(true)\n try {\n if (await onInvite({ email: email.trim(), role })) {\n setEmail('')\n setChecked(false)\n }\n } finally {\n setInviting(false)\n }\n }\n\n return (\n <div className=\"flex flex-col gap-1.5\">\n <label htmlFor={`${id}-email`} className=\"text-sm font-medium text-[var(--text-secondary)]\">{label}</label>\n <div className=\"flex flex-wrap gap-2\">\n <Input\n id={`${id}-email`}\n type=\"email\"\n inputMode=\"email\"\n autoComplete=\"off\"\n placeholder={placeholder}\n value={email}\n variant={showHint ? 'error' : undefined}\n aria-describedby={showHint ? `${id}-hint` : undefined}\n onChange={(event) => setEmail(event.target.value)}\n onBlur={() => setChecked(true)}\n onKeyDown={(event) => {\n if (event.key === 'Enter') {\n event.preventDefault()\n void submit()\n }\n }}\n className=\"min-w-[12rem] flex-1\"\n />\n <div className=\"ml-auto flex shrink-0 gap-2\">\n <RoleSelect value={role} ariaLabel=\"Invite role\" onChange={setRole} />\n <Button type=\"button\" onClick={() => void submit()} disabled={inviting || !valid}>\n {inviting ? 'Inviting…' : 'Invite'}\n </Button>\n </div>\n </div>\n {showHint && (\n <p id={`${id}-hint`} role=\"alert\" className=\"text-sm text-[var(--surface-danger-text)]\">\n {INVITATION_EMAIL_HINT}\n </p>\n )}\n </div>\n )\n}\n","/**\n * Shared role dropdown for the teams panels — the popover-listbox pattern the\n * design system requires in place of a native `<select>` (same contract as the\n * design-canvas Toolbar's SelectControl: bordered trigger, chevron glyph, and a\n * `role=\"listbox\"` panel on the L3 popover surface with click-outside /\n * Escape-to-close). Both panels assign from the same workspace-role set, so the\n * options live here too.\n */\n\nimport { useEffect, useRef, useState } from 'react'\nimport type { WorkspaceRole } from '../../teams/roles'\n\n// Each role says what it adds, so choosing one never needs a help page.\nconst ASSIGNABLE_ROLES: ReadonlyArray<{ value: WorkspaceRole; label: string; description: string }> = [\n { value: 'viewer', label: 'Viewer', description: 'Can read everything' },\n { value: 'editor', label: 'Editor', description: 'Can also chat and edit' },\n { value: 'admin', label: 'Admin', description: 'Can also manage settings and people' },\n]\n\nfunction ChevronDownGlyph({ className }: { className?: string }) {\n return (\n <svg className={className} viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2\" strokeLinecap=\"round\" strokeLinejoin=\"round\" aria-hidden>\n <path d=\"m6 9 6 6 6-6\" />\n </svg>\n )\n}\n\nexport interface RoleSelectProps {\n value: WorkspaceRole\n onChange(role: WorkspaceRole): void\n /** Accessible name (no visible label — the panels label the row). */\n ariaLabel: string\n disabled?: boolean\n}\n\nexport function RoleSelect({ value, onChange, ariaLabel, disabled }: RoleSelectProps) {\n const [open, setOpen] = useState(false)\n const ref = useRef<HTMLDivElement>(null)\n const current = ASSIGNABLE_ROLES.find((option) => option.value === value)\n\n useEffect(() => {\n if (!open) return\n function onDocPointer(event: PointerEvent) {\n if (ref.current && !ref.current.contains(event.target as Node)) setOpen(false)\n }\n function onKey(event: KeyboardEvent) {\n if (event.key === 'Escape') setOpen(false)\n }\n document.addEventListener('pointerdown', onDocPointer)\n document.addEventListener('keydown', onKey)\n return () => {\n document.removeEventListener('pointerdown', onDocPointer)\n document.removeEventListener('keydown', onKey)\n }\n }, [open])\n\n return (\n <div ref={ref} className=\"relative\">\n <button\n type=\"button\"\n disabled={disabled}\n aria-haspopup=\"listbox\"\n aria-expanded={open}\n aria-label={ariaLabel}\n onClick={() => setOpen((v) => !v)}\n className=\"flex items-center justify-between gap-1.5 rounded border border-[var(--border-default)] bg-[var(--bg-input)] px-2 py-1.5 text-sm text-[var(--text-secondary)] hover:border-[var(--brand-primary)] disabled:cursor-default disabled:opacity-40\"\n >\n <span>{current?.label ?? value}</span>\n <ChevronDownGlyph className=\"h-3 w-3 text-[var(--text-muted)]\" />\n </button>\n {open ? (\n <div\n role=\"listbox\"\n aria-label={ariaLabel}\n className=\"absolute right-0 top-full z-50 mt-1 flex w-64 flex-col rounded border border-[var(--card-edge)] bg-[hsl(var(--popover))] py-1 shadow-[var(--shadow-overlay)]\"\n >\n {ASSIGNABLE_ROLES.map((option) => (\n <button\n key={option.value}\n type=\"button\"\n role=\"option\"\n aria-selected={option.value === value}\n onClick={() => {\n onChange(option.value)\n setOpen(false)\n }}\n className={`flex flex-col px-3 py-2 text-left text-sm hover:bg-[color-mix(in_srgb,var(--brand-primary)_10%,transparent)] ${\n option.value === value ? 'text-[var(--brand-primary)]' : 'text-[var(--text-primary)]'\n }`}\n >\n <span className=\"font-medium\">{option.label}</span>\n <span className=\"text-[var(--text-muted)]\">{option.description}</span>\n </button>\n ))}\n </div>\n ) : null}\n </div>\n )\n}\n","/**\n * Workspace members panel: list members, invite by email + role, change a\n * member's role, remove a member. Fully callback-driven — the host supplies the\n * data and the async `onInvite`/`onChangeRole`/`onRemove` callbacks (backed by\n * `./teams/members-api`), so this imports no app router, fetch client, or toast.\n * Styled with the shipped Tangle Quiet tokens (`var(--*)`).\n *\n * Role gating mirrors the API: only admins/owners see role selects and the\n * remove control; inherited org owners and explicit owners are not editable\n * here (org-level concern). The invite role select offers `admin` only to\n * admins/owners.\n */\n\nimport type { WorkspaceRole } from '../../teams/roles'\nimport { hasWorkspaceRole } from '../../teams/roles'\nimport type { MemberView, MembersPanelProps } from '../contracts'\nimport { InviteForm } from './InviteForm'\nimport { RoleSelect } from './RoleSelect'\n\nexport function MembersPanel({\n members,\n currentRole,\n onInvite,\n onChangeRole,\n onRemove,\n onNotice,\n showInviteForm = true,\n}: MembersPanelProps) {\n const canManage = hasWorkspaceRole(currentRole, 'admin')\n\n function notify(kind: 'success' | 'error', message: string) {\n onNotice?.({ kind, message })\n }\n\n async function invite(input: { email: string; role: WorkspaceRole }): Promise<boolean> {\n try {\n const result = await onInvite(input)\n notify('success', result && 'inviteUrl' in result && result.inviteUrl ? `Invite link ready for ${input.email}` : `Invited ${input.email}`)\n return true\n } catch (err) {\n notify('error', err instanceof Error ? err.message : 'Failed to invite')\n return false\n }\n }\n\n async function changeRole(memberId: string, role: WorkspaceRole) {\n try {\n await onChangeRole({ memberId, role })\n notify('success', 'Role updated')\n } catch (err) {\n notify('error', err instanceof Error ? err.message : 'Failed to update role')\n }\n }\n\n async function remove(memberId: string) {\n try {\n await onRemove({ memberId })\n notify('success', 'Member removed')\n } catch (err) {\n notify('error', err instanceof Error ? err.message : 'Failed to remove member')\n }\n }\n\n return (\n <section className=\"flex flex-col gap-4\">\n <div className=\"flex items-center justify-between\">\n <h4 className=\"text-sm font-semibold text-[var(--text-primary)]\">Members</h4>\n <span className=\"text-sm text-[var(--text-muted)]\">{members.length} total</span>\n </div>\n <div className=\"flex flex-col gap-2\">\n {members.map((member) => (\n <MemberRow\n key={member.id}\n member={member}\n canManage={canManage}\n onChangeRole={changeRole}\n onRemove={remove}\n />\n ))}\n {members.length === 0 && (\n <p className=\"text-sm text-[var(--text-muted)]\">No team members yet.</p>\n )}\n </div>\n\n {canManage && showInviteForm && (\n <div className=\"border-t border-[var(--border-default)] pt-3\">\n <InviteForm label=\"Invite member\" placeholder=\"Email address\" onInvite={invite} />\n </div>\n )}\n </section>\n )\n}\n\ninterface MemberRowProps {\n member: MemberView\n canManage: boolean\n onChangeRole(memberId: string, role: WorkspaceRole): void\n onRemove(memberId: string): void\n}\n\nfunction MemberRow({ member, canManage, onChangeRole, onRemove }: MemberRowProps) {\n const pending = member.acceptedAt == null\n const label = member.name ?? member.email ?? 'Unknown'\n const initial = (member.name?.[0] ?? member.email?.[0] ?? '?').toUpperCase()\n const isOwner = member.role === 'owner'\n const editable = canManage && !isOwner && !member.inherited\n\n return (\n <div className=\"flex flex-wrap items-center justify-between gap-x-3 gap-y-2 border-b border-[var(--border-default)] py-2 last:border-0\">\n <div className=\"flex min-w-0 flex-1 items-center gap-3\">\n <div className=\"flex h-8 w-8 shrink-0 items-center justify-center rounded-full bg-[var(--bg-input)] text-sm font-semibold text-[var(--text-secondary)]\">\n {initial}\n </div>\n <div className=\"min-w-0\">\n <p className=\"flex flex-wrap items-center gap-x-2 text-sm font-medium text-[var(--text-primary)]\">\n <span className=\"min-w-0 [overflow-wrap:anywhere]\">{label}</span>\n {pending && (\n <span className=\"rounded border border-[var(--border-default)] px-1.5 py-0.5 text-sm font-medium text-[var(--text-muted)]\">\n Pending\n </span>\n )}\n </p>\n {member.name && member.email && (\n <p className=\"text-sm text-[var(--text-muted)] [overflow-wrap:anywhere]\">{member.email}</p>\n )}\n </div>\n </div>\n\n <div className=\"ml-auto flex shrink-0 items-center gap-2\">\n {isOwner ? (\n <span className=\"rounded border border-[var(--border-default)] px-2 py-0.5 text-sm text-[var(--text-secondary)]\">\n {member.inherited ? 'Org Admin' : 'Owner'}\n </span>\n ) : editable ? (\n <>\n <RoleSelect\n value={member.role}\n ariaLabel={`Role for ${label}`}\n onChange={(role) => onChangeRole(member.id, role)}\n />\n <button\n type=\"button\"\n aria-label={`Remove ${label}`}\n onClick={() => onRemove(member.id)}\n className=\"rounded px-2 py-1 text-sm text-[var(--text-danger)] hover:bg-[var(--border-default)]\"\n >\n Remove\n </button>\n </>\n ) : (\n <span className=\"rounded border border-[var(--border-default)] px-2 py-0.5 text-sm capitalize text-[var(--text-secondary)]\">\n {member.role}\n </span>\n )}\n </div>\n </div>\n )\n}\n","/**\n * Email-invitation panel: invite by email + role, and a history of every\n * invitation (pending / accepted / expired / revoked) with its email-delivery\n * status. Pending rows expose copy-link / resend / revoke. Fully callback-driven\n * — the host supplies the data and the async `onInvite` / `onResend` / `onRevoke`\n * callbacks (backed by `./teams/invitations-api`), so this imports no app router,\n * fetch client, or toast. Styled with the shipped Tangle Quiet tokens (`var(--*)`).\n *\n * Mount alongside a list-only `MembersPanel` (`showInviteForm={false}`): the\n * members panel shows accepted members, this owns the invite flow + pending list.\n */\n\nimport { useState } from 'react'\nimport { hasWorkspaceRole, type WorkspaceRole } from '../../teams/roles'\nimport type { InvitationView, InvitationsPanelProps } from '../contracts'\nimport { InviteForm } from './InviteForm'\n\nconst BADGE_BASE = 'inline-flex items-center rounded border px-2 py-0.5 text-sm font-medium'\n\n// One badge per invitation, for where it stands: green = joined, amber =\n// waiting on the invitee, red = withdrawn, muted = lapsed. Email delivery is a\n// detail of a pending invitation, so it is said in words on the line below,\n// never as a second badge beside \"Joined\".\nconst STATUS: Record<InvitationView['status'], { label: string; tone: string }> = {\n accepted: { label: 'Joined', tone: 'border-[var(--surface-success-border)] bg-[var(--surface-success-bg)] text-[var(--surface-success-text)]' },\n pending: { label: 'Pending', tone: 'border-[var(--surface-warning-border)] bg-[var(--surface-warning-bg)] text-[var(--surface-warning-text)]' },\n revoked: { label: 'Revoked', tone: 'border-[var(--surface-danger-border)] bg-[var(--surface-danger-bg)] text-[var(--surface-danger-text)]' },\n expired: { label: 'Expired', tone: 'border-[var(--border-default)] text-[var(--text-muted)]' },\n}\n\n/** Uppercase the role's first letter in JS (not CSS `capitalize`, which would\n * also hit the lowercase words that follow it on the same line). */\nfunction capitalize(text: string): string {\n return text.length === 0 ? text : text[0]!.toUpperCase() + text.slice(1)\n}\n\nfunction shortDate(value: Date | number | string): string {\n return new Date(value).toLocaleDateString('en-US', { month: 'short', day: 'numeric', year: 'numeric' })\n}\n\n/** The line under the address: the role, then only what is true of this invitation now. */\nfunction invitationDetail(invitation: InvitationView): string {\n const role = capitalize(invitation.permissions)\n switch (invitation.status) {\n case 'accepted':\n return invitation.acceptedAt ? `${role} · joined ${shortDate(invitation.acceptedAt)}` : role\n case 'pending': {\n const delivery = invitation.emailStatus === 'sent' ? 'email sent' : invitation.emailStatus === 'not_sent' ? 'email not sent yet' : null\n return [role, delivery, `expires ${shortDate(invitation.expiresAt)}`].filter(Boolean).join(' · ')\n }\n case 'expired':\n return `${role} · expired ${shortDate(invitation.expiresAt)}`\n case 'revoked':\n return role\n }\n}\n\nexport function InvitationsPanel({\n invitations,\n currentRole,\n onInvite,\n onResend,\n onRevoke,\n onCopy,\n onNotice,\n}: InvitationsPanelProps) {\n const [busyId, setBusyId] = useState<string | null>(null)\n\n const canManage = hasWorkspaceRole(currentRole, 'admin')\n\n function notify(kind: 'success' | 'error', message: string) {\n onNotice?.({ kind, message })\n }\n\n async function invite(input: { email: string; role: WorkspaceRole }): Promise<boolean> {\n try {\n await onInvite(input)\n notify('success', `Invitation sent to ${input.email}`)\n return true\n } catch (err) {\n notify('error', err instanceof Error ? err.message : 'Failed to invite')\n return false\n }\n }\n\n async function copyLink(inviteUrl: string) {\n try {\n if (onCopy) await onCopy({ inviteUrl })\n else await navigator.clipboard.writeText(inviteUrl)\n notify('success', 'Invite link copied')\n } catch (err) {\n notify('error', err instanceof Error ? err.message : 'Failed to copy link')\n }\n }\n\n async function resend(invitationId: string) {\n setBusyId(invitationId)\n try {\n await onResend({ invitationId })\n notify('success', 'Invitation resent')\n } catch (err) {\n notify('error', err instanceof Error ? err.message : 'Failed to resend invitation')\n } finally {\n setBusyId(null)\n }\n }\n\n async function revoke(invitationId: string) {\n setBusyId(invitationId)\n try {\n await onRevoke({ invitationId })\n notify('success', 'Invitation revoked')\n } catch (err) {\n notify('error', err instanceof Error ? err.message : 'Failed to revoke invitation')\n } finally {\n setBusyId(null)\n }\n }\n\n return (\n <section className=\"flex flex-col gap-4\">\n {canManage && <InviteForm label=\"Invite by email\" placeholder=\"colleague@example.com\" onInvite={invite} />}\n\n <div className=\"flex flex-col gap-2 border-t border-[var(--border-default)] pt-3\">\n <div className=\"flex items-center justify-between\">\n <h4 className=\"text-sm font-semibold text-[var(--text-primary)]\">Invitation history</h4>\n <span className=\"text-sm text-[var(--text-muted)]\">{invitations.length} total</span>\n </div>\n {invitations.length === 0 ? (\n <p className=\"text-sm text-[var(--text-muted)]\">No invitations yet.</p>\n ) : (\n invitations.map((invitation) => (\n <InvitationRow\n key={invitation.id}\n invitation={invitation}\n canManage={canManage}\n busy={busyId === invitation.id}\n onCopy={() => void copyLink(invitation.inviteUrl)}\n onResend={() => void resend(invitation.id)}\n onRevoke={() => void revoke(invitation.id)}\n />\n ))\n )}\n </div>\n </section>\n )\n}\n\ninterface InvitationRowProps {\n invitation: InvitationView\n canManage: boolean\n busy: boolean\n onCopy(): void\n onResend(): void\n onRevoke(): void\n}\n\nfunction InvitationRow({ invitation, canManage, busy, onCopy, onResend, onRevoke }: InvitationRowProps) {\n const isPending = invitation.status === 'pending'\n const status = STATUS[invitation.status]\n\n return (\n <div className=\"rounded-lg border border-[var(--border-default)] bg-[var(--bg-input)] p-3\">\n <div className=\"flex items-start justify-between gap-3\">\n <div className=\"min-w-0\">\n <p className=\"truncate text-sm font-medium text-[var(--text-primary)]\" title={invitation.email}>{invitation.email}</p>\n <p className=\"text-sm text-[var(--text-muted)]\">{invitationDetail(invitation)}</p>\n {isPending && invitation.emailStatus === 'failed' && (\n <p className=\"mt-1 text-sm text-[var(--surface-danger-text)]\">The email was not delivered. Copy the link and send it yourself.</p>\n )}\n </div>\n <span className={`${BADGE_BASE} ${status.tone} shrink-0`}>{status.label}</span>\n </div>\n {canManage && isPending && (\n <div className=\"mt-3 flex flex-wrap items-center justify-end gap-2\">\n <button\n type=\"button\"\n onClick={onCopy}\n disabled={busy}\n className=\"rounded border border-[var(--border-default)] px-2.5 py-1 text-sm text-[var(--text-secondary)] hover:text-[var(--text-primary)] disabled:opacity-50\"\n >\n Copy link\n </button>\n <button\n type=\"button\"\n onClick={onResend}\n disabled={busy}\n className=\"rounded border border-[var(--border-default)] px-2.5 py-1 text-sm text-[var(--text-secondary)] hover:text-[var(--text-primary)] disabled:opacity-50\"\n >\n {busy ? 'Working…' : 'Resend'}\n </button>\n <button\n type=\"button\"\n onClick={onRevoke}\n disabled={busy}\n className=\"rounded px-2.5 py-1 text-sm text-[var(--text-danger)] hover:bg-[var(--border-default)] disabled:opacity-50\"\n >\n Revoke\n </button>\n </div>\n )}\n </div>\n )\n}\n","/**\n * Invite-accept surface for `/invite/:token`. Renders the invite state (valid /\n * invalid / already-accepted), handles the signed-out path (sign in or create\n * an account with the invited email), the email-mismatch path (switch account),\n * and the accept action. Callback-driven: the host supplies the resolved\n * `details` and `onAccept` / `onNavigate`, so this imports no app router or\n * fetch client. Styled with the shipped Tangle Quiet tokens (`var(--*)`).\n */\n\nimport { useState } from 'react'\nimport type { InviteAcceptPageProps } from '../contracts'\nimport { BrandMark } from './BrandMark'\n\nexport function InviteAcceptPage({ details, onAccept, onNavigate, onResendVerification }: InviteAcceptPageProps) {\n const [accepting, setAccepting] = useState(false)\n const [acceptError, setAcceptError] = useState<string | null>(null)\n const [accepted, setAccepted] = useState(false)\n const [resendingVerification, setResendingVerification] = useState(false)\n const [verificationSent, setVerificationSent] = useState(false)\n\n if (details.status === 'invalid') {\n return (\n <Shell title=\"Invalid invitation\" body=\"This link is invalid or already used. Ask the workspace admin to send a new one.\">\n <PrimaryButton onClick={() => onNavigate({ kind: 'sign-in' })}>Go to sign in</PrimaryButton>\n </Shell>\n )\n }\n\n if (details.status === 'already-accepted') {\n return (\n <Shell title=\"Already accepted\" body=\"This invitation has already been accepted.\">\n <PrimaryButton onClick={() => onNavigate({ kind: 'open-app' })}>Open workspace</PrimaryButton>\n </Shell>\n )\n }\n\n if (details.status === 'expired') {\n return (\n <Shell title=\"Invitation expired\" body=\"This invitation has expired. Ask the workspace admin to send a new one.\">\n <PrimaryButton onClick={() => onNavigate({ kind: 'sign-in' })}>Go to sign in</PrimaryButton>\n </Shell>\n )\n }\n\n if (details.status === 'revoked') {\n return (\n <Shell title=\"Invitation revoked\" body=\"This invitation has been revoked. Ask the workspace admin to send a new one.\">\n <PrimaryButton onClick={() => onNavigate({ kind: 'sign-in' })}>Go to sign in</PrimaryButton>\n </Shell>\n )\n }\n\n const workspaceName = details.workspaceName ?? 'a workspace'\n const inviterPrefix = details.inviterName ? `${details.inviterName} invited you` : \"You've been invited\"\n const roleSuffix = details.role ? ` as ${details.role}` : ''\n\n if (!details.currentUserEmail) {\n return (\n <Shell title=\"You've been invited\">\n <p className=\"mb-4 text-sm text-[var(--text-secondary)]\">\n {inviterPrefix} to join <span className=\"font-medium text-[var(--text-primary)]\">{workspaceName}</span>{roleSuffix}.\n </p>\n {details.inviteEmail && (\n <p className=\"mb-6 text-sm text-[var(--text-secondary)]\">\n Sign in or create an account with{' '}\n <span className=\"font-medium text-[var(--text-primary)]\">{details.inviteEmail}</span> to accept.\n </p>\n )}\n <div className=\"flex gap-2\">\n <PrimaryButton onClick={() => onNavigate({ kind: 'sign-in' })}>Sign in</PrimaryButton>\n <SecondaryButton onClick={() => onNavigate({ kind: 'sign-up' })}>Create account</SecondaryButton>\n </div>\n </Shell>\n )\n }\n\n if (accepted) {\n return (\n <Shell title=\"Welcome!\">\n <p className=\"text-sm text-[var(--text-secondary)]\">\n You've joined <span className=\"font-medium text-[var(--text-primary)]\">{workspaceName}</span>.\n </p>\n </Shell>\n )\n }\n\n const emailMismatch = Boolean(\n details.inviteEmail &&\n details.inviteEmail.toLowerCase() !== details.currentUserEmail.toLowerCase(),\n )\n const needsVerification = Boolean(details.needsEmailVerification) && !emailMismatch\n const expiryLabel = details.expiresAt != null\n ? new Date(details.expiresAt).toLocaleDateString('en-US', { month: 'short', day: 'numeric', year: 'numeric' })\n : null\n\n async function handleAccept() {\n setAccepting(true)\n setAcceptError(null)\n try {\n const result = await onAccept()\n setAccepted(true)\n if (result && 'workspaceId' in result && result.workspaceId) {\n onNavigate({ kind: 'open-app', workspaceId: result.workspaceId })\n }\n } catch (err) {\n setAcceptError(err instanceof Error ? err.message : 'Failed to accept invitation')\n } finally {\n setAccepting(false)\n }\n }\n\n async function handleResendVerification() {\n if (!onResendVerification || resendingVerification) return\n setResendingVerification(true)\n try {\n await onResendVerification()\n setVerificationSent(true)\n } finally {\n setResendingVerification(false)\n }\n }\n\n return (\n <Shell title=\"Join workspace\">\n <p className=\"mb-4 text-sm text-[var(--text-secondary)]\">\n {inviterPrefix} to join <span className=\"font-medium text-[var(--text-primary)]\">{workspaceName}</span>{roleSuffix}.\n </p>\n <p className=\"mb-4 text-sm text-[var(--text-secondary)]\">\n Signed in as <span className=\"font-medium text-[var(--text-primary)]\">{details.currentUserEmail}</span>\n </p>\n {expiryLabel && (\n <p className=\"mb-4 text-xs text-[var(--text-muted)]\">This invitation expires on {expiryLabel}.</p>\n )}\n {emailMismatch && (\n <div\n role=\"alert\"\n className=\"mb-4 rounded-md border border-[var(--border-default)] px-4 py-2 text-sm text-[var(--text-warning)]\"\n >\n This invitation was sent to <span className=\"font-medium\">{details.inviteEmail}</span>. Switch to that account to accept it.\n </div>\n )}\n {needsVerification && (\n <div\n role=\"alert\"\n className=\"mb-4 rounded-md border border-[var(--border-default)] px-4 py-2 text-sm text-[var(--text-warning)]\"\n >\n {verificationSent\n ? 'Verification email sent — check your inbox, then refresh this page to accept.'\n : 'Verify your email address before you can accept this invitation.'}\n </div>\n )}\n {acceptError && (\n <p role=\"alert\" className=\"mb-4 text-sm text-[var(--text-danger)]\">{acceptError}</p>\n )}\n <div className=\"flex gap-2\">\n {emailMismatch ? (\n <PrimaryButton onClick={() => onNavigate({ kind: 'switch-account' })}>Switch account</PrimaryButton>\n ) : needsVerification ? (\n onResendVerification ? (\n <PrimaryButton\n onClick={() => void handleResendVerification()}\n disabled={resendingVerification || verificationSent}\n >\n {verificationSent ? 'Verification sent' : resendingVerification ? 'Sending…' : 'Resend verification email'}\n </PrimaryButton>\n ) : (\n <PrimaryButton onClick={() => onNavigate({ kind: 'open-app' })}>Open app</PrimaryButton>\n )\n ) : (\n <PrimaryButton onClick={() => void handleAccept()} disabled={accepting}>\n {accepting ? 'Accepting…' : 'Accept invitation'}\n </PrimaryButton>\n )}\n <SecondaryButton onClick={() => onNavigate({ kind: 'open-app' })}>Not now</SecondaryButton>\n </div>\n </Shell>\n )\n}\n\nfunction Shell({ title, body, children }: { title: string; body?: string; children: React.ReactNode }) {\n return (\n <div className=\"mx-auto flex w-full max-w-sm flex-col\">\n <span className=\"mb-4 flex items-center gap-2 text-[var(--text-muted)]\">\n <BrandMark size={22} className=\"shrink-0\" />\n <span className=\"text-xs font-semibold uppercase tracking-[0.05em]\">Tangle Teams</span>\n </span>\n <h1 className=\"mb-1 text-xl font-semibold tracking-tight text-[var(--text-primary)]\">{title}</h1>\n {body && <p className=\"mb-6 text-sm text-[var(--text-secondary)]\">{body}</p>}\n {children}\n </div>\n )\n}\n\nfunction PrimaryButton({ children, onClick, disabled }: { children: React.ReactNode; onClick(): void; disabled?: boolean }) {\n return (\n <button\n type=\"button\"\n onClick={onClick}\n disabled={disabled}\n className=\"flex-1 rounded bg-[var(--brand-primary)] px-4 py-2 text-sm text-[hsl(var(--primary-foreground))] disabled:opacity-50\"\n >\n {children}\n </button>\n )\n}\n\nfunction SecondaryButton({ children, onClick }: { children: React.ReactNode; onClick(): void }) {\n return (\n <button\n type=\"button\"\n onClick={onClick}\n className=\"flex-1 rounded border border-[var(--border-default)] px-4 py-2 text-sm text-[var(--text-secondary)] hover:text-[var(--text-primary)]\"\n >\n {children}\n </button>\n )\n}\n","/**\n * Load the canonical Tangle knot only when a teams surface renders it.\n * `/brand` imports the optional `@tangle-network/brand` peer, so a failed load\n * renders a fixed-size spacer instead of crashing the panel.\n */\n\nimport { lazy, Suspense } from 'react'\nimport type { ComponentType } from 'react'\n\nexport interface BrandMarkProps {\n size: number\n className?: string\n}\n\n/** Preserve the mark's footprint while its optional package loads or is absent. */\nfunction MarkSpacer({ size }: { size: number }) {\n return <span aria-hidden style={{ display: 'inline-block', width: size, height: size }} />\n}\n\nconst LazyKnot = lazy(async () => {\n try {\n const mod = await import('../../brand')\n return { default: mod.TangleKnot as ComponentType<BrandMarkProps> }\n } catch {\n return { default: MarkSpacer as ComponentType<BrandMarkProps> }\n }\n})\n\nexport function BrandMark({ size, className }: BrandMarkProps) {\n return (\n <Suspense fallback={<MarkSpacer size={size} />}>\n <LazyKnot size={size} className={className} />\n </Suspense>\n )\n}\n"],"mappings":"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","names":["useState","jsx","jsxs","useState","jsx","jsxs","useState","jsx","jsxs","useState","useState","jsx","jsx","jsxs","useState"]}
1
+ {"version":3,"sources":["../../src/teams-react/components/MembersPanel.tsx","../../src/teams-react/components/InviteForm.tsx","../../src/teams-react/components/InvitationsPanel.tsx","../../src/teams-react/components/InviteAcceptPage.tsx","../../src/teams-react/components/BrandMark.tsx"],"sourcesContent":["/**\n * Workspace members panel: list members, invite by email + role, change a\n * member's role, remove a member. Fully callback-driven — the host supplies the\n * data and the async `onInvite`/`onChangeRole`/`onRemove` callbacks (backed by\n * `./teams/members-api`), so this imports no app router, fetch client, or toast.\n * Styled with the shipped Tangle Quiet tokens (`var(--*)`).\n *\n * Role gating mirrors the API and `MembersSection` (`canManageMember`): only\n * admins/owners see role selects and the remove control; inherited org owners,\n * explicit owners and the viewer's own row are not editable here. The invite\n * role select offers `admin` only to admins/owners.\n *\n * Below 36rem of panel a member's role picker takes its own full-width line\n * under the name, and Remove stays beside the name, so the longest capability\n * name fits and nothing passes the card's edge.\n */\n\nimport { Button, Heading } from '@tangle-network/ui/primitives'\nimport type { WorkspaceRole } from '../../teams/roles'\nimport { hasWorkspaceRole } from '../../teams/roles'\nimport type { MemberView, MembersPanelProps } from '../contracts'\nimport { InviteForm } from './InviteForm'\nimport { canManageMember, isCurrentMember, memberRoleLabel } from './member-access'\nimport { RoleSelect } from './RoleSelect'\n\nexport function MembersPanel({\n members,\n currentRole,\n currentUserId,\n onInvite,\n onChangeRole,\n onRemove,\n onNotice,\n showInviteForm = true,\n}: MembersPanelProps) {\n const canManage = hasWorkspaceRole(currentRole, 'admin')\n\n function notify(kind: 'success' | 'error', message: string) {\n onNotice?.({ kind, message })\n }\n\n async function invite(input: { email: string; role: WorkspaceRole }): Promise<boolean> {\n try {\n const result = await onInvite(input)\n notify('success', result && 'inviteUrl' in result && result.inviteUrl ? `Invite link ready for ${input.email}` : `Invited ${input.email}`)\n return true\n } catch (err) {\n notify('error', err instanceof Error ? err.message : 'Failed to invite')\n return false\n }\n }\n\n async function changeRole(memberId: string, role: WorkspaceRole) {\n try {\n await onChangeRole({ memberId, role })\n notify('success', 'Role updated')\n } catch (err) {\n notify('error', err instanceof Error ? err.message : 'Failed to update role')\n }\n }\n\n async function remove(memberId: string) {\n try {\n await onRemove({ memberId })\n notify('success', 'Member removed')\n } catch (err) {\n notify('error', err instanceof Error ? err.message : 'Failed to remove member')\n }\n }\n\n return (\n <section className=\"@container/members flex flex-col gap-4\">\n <div className=\"flex items-center justify-between\">\n <Heading as=\"h4\" variant=\"subsection\">Members</Heading>\n <span className=\"text-sm text-[var(--text-muted)]\">{members.length} total</span>\n </div>\n <div className=\"flex flex-col gap-2\">\n {members.map((member) => (\n <MemberRow\n key={member.id}\n member={member}\n editable={canManageMember(member, currentRole, currentUserId)}\n self={isCurrentMember(member, currentUserId)}\n onChangeRole={changeRole}\n onRemove={remove}\n />\n ))}\n {members.length === 0 && (\n <p className=\"text-sm text-[var(--text-muted)]\">No team members yet.</p>\n )}\n </div>\n\n {canManage && showInviteForm && (\n <div className=\"border-t border-[var(--border-default)] pt-3\">\n <InviteForm label=\"Invite member\" placeholder=\"Email address\" onInvite={invite} />\n </div>\n )}\n </section>\n )\n}\n\ninterface MemberRowProps {\n member: MemberView\n editable: boolean\n self: boolean\n onChangeRole(memberId: string, role: WorkspaceRole): void\n onRemove(memberId: string): void\n}\n\nfunction MemberRow({ member, editable, self, onChangeRole, onRemove }: MemberRowProps) {\n const pending = member.acceptedAt == null\n const label = member.name ?? member.email ?? 'Unknown'\n const initial = (member.name?.[0] ?? member.email?.[0] ?? '?').toUpperCase()\n\n return (\n <div className=\"flex flex-wrap items-center gap-x-3 gap-y-2 border-b border-[var(--border-default)] py-2 last:border-0\">\n <div className=\"flex min-w-0 flex-1 items-center gap-3 @max-[36rem]/members:basis-40\">\n <div className=\"flex h-8 w-8 shrink-0 items-center justify-center rounded-full bg-[var(--bg-input)] text-sm font-semibold text-[var(--text-secondary)]\">\n {initial}\n </div>\n <div className=\"min-w-0\">\n <p className=\"flex flex-wrap items-center gap-x-2 text-sm font-medium text-[var(--text-primary)]\">\n <span className=\"min-w-0 [overflow-wrap:anywhere]\">{label}{self && <span className=\"font-normal text-[var(--text-muted)]\"> (you)</span>}</span>\n {pending && (\n <span className=\"rounded border border-[var(--border-default)] px-1.5 py-0.5 text-sm font-medium text-[var(--text-muted)]\">\n Pending\n </span>\n )}\n </p>\n {member.name && member.email && (\n <p className=\"text-sm text-[var(--text-muted)] [overflow-wrap:anywhere]\">{member.email}</p>\n )}\n </div>\n </div>\n\n {editable ? (\n <>\n <div className=\"w-72 shrink-0 @max-[36rem]/members:order-last @max-[36rem]/members:w-full\">\n <RoleSelect\n value={member.role}\n ariaLabel={`Role for ${label}`}\n onChange={(role) => onChangeRole(member.id, role)}\n />\n </div>\n <Button type=\"button\" variant=\"destructive-outline\" aria-label={`Remove ${label}`} onClick={() => onRemove(member.id)}>\n Remove\n </Button>\n </>\n ) : (\n <span className=\"ml-auto rounded border border-[var(--border-default)] px-2 py-0.5 text-sm text-[var(--text-secondary)]\">\n {memberRoleLabel(member)}\n </span>\n )}\n </div>\n )\n}\n","/**\n * The invite-by-email row both team panels share: address, role, Invite. The\n * address is checked with the same rule the invitations API enforces, so\n * Invite stays disabled until the address could be delivered to, and the\n * reason appears under the field once the person leaves it or tries to send.\n * On a narrow card the field, the role and Invite stack, the role at full\n * width so its longest name fits, and nothing passes the card's edge.\n */\n\nimport { Button, Input } from '@tangle-network/ui/primitives'\nimport { useId, useState } from 'react'\nimport type { WorkspaceRole } from '../../teams/roles'\nimport { INVITATION_EMAIL_HINT, isInvitationEmail } from '../../teams/invitations'\nimport { RoleSelect } from './RoleSelect'\n\ninterface InviteFormProps {\n label: string\n placeholder: string\n /** Send the invite; resolve true to clear the field, false to keep it for a retry. */\n onInvite(input: { email: string; role: WorkspaceRole }): Promise<boolean>\n}\n\nexport function InviteForm({ label, placeholder, onInvite }: InviteFormProps) {\n const id = useId()\n const [email, setEmail] = useState('')\n const [role, setRole] = useState<WorkspaceRole>('editor')\n const [inviting, setInviting] = useState(false)\n // Reward early, flag late: the hint waits until the person leaves the field\n // or tries to send, then follows every keystroke until the address is valid.\n const [checked, setChecked] = useState(false)\n\n const valid = isInvitationEmail(email)\n const showHint = checked && email.trim() !== '' && !valid\n\n async function submit() {\n if (inviting) return\n if (!valid) {\n setChecked(true)\n return\n }\n setInviting(true)\n try {\n if (await onInvite({ email: email.trim(), role })) {\n setEmail('')\n setChecked(false)\n }\n } finally {\n setInviting(false)\n }\n }\n\n return (\n <div className=\"@container/invite flex flex-col gap-1.5\">\n <label htmlFor={`${id}-email`} className=\"text-sm font-medium text-[var(--text-secondary)]\">{label}</label>\n <div className=\"flex flex-wrap gap-2\">\n <Input\n id={`${id}-email`}\n type=\"email\"\n inputMode=\"email\"\n autoComplete=\"off\"\n placeholder={placeholder}\n value={email}\n variant={showHint ? 'error' : undefined}\n aria-describedby={showHint ? `${id}-hint` : undefined}\n onChange={(event) => setEmail(event.target.value)}\n onBlur={() => setChecked(true)}\n onKeyDown={(event) => {\n if (event.key === 'Enter') {\n event.preventDefault()\n void submit()\n }\n }}\n className=\"min-w-[12rem] flex-1\"\n />\n <div className=\"w-72 shrink-0 @max-[36rem]/invite:w-full\">\n <RoleSelect value={role} ariaLabel=\"Invite role\" onChange={setRole} />\n </div>\n <Button type=\"button\" className=\"ml-auto\" onClick={() => void submit()} disabled={inviting || !valid}>\n {inviting ? 'Inviting…' : 'Invite'}\n </Button>\n </div>\n {showHint && (\n <p id={`${id}-hint`} role=\"alert\" className=\"text-sm text-[var(--surface-danger-text)]\">\n {INVITATION_EMAIL_HINT}\n </p>\n )}\n </div>\n )\n}\n","/**\n * Email-invitation panel: invite by email + role, and a history of every\n * invitation (pending / accepted / expired / revoked) with its email-delivery\n * status. Pending rows expose copy-link / resend / revoke. Fully callback-driven\n * — the host supplies the data and the async `onInvite` / `onResend` / `onRevoke`\n * callbacks (backed by `./teams/invitations-api`), so this imports no app router,\n * fetch client, or toast. Styled with the shipped Tangle Quiet tokens (`var(--*)`).\n *\n * Mount alongside a list-only `MembersPanel` (`showInviteForm={false}`): the\n * members panel shows accepted members, this owns the invite flow + pending list.\n */\n\nimport { Button, Heading } from '@tangle-network/ui/primitives'\nimport { useState } from 'react'\nimport { hasWorkspaceRole, type WorkspaceRole } from '../../teams/roles'\nimport type { InvitationView, InvitationsPanelProps } from '../contracts'\nimport { invitationDetail } from './invitation-detail'\nimport { InviteForm } from './InviteForm'\n\nconst BADGE_BASE = 'inline-flex items-center rounded border px-2 py-0.5 text-sm font-medium'\n\n// One badge per invitation, for where it stands: green = joined, amber =\n// waiting on the invitee, red = withdrawn, muted = lapsed. Email delivery is a\n// detail of a pending invitation, so it is said in words on the line below,\n// never as a second badge beside \"Joined\".\nconst STATUS: Record<InvitationView['status'], { label: string; tone: string }> = {\n accepted: { label: 'Joined', tone: 'border-[var(--surface-success-border)] bg-[var(--surface-success-bg)] text-[var(--surface-success-text)]' },\n pending: { label: 'Pending', tone: 'border-[var(--surface-warning-border)] bg-[var(--surface-warning-bg)] text-[var(--surface-warning-text)]' },\n revoked: { label: 'Revoked', tone: 'border-[var(--surface-danger-border)] bg-[var(--surface-danger-bg)] text-[var(--surface-danger-text)]' },\n expired: { label: 'Expired', tone: 'border-[var(--border-default)] text-[var(--text-muted)]' },\n}\n\nexport function InvitationsPanel({\n invitations,\n currentRole,\n onInvite,\n onResend,\n onRevoke,\n onCopy,\n onNotice,\n}: InvitationsPanelProps) {\n const [busyId, setBusyId] = useState<string | null>(null)\n\n const canManage = hasWorkspaceRole(currentRole, 'admin')\n\n function notify(kind: 'success' | 'error', message: string) {\n onNotice?.({ kind, message })\n }\n\n async function invite(input: { email: string; role: WorkspaceRole }): Promise<boolean> {\n try {\n await onInvite(input)\n notify('success', `Invitation sent to ${input.email}`)\n return true\n } catch (err) {\n notify('error', err instanceof Error ? err.message : 'Failed to invite')\n return false\n }\n }\n\n async function copyLink(inviteUrl: string) {\n try {\n if (onCopy) await onCopy({ inviteUrl })\n else await navigator.clipboard.writeText(inviteUrl)\n notify('success', 'Invite link copied')\n } catch (err) {\n notify('error', err instanceof Error ? err.message : 'Failed to copy link')\n }\n }\n\n async function resend(invitationId: string) {\n setBusyId(invitationId)\n try {\n await onResend({ invitationId })\n notify('success', 'Invitation resent')\n } catch (err) {\n notify('error', err instanceof Error ? err.message : 'Failed to resend invitation')\n } finally {\n setBusyId(null)\n }\n }\n\n async function revoke(invitationId: string) {\n setBusyId(invitationId)\n try {\n await onRevoke({ invitationId })\n notify('success', 'Invitation revoked')\n } catch (err) {\n notify('error', err instanceof Error ? err.message : 'Failed to revoke invitation')\n } finally {\n setBusyId(null)\n }\n }\n\n return (\n <section className=\"flex flex-col gap-4\">\n {canManage && <InviteForm label=\"Invite by email\" placeholder=\"colleague@example.com\" onInvite={invite} />}\n\n <div className=\"flex flex-col gap-2 border-t border-[var(--border-default)] pt-3\">\n <div className=\"flex items-center justify-between\">\n <Heading as=\"h4\" variant=\"subsection\">Invitation history</Heading>\n <span className=\"text-sm text-[var(--text-muted)]\">{invitations.length} total</span>\n </div>\n {invitations.length === 0 ? (\n <p className=\"text-sm text-[var(--text-muted)]\">No invitations yet.</p>\n ) : (\n invitations.map((invitation) => (\n <InvitationRow\n key={invitation.id}\n invitation={invitation}\n canManage={canManage}\n busy={busyId === invitation.id}\n onCopy={() => void copyLink(invitation.inviteUrl)}\n onResend={() => void resend(invitation.id)}\n onRevoke={() => void revoke(invitation.id)}\n />\n ))\n )}\n </div>\n </section>\n )\n}\n\ninterface InvitationRowProps {\n invitation: InvitationView\n canManage: boolean\n busy: boolean\n onCopy(): void\n onResend(): void\n onRevoke(): void\n}\n\nfunction InvitationRow({ invitation, canManage, busy, onCopy, onResend, onRevoke }: InvitationRowProps) {\n const isPending = invitation.status === 'pending'\n const status = STATUS[invitation.status]\n\n return (\n <div className=\"rounded-lg border border-[var(--border-default)] bg-[var(--bg-input)] p-3\">\n <div className=\"flex items-start justify-between gap-3\">\n <div className=\"min-w-0\">\n <p className=\"truncate text-sm font-medium text-[var(--text-primary)]\" title={invitation.email}>{invitation.email}</p>\n <p className=\"text-sm text-[var(--text-muted)]\">{invitationDetail(invitation)}</p>\n {isPending && invitation.emailStatus === 'failed' && (\n <p className=\"mt-1 text-sm text-[var(--surface-danger-text)]\">The email was not delivered. Copy the link and send it yourself.</p>\n )}\n </div>\n <span className={`${BADGE_BASE} ${status.tone} shrink-0`}>{status.label}</span>\n </div>\n {canManage && isPending && (\n <div className=\"mt-3 flex flex-wrap items-center justify-end gap-2\">\n <Button type=\"button\" variant=\"outline\" onClick={onCopy} disabled={busy}>Copy link</Button>\n <Button type=\"button\" variant=\"outline\" onClick={onResend} disabled={busy}>{busy ? 'Working…' : 'Resend'}</Button>\n <Button type=\"button\" variant=\"destructive-outline\" onClick={onRevoke} disabled={busy}>Revoke</Button>\n </div>\n )}\n </div>\n )\n}\n","/**\n * Invite-accept surface for `/invite/:token`. Renders the invite state (valid /\n * invalid / already-accepted), handles the signed-out path (sign in or create\n * an account with the invited email), the email-mismatch path (switch account),\n * and the accept action. Callback-driven: the host supplies the resolved\n * `details` and `onAccept` / `onNavigate`, so this imports no app router or\n * fetch client. Styled with the shipped Tangle Quiet tokens (`var(--*)`).\n */\n\nimport { useState } from 'react'\nimport type { InviteAcceptPageProps } from '../contracts'\nimport { BrandMark } from './BrandMark'\n\nexport function InviteAcceptPage({ details, onAccept, onNavigate, onResendVerification }: InviteAcceptPageProps) {\n const [accepting, setAccepting] = useState(false)\n const [acceptError, setAcceptError] = useState<string | null>(null)\n const [accepted, setAccepted] = useState(false)\n const [resendingVerification, setResendingVerification] = useState(false)\n const [verificationSent, setVerificationSent] = useState(false)\n\n if (details.status === 'invalid') {\n return (\n <Shell title=\"Invalid invitation\" body=\"This link is invalid or already used. Ask the workspace admin to send a new one.\">\n <PrimaryButton onClick={() => onNavigate({ kind: 'sign-in' })}>Go to sign in</PrimaryButton>\n </Shell>\n )\n }\n\n if (details.status === 'already-accepted') {\n return (\n <Shell title=\"Already accepted\" body=\"This invitation has already been accepted.\">\n <PrimaryButton onClick={() => onNavigate({ kind: 'open-app' })}>Open workspace</PrimaryButton>\n </Shell>\n )\n }\n\n if (details.status === 'expired') {\n return (\n <Shell title=\"Invitation expired\" body=\"This invitation has expired. Ask the workspace admin to send a new one.\">\n <PrimaryButton onClick={() => onNavigate({ kind: 'sign-in' })}>Go to sign in</PrimaryButton>\n </Shell>\n )\n }\n\n if (details.status === 'revoked') {\n return (\n <Shell title=\"Invitation revoked\" body=\"This invitation has been revoked. Ask the workspace admin to send a new one.\">\n <PrimaryButton onClick={() => onNavigate({ kind: 'sign-in' })}>Go to sign in</PrimaryButton>\n </Shell>\n )\n }\n\n const workspaceName = details.workspaceName ?? 'a workspace'\n const inviterPrefix = details.inviterName ? `${details.inviterName} invited you` : \"You've been invited\"\n const roleSuffix = details.role ? ` as ${details.role}` : ''\n\n if (!details.currentUserEmail) {\n return (\n <Shell title=\"You've been invited\">\n <p className=\"mb-4 text-sm text-[var(--text-secondary)]\">\n {inviterPrefix} to join <span className=\"font-medium text-[var(--text-primary)]\">{workspaceName}</span>{roleSuffix}.\n </p>\n {details.inviteEmail && (\n <p className=\"mb-6 text-sm text-[var(--text-secondary)]\">\n Sign in or create an account with{' '}\n <span className=\"font-medium text-[var(--text-primary)]\">{details.inviteEmail}</span> to accept.\n </p>\n )}\n <div className=\"flex gap-2\">\n <PrimaryButton onClick={() => onNavigate({ kind: 'sign-in' })}>Sign in</PrimaryButton>\n <SecondaryButton onClick={() => onNavigate({ kind: 'sign-up' })}>Create account</SecondaryButton>\n </div>\n </Shell>\n )\n }\n\n if (accepted) {\n return (\n <Shell title=\"Welcome!\">\n <p className=\"text-sm text-[var(--text-secondary)]\">\n You've joined <span className=\"font-medium text-[var(--text-primary)]\">{workspaceName}</span>.\n </p>\n </Shell>\n )\n }\n\n const emailMismatch = Boolean(\n details.inviteEmail &&\n details.inviteEmail.toLowerCase() !== details.currentUserEmail.toLowerCase(),\n )\n const needsVerification = Boolean(details.needsEmailVerification) && !emailMismatch\n const expiryLabel = details.expiresAt != null\n ? new Date(details.expiresAt).toLocaleDateString('en-US', { month: 'short', day: 'numeric', year: 'numeric' })\n : null\n\n async function handleAccept() {\n setAccepting(true)\n setAcceptError(null)\n try {\n const result = await onAccept()\n setAccepted(true)\n if (result && 'workspaceId' in result && result.workspaceId) {\n onNavigate({ kind: 'open-app', workspaceId: result.workspaceId })\n }\n } catch (err) {\n setAcceptError(err instanceof Error ? err.message : 'Failed to accept invitation')\n } finally {\n setAccepting(false)\n }\n }\n\n async function handleResendVerification() {\n if (!onResendVerification || resendingVerification) return\n setResendingVerification(true)\n try {\n await onResendVerification()\n setVerificationSent(true)\n } finally {\n setResendingVerification(false)\n }\n }\n\n return (\n <Shell title=\"Join workspace\">\n <p className=\"mb-4 text-sm text-[var(--text-secondary)]\">\n {inviterPrefix} to join <span className=\"font-medium text-[var(--text-primary)]\">{workspaceName}</span>{roleSuffix}.\n </p>\n <p className=\"mb-4 text-sm text-[var(--text-secondary)]\">\n Signed in as <span className=\"font-medium text-[var(--text-primary)]\">{details.currentUserEmail}</span>\n </p>\n {expiryLabel && (\n <p className=\"mb-4 text-xs text-[var(--text-muted)]\">This invitation expires on {expiryLabel}.</p>\n )}\n {emailMismatch && (\n <div\n role=\"alert\"\n className=\"mb-4 rounded-md border border-[var(--border-default)] px-4 py-2 text-sm text-[var(--text-warning)]\"\n >\n This invitation was sent to <span className=\"font-medium\">{details.inviteEmail}</span>. Switch to that account to accept it.\n </div>\n )}\n {needsVerification && (\n <div\n role=\"alert\"\n className=\"mb-4 rounded-md border border-[var(--border-default)] px-4 py-2 text-sm text-[var(--text-warning)]\"\n >\n {verificationSent\n ? 'Verification email sent — check your inbox, then refresh this page to accept.'\n : 'Verify your email address before you can accept this invitation.'}\n </div>\n )}\n {acceptError && (\n <p role=\"alert\" className=\"mb-4 text-sm text-[var(--text-danger)]\">{acceptError}</p>\n )}\n <div className=\"flex gap-2\">\n {emailMismatch ? (\n <PrimaryButton onClick={() => onNavigate({ kind: 'switch-account' })}>Switch account</PrimaryButton>\n ) : needsVerification ? (\n onResendVerification ? (\n <PrimaryButton\n onClick={() => void handleResendVerification()}\n disabled={resendingVerification || verificationSent}\n >\n {verificationSent ? 'Verification sent' : resendingVerification ? 'Sending…' : 'Resend verification email'}\n </PrimaryButton>\n ) : (\n <PrimaryButton onClick={() => onNavigate({ kind: 'open-app' })}>Open app</PrimaryButton>\n )\n ) : (\n <PrimaryButton onClick={() => void handleAccept()} disabled={accepting}>\n {accepting ? 'Accepting…' : 'Accept invitation'}\n </PrimaryButton>\n )}\n <SecondaryButton onClick={() => onNavigate({ kind: 'open-app' })}>Not now</SecondaryButton>\n </div>\n </Shell>\n )\n}\n\nfunction Shell({ title, body, children }: { title: string; body?: string; children: React.ReactNode }) {\n return (\n <div className=\"mx-auto flex w-full max-w-sm flex-col\">\n <span className=\"mb-4 flex items-center gap-2 text-[var(--text-muted)]\">\n <BrandMark size={22} className=\"shrink-0\" />\n <span className=\"text-xs font-semibold uppercase tracking-[0.05em]\">Tangle Teams</span>\n </span>\n <h1 className=\"mb-1 text-xl font-semibold tracking-tight text-[var(--text-primary)]\">{title}</h1>\n {body && <p className=\"mb-6 text-sm text-[var(--text-secondary)]\">{body}</p>}\n {children}\n </div>\n )\n}\n\nfunction PrimaryButton({ children, onClick, disabled }: { children: React.ReactNode; onClick(): void; disabled?: boolean }) {\n return (\n <button\n type=\"button\"\n onClick={onClick}\n disabled={disabled}\n className=\"flex-1 rounded bg-[var(--brand-primary)] px-4 py-2 text-sm text-[hsl(var(--primary-foreground))] disabled:opacity-50\"\n >\n {children}\n </button>\n )\n}\n\nfunction SecondaryButton({ children, onClick }: { children: React.ReactNode; onClick(): void }) {\n return (\n <button\n type=\"button\"\n onClick={onClick}\n className=\"flex-1 rounded border border-[var(--border-default)] px-4 py-2 text-sm text-[var(--text-secondary)] hover:text-[var(--text-primary)]\"\n >\n {children}\n </button>\n )\n}\n","/**\n * Load the canonical Tangle knot only when a teams surface renders it.\n * `/brand` imports the optional `@tangle-network/brand` peer, so a failed load\n * renders a fixed-size spacer instead of crashing the panel.\n */\n\nimport { lazy, Suspense } from 'react'\nimport type { ComponentType } from 'react'\n\nexport interface BrandMarkProps {\n size: number\n className?: string\n}\n\n/** Preserve the mark's footprint while its optional package loads or is absent. */\nfunction MarkSpacer({ size }: { size: number }) {\n return <span aria-hidden style={{ display: 'inline-block', width: size, height: size }} />\n}\n\nconst LazyKnot = lazy(async () => {\n try {\n const mod = await import('../../brand')\n return { default: mod.TangleKnot as ComponentType<BrandMarkProps> }\n } catch {\n return { default: MarkSpacer as ComponentType<BrandMarkProps> }\n }\n})\n\nexport function BrandMark({ size, className }: BrandMarkProps) {\n return (\n <Suspense fallback={<MarkSpacer size={size} />}>\n <LazyKnot size={size} className={className} />\n </Suspense>\n )\n}\n"],"mappings":";;;;;;;;;;;;;;;;AAiBA,SAAS,UAAAA,SAAQ,eAAe;;;ACRhC,SAAS,QAAQ,aAAa;AAC9B,SAAS,OAAO,gBAAgB;AA2C1B,cACA,YADA;AA/BC,SAAS,WAAW,EAAE,OAAO,aAAa,SAAS,GAAoB;AAC5E,QAAM,KAAK,MAAM;AACjB,QAAM,CAAC,OAAO,QAAQ,IAAI,SAAS,EAAE;AACrC,QAAM,CAAC,MAAM,OAAO,IAAI,SAAwB,QAAQ;AACxD,QAAM,CAAC,UAAU,WAAW,IAAI,SAAS,KAAK;AAG9C,QAAM,CAAC,SAAS,UAAU,IAAI,SAAS,KAAK;AAE5C,QAAM,QAAQ,kBAAkB,KAAK;AACrC,QAAM,WAAW,WAAW,MAAM,KAAK,MAAM,MAAM,CAAC;AAEpD,iBAAe,SAAS;AACtB,QAAI,SAAU;AACd,QAAI,CAAC,OAAO;AACV,iBAAW,IAAI;AACf;AAAA,IACF;AACA,gBAAY,IAAI;AAChB,QAAI;AACF,UAAI,MAAM,SAAS,EAAE,OAAO,MAAM,KAAK,GAAG,KAAK,CAAC,GAAG;AACjD,iBAAS,EAAE;AACX,mBAAW,KAAK;AAAA,MAClB;AAAA,IACF,UAAE;AACA,kBAAY,KAAK;AAAA,IACnB;AAAA,EACF;AAEA,SACE,qBAAC,SAAI,WAAU,2CACb;AAAA,wBAAC,WAAM,SAAS,GAAG,EAAE,UAAU,WAAU,oDAAoD,iBAAM;AAAA,IACnG,qBAAC,SAAI,WAAU,wBACb;AAAA;AAAA,QAAC;AAAA;AAAA,UACC,IAAI,GAAG,EAAE;AAAA,UACT,MAAK;AAAA,UACL,WAAU;AAAA,UACV,cAAa;AAAA,UACb;AAAA,UACA,OAAO;AAAA,UACP,SAAS,WAAW,UAAU;AAAA,UAC9B,oBAAkB,WAAW,GAAG,EAAE,UAAU;AAAA,UAC5C,UAAU,CAAC,UAAU,SAAS,MAAM,OAAO,KAAK;AAAA,UAChD,QAAQ,MAAM,WAAW,IAAI;AAAA,UAC7B,WAAW,CAAC,UAAU;AACpB,gBAAI,MAAM,QAAQ,SAAS;AACzB,oBAAM,eAAe;AACrB,mBAAK,OAAO;AAAA,YACd;AAAA,UACF;AAAA,UACA,WAAU;AAAA;AAAA,MACZ;AAAA,MACA,oBAAC,SAAI,WAAU,4CACb,8BAAC,cAAW,OAAO,MAAM,WAAU,eAAc,UAAU,SAAS,GACtE;AAAA,MACA,oBAAC,UAAO,MAAK,UAAS,WAAU,WAAU,SAAS,MAAM,KAAK,OAAO,GAAG,UAAU,YAAY,CAAC,OAC5F,qBAAW,mBAAc,UAC5B;AAAA,OACF;AAAA,IACC,YACC,oBAAC,OAAE,IAAI,GAAG,EAAE,SAAS,MAAK,SAAQ,WAAU,6CACzC,iCACH;AAAA,KAEJ;AAEJ;;;ADfQ,SA+DA,UA/DA,OAAAC,MACA,QAAAC,aADA;AAhDD,SAAS,aAAa;AAAA,EAC3B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,iBAAiB;AACnB,GAAsB;AACpB,QAAM,YAAY,iBAAiB,aAAa,OAAO;AAEvD,WAAS,OAAO,MAA2B,SAAiB;AAC1D,eAAW,EAAE,MAAM,QAAQ,CAAC;AAAA,EAC9B;AAEA,iBAAe,OAAO,OAAiE;AACrF,QAAI;AACF,YAAM,SAAS,MAAM,SAAS,KAAK;AACnC,aAAO,WAAW,UAAU,eAAe,UAAU,OAAO,YAAY,yBAAyB,MAAM,KAAK,KAAK,WAAW,MAAM,KAAK,EAAE;AACzI,aAAO;AAAA,IACT,SAAS,KAAK;AACZ,aAAO,SAAS,eAAe,QAAQ,IAAI,UAAU,kBAAkB;AACvE,aAAO;AAAA,IACT;AAAA,EACF;AAEA,iBAAe,WAAW,UAAkB,MAAqB;AAC/D,QAAI;AACF,YAAM,aAAa,EAAE,UAAU,KAAK,CAAC;AACrC,aAAO,WAAW,cAAc;AAAA,IAClC,SAAS,KAAK;AACZ,aAAO,SAAS,eAAe,QAAQ,IAAI,UAAU,uBAAuB;AAAA,IAC9E;AAAA,EACF;AAEA,iBAAe,OAAO,UAAkB;AACtC,QAAI;AACF,YAAM,SAAS,EAAE,SAAS,CAAC;AAC3B,aAAO,WAAW,gBAAgB;AAAA,IACpC,SAAS,KAAK;AACZ,aAAO,SAAS,eAAe,QAAQ,IAAI,UAAU,yBAAyB;AAAA,IAChF;AAAA,EACF;AAEA,SACE,gBAAAA,MAAC,aAAQ,WAAU,0CACjB;AAAA,oBAAAA,MAAC,SAAI,WAAU,qCACb;AAAA,sBAAAD,KAAC,WAAQ,IAAG,MAAK,SAAQ,cAAa,qBAAO;AAAA,MAC7C,gBAAAC,MAAC,UAAK,WAAU,oCAAoC;AAAA,gBAAQ;AAAA,QAAO;AAAA,SAAM;AAAA,OAC3E;AAAA,IACA,gBAAAA,MAAC,SAAI,WAAU,uBACZ;AAAA,cAAQ,IAAI,CAAC,WACZ,gBAAAD;AAAA,QAAC;AAAA;AAAA,UAEC;AAAA,UACA,UAAU,gBAAgB,QAAQ,aAAa,aAAa;AAAA,UAC5D,MAAM,gBAAgB,QAAQ,aAAa;AAAA,UAC3C,cAAc;AAAA,UACd,UAAU;AAAA;AAAA,QALL,OAAO;AAAA,MAMd,CACD;AAAA,MACA,QAAQ,WAAW,KAClB,gBAAAA,KAAC,OAAE,WAAU,oCAAmC,kCAAoB;AAAA,OAExE;AAAA,IAEC,aAAa,kBACZ,gBAAAA,KAAC,SAAI,WAAU,gDACb,0BAAAA,KAAC,cAAW,OAAM,iBAAgB,aAAY,iBAAgB,UAAU,QAAQ,GAClF;AAAA,KAEJ;AAEJ;AAUA,SAAS,UAAU,EAAE,QAAQ,UAAU,MAAM,cAAc,SAAS,GAAmB;AACrF,QAAM,UAAU,OAAO,cAAc;AACrC,QAAM,QAAQ,OAAO,QAAQ,OAAO,SAAS;AAC7C,QAAM,WAAW,OAAO,OAAO,CAAC,KAAK,OAAO,QAAQ,CAAC,KAAK,KAAK,YAAY;AAE3E,SACE,gBAAAC,MAAC,SAAI,WAAU,0GACb;AAAA,oBAAAA,MAAC,SAAI,WAAU,wEACb;AAAA,sBAAAD,KAAC,SAAI,WAAU,0IACZ,mBACH;AAAA,MACA,gBAAAC,MAAC,SAAI,WAAU,WACb;AAAA,wBAAAA,MAAC,OAAE,WAAU,sFACX;AAAA,0BAAAA,MAAC,UAAK,WAAU,oCAAoC;AAAA;AAAA,YAAO,QAAQ,gBAAAD,KAAC,UAAK,WAAU,wCAAuC,oBAAM;AAAA,aAAQ;AAAA,UACvI,WACC,gBAAAA,KAAC,UAAK,WAAU,4GAA2G,qBAE3H;AAAA,WAEJ;AAAA,QACC,OAAO,QAAQ,OAAO,SACrB,gBAAAA,KAAC,OAAE,WAAU,6DAA6D,iBAAO,OAAM;AAAA,SAE3F;AAAA,OACF;AAAA,IAEC,WACC,gBAAAC,MAAA,YACE;AAAA,sBAAAD,KAAC,SAAI,WAAU,6EACb,0BAAAA;AAAA,QAAC;AAAA;AAAA,UACC,OAAO,OAAO;AAAA,UACd,WAAW,YAAY,KAAK;AAAA,UAC5B,UAAU,CAAC,SAAS,aAAa,OAAO,IAAI,IAAI;AAAA;AAAA,MAClD,GACF;AAAA,MACA,gBAAAA,KAACE,SAAA,EAAO,MAAK,UAAS,SAAQ,uBAAsB,cAAY,UAAU,KAAK,IAAI,SAAS,MAAM,SAAS,OAAO,EAAE,GAAG,oBAEvH;AAAA,OACF,IAEA,gBAAAF,KAAC,UAAK,WAAU,0GACb,0BAAgB,MAAM,GACzB;AAAA,KAEJ;AAEJ;;;AE/IA,SAAS,UAAAG,SAAQ,WAAAC,gBAAe;AAChC,SAAS,YAAAC,iBAAgB;AAmFL,gBAAAC,MAKV,QAAAC,aALU;AA7EpB,IAAM,aAAa;AAMnB,IAAM,SAA4E;AAAA,EAChF,UAAU,EAAE,OAAO,UAAU,MAAM,2GAA2G;AAAA,EAC9I,SAAS,EAAE,OAAO,WAAW,MAAM,2GAA2G;AAAA,EAC9I,SAAS,EAAE,OAAO,WAAW,MAAM,wGAAwG;AAAA,EAC3I,SAAS,EAAE,OAAO,WAAW,MAAM,0DAA0D;AAC/F;AAEO,SAAS,iBAAiB;AAAA,EAC/B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAA0B;AACxB,QAAM,CAAC,QAAQ,SAAS,IAAIC,UAAwB,IAAI;AAExD,QAAM,YAAY,iBAAiB,aAAa,OAAO;AAEvD,WAAS,OAAO,MAA2B,SAAiB;AAC1D,eAAW,EAAE,MAAM,QAAQ,CAAC;AAAA,EAC9B;AAEA,iBAAe,OAAO,OAAiE;AACrF,QAAI;AACF,YAAM,SAAS,KAAK;AACpB,aAAO,WAAW,sBAAsB,MAAM,KAAK,EAAE;AACrD,aAAO;AAAA,IACT,SAAS,KAAK;AACZ,aAAO,SAAS,eAAe,QAAQ,IAAI,UAAU,kBAAkB;AACvE,aAAO;AAAA,IACT;AAAA,EACF;AAEA,iBAAe,SAAS,WAAmB;AACzC,QAAI;AACF,UAAI,OAAQ,OAAM,OAAO,EAAE,UAAU,CAAC;AAAA,UACjC,OAAM,UAAU,UAAU,UAAU,SAAS;AAClD,aAAO,WAAW,oBAAoB;AAAA,IACxC,SAAS,KAAK;AACZ,aAAO,SAAS,eAAe,QAAQ,IAAI,UAAU,qBAAqB;AAAA,IAC5E;AAAA,EACF;AAEA,iBAAe,OAAO,cAAsB;AAC1C,cAAU,YAAY;AACtB,QAAI;AACF,YAAM,SAAS,EAAE,aAAa,CAAC;AAC/B,aAAO,WAAW,mBAAmB;AAAA,IACvC,SAAS,KAAK;AACZ,aAAO,SAAS,eAAe,QAAQ,IAAI,UAAU,6BAA6B;AAAA,IACpF,UAAE;AACA,gBAAU,IAAI;AAAA,IAChB;AAAA,EACF;AAEA,iBAAe,OAAO,cAAsB;AAC1C,cAAU,YAAY;AACtB,QAAI;AACF,YAAM,SAAS,EAAE,aAAa,CAAC;AAC/B,aAAO,WAAW,oBAAoB;AAAA,IACxC,SAAS,KAAK;AACZ,aAAO,SAAS,eAAe,QAAQ,IAAI,UAAU,6BAA6B;AAAA,IACpF,UAAE;AACA,gBAAU,IAAI;AAAA,IAChB;AAAA,EACF;AAEA,SACE,gBAAAD,MAAC,aAAQ,WAAU,uBAChB;AAAA,iBAAa,gBAAAD,KAAC,cAAW,OAAM,mBAAkB,aAAY,yBAAwB,UAAU,QAAQ;AAAA,IAExG,gBAAAC,MAAC,SAAI,WAAU,oEACb;AAAA,sBAAAA,MAAC,SAAI,WAAU,qCACb;AAAA,wBAAAD,KAACG,UAAA,EAAQ,IAAG,MAAK,SAAQ,cAAa,gCAAkB;AAAA,QACxD,gBAAAF,MAAC,UAAK,WAAU,oCAAoC;AAAA,sBAAY;AAAA,UAAO;AAAA,WAAM;AAAA,SAC/E;AAAA,MACC,YAAY,WAAW,IACtB,gBAAAD,KAAC,OAAE,WAAU,oCAAmC,iCAAmB,IAEnE,YAAY,IAAI,CAAC,eACf,gBAAAA;AAAA,QAAC;AAAA;AAAA,UAEC;AAAA,UACA;AAAA,UACA,MAAM,WAAW,WAAW;AAAA,UAC5B,QAAQ,MAAM,KAAK,SAAS,WAAW,SAAS;AAAA,UAChD,UAAU,MAAM,KAAK,OAAO,WAAW,EAAE;AAAA,UACzC,UAAU,MAAM,KAAK,OAAO,WAAW,EAAE;AAAA;AAAA,QANpC,WAAW;AAAA,MAOlB,CACD;AAAA,OAEL;AAAA,KACF;AAEJ;AAWA,SAAS,cAAc,EAAE,YAAY,WAAW,MAAM,QAAQ,UAAU,SAAS,GAAuB;AACtG,QAAM,YAAY,WAAW,WAAW;AACxC,QAAM,SAAS,OAAO,WAAW,MAAM;AAEvC,SACE,gBAAAC,MAAC,SAAI,WAAU,6EACb;AAAA,oBAAAA,MAAC,SAAI,WAAU,0CACb;AAAA,sBAAAA,MAAC,SAAI,WAAU,WACb;AAAA,wBAAAD,KAAC,OAAE,WAAU,2DAA0D,OAAO,WAAW,OAAQ,qBAAW,OAAM;AAAA,QAClH,gBAAAA,KAAC,OAAE,WAAU,oCAAoC,2BAAiB,UAAU,GAAE;AAAA,QAC7E,aAAa,WAAW,gBAAgB,YACvC,gBAAAA,KAAC,OAAE,WAAU,kDAAiD,8EAAgE;AAAA,SAElI;AAAA,MACA,gBAAAA,KAAC,UAAK,WAAW,GAAG,UAAU,IAAI,OAAO,IAAI,aAAc,iBAAO,OAAM;AAAA,OAC1E;AAAA,IACC,aAAa,aACZ,gBAAAC,MAAC,SAAI,WAAU,sDACb;AAAA,sBAAAD,KAACI,SAAA,EAAO,MAAK,UAAS,SAAQ,WAAU,SAAS,QAAQ,UAAU,MAAM,uBAAS;AAAA,MAClF,gBAAAJ,KAACI,SAAA,EAAO,MAAK,UAAS,SAAQ,WAAU,SAAS,UAAU,UAAU,MAAO,iBAAO,kBAAa,UAAS;AAAA,MACzG,gBAAAJ,KAACI,SAAA,EAAO,MAAK,UAAS,SAAQ,uBAAsB,SAAS,UAAU,UAAU,MAAM,oBAAM;AAAA,OAC/F;AAAA,KAEJ;AAEJ;;;ACpJA,SAAS,YAAAC,iBAAgB;;;ACHzB,SAAS,MAAM,gBAAgB;AAUtB,gBAAAC,YAAA;AADT,SAAS,WAAW,EAAE,KAAK,GAAqB;AAC9C,SAAO,gBAAAA,KAAC,UAAK,eAAW,MAAC,OAAO,EAAE,SAAS,gBAAgB,OAAO,MAAM,QAAQ,KAAK,GAAG;AAC1F;AAEA,IAAM,WAAW,KAAK,YAAY;AAChC,MAAI;AACF,UAAM,MAAM,MAAM,OAAO,mBAAa;AACtC,WAAO,EAAE,SAAS,IAAI,WAA4C;AAAA,EACpE,QAAQ;AACN,WAAO,EAAE,SAAS,WAA4C;AAAA,EAChE;AACF,CAAC;AAEM,SAAS,UAAU,EAAE,MAAM,UAAU,GAAmB;AAC7D,SACE,gBAAAA,KAAC,YAAS,UAAU,gBAAAA,KAAC,cAAW,MAAY,GAC1C,0BAAAA,KAAC,YAAS,MAAY,WAAsB,GAC9C;AAEJ;;;ADXQ,gBAAAC,MAoCA,QAAAC,aApCA;AAVD,SAAS,iBAAiB,EAAE,SAAS,UAAU,YAAY,qBAAqB,GAA0B;AAC/G,QAAM,CAAC,WAAW,YAAY,IAAIC,UAAS,KAAK;AAChD,QAAM,CAAC,aAAa,cAAc,IAAIA,UAAwB,IAAI;AAClE,QAAM,CAAC,UAAU,WAAW,IAAIA,UAAS,KAAK;AAC9C,QAAM,CAAC,uBAAuB,wBAAwB,IAAIA,UAAS,KAAK;AACxE,QAAM,CAAC,kBAAkB,mBAAmB,IAAIA,UAAS,KAAK;AAE9D,MAAI,QAAQ,WAAW,WAAW;AAChC,WACE,gBAAAF,KAAC,SAAM,OAAM,sBAAqB,MAAK,oFACrC,0BAAAA,KAAC,iBAAc,SAAS,MAAM,WAAW,EAAE,MAAM,UAAU,CAAC,GAAG,2BAAa,GAC9E;AAAA,EAEJ;AAEA,MAAI,QAAQ,WAAW,oBAAoB;AACzC,WACE,gBAAAA,KAAC,SAAM,OAAM,oBAAmB,MAAK,8CACnC,0BAAAA,KAAC,iBAAc,SAAS,MAAM,WAAW,EAAE,MAAM,WAAW,CAAC,GAAG,4BAAc,GAChF;AAAA,EAEJ;AAEA,MAAI,QAAQ,WAAW,WAAW;AAChC,WACE,gBAAAA,KAAC,SAAM,OAAM,sBAAqB,MAAK,2EACrC,0BAAAA,KAAC,iBAAc,SAAS,MAAM,WAAW,EAAE,MAAM,UAAU,CAAC,GAAG,2BAAa,GAC9E;AAAA,EAEJ;AAEA,MAAI,QAAQ,WAAW,WAAW;AAChC,WACE,gBAAAA,KAAC,SAAM,OAAM,sBAAqB,MAAK,gFACrC,0BAAAA,KAAC,iBAAc,SAAS,MAAM,WAAW,EAAE,MAAM,UAAU,CAAC,GAAG,2BAAa,GAC9E;AAAA,EAEJ;AAEA,QAAM,gBAAgB,QAAQ,iBAAiB;AAC/C,QAAM,gBAAgB,QAAQ,cAAc,GAAG,QAAQ,WAAW,iBAAiB;AACnF,QAAM,aAAa,QAAQ,OAAO,OAAO,QAAQ,IAAI,KAAK;AAE1D,MAAI,CAAC,QAAQ,kBAAkB;AAC7B,WACE,gBAAAC,MAAC,SAAM,OAAM,uBACX;AAAA,sBAAAA,MAAC,OAAE,WAAU,6CACV;AAAA;AAAA,QAAc;AAAA,QAAS,gBAAAD,KAAC,UAAK,WAAU,0CAA0C,yBAAc;AAAA,QAAQ;AAAA,QAAW;AAAA,SACrH;AAAA,MACC,QAAQ,eACP,gBAAAC,MAAC,OAAE,WAAU,6CAA4C;AAAA;AAAA,QACrB;AAAA,QAClC,gBAAAD,KAAC,UAAK,WAAU,0CAA0C,kBAAQ,aAAY;AAAA,QAAO;AAAA,SACvF;AAAA,MAEF,gBAAAC,MAAC,SAAI,WAAU,cACb;AAAA,wBAAAD,KAAC,iBAAc,SAAS,MAAM,WAAW,EAAE,MAAM,UAAU,CAAC,GAAG,qBAAO;AAAA,QACtE,gBAAAA,KAAC,mBAAgB,SAAS,MAAM,WAAW,EAAE,MAAM,UAAU,CAAC,GAAG,4BAAc;AAAA,SACjF;AAAA,OACF;AAAA,EAEJ;AAEA,MAAI,UAAU;AACZ,WACE,gBAAAA,KAAC,SAAM,OAAM,YACX,0BAAAC,MAAC,OAAE,WAAU,wCAAuC;AAAA;AAAA,MACpC,gBAAAD,KAAC,UAAK,WAAU,0CAA0C,yBAAc;AAAA,MAAO;AAAA,OAC/F,GACF;AAAA,EAEJ;AAEA,QAAM,gBAAgB;AAAA,IACpB,QAAQ,eACR,QAAQ,YAAY,YAAY,MAAM,QAAQ,iBAAiB,YAAY;AAAA,EAC7E;AACA,QAAM,oBAAoB,QAAQ,QAAQ,sBAAsB,KAAK,CAAC;AACtE,QAAM,cAAc,QAAQ,aAAa,OACrC,IAAI,KAAK,QAAQ,SAAS,EAAE,mBAAmB,SAAS,EAAE,OAAO,SAAS,KAAK,WAAW,MAAM,UAAU,CAAC,IAC3G;AAEJ,iBAAe,eAAe;AAC5B,iBAAa,IAAI;AACjB,mBAAe,IAAI;AACnB,QAAI;AACF,YAAM,SAAS,MAAM,SAAS;AAC9B,kBAAY,IAAI;AAChB,UAAI,UAAU,iBAAiB,UAAU,OAAO,aAAa;AAC3D,mBAAW,EAAE,MAAM,YAAY,aAAa,OAAO,YAAY,CAAC;AAAA,MAClE;AAAA,IACF,SAAS,KAAK;AACZ,qBAAe,eAAe,QAAQ,IAAI,UAAU,6BAA6B;AAAA,IACnF,UAAE;AACA,mBAAa,KAAK;AAAA,IACpB;AAAA,EACF;AAEA,iBAAe,2BAA2B;AACxC,QAAI,CAAC,wBAAwB,sBAAuB;AACpD,6BAAyB,IAAI;AAC7B,QAAI;AACF,YAAM,qBAAqB;AAC3B,0BAAoB,IAAI;AAAA,IAC1B,UAAE;AACA,+BAAyB,KAAK;AAAA,IAChC;AAAA,EACF;AAEA,SACE,gBAAAC,MAAC,SAAM,OAAM,kBACX;AAAA,oBAAAA,MAAC,OAAE,WAAU,6CACV;AAAA;AAAA,MAAc;AAAA,MAAS,gBAAAD,KAAC,UAAK,WAAU,0CAA0C,yBAAc;AAAA,MAAQ;AAAA,MAAW;AAAA,OACrH;AAAA,IACA,gBAAAC,MAAC,OAAE,WAAU,6CAA4C;AAAA;AAAA,MAC1C,gBAAAD,KAAC,UAAK,WAAU,0CAA0C,kBAAQ,kBAAiB;AAAA,OAClG;AAAA,IACC,eACC,gBAAAC,MAAC,OAAE,WAAU,yCAAwC;AAAA;AAAA,MAA4B;AAAA,MAAY;AAAA,OAAC;AAAA,IAE/F,iBACC,gBAAAA;AAAA,MAAC;AAAA;AAAA,QACC,MAAK;AAAA,QACL,WAAU;AAAA,QACX;AAAA;AAAA,UAC6B,gBAAAD,KAAC,UAAK,WAAU,eAAe,kBAAQ,aAAY;AAAA,UAAO;AAAA;AAAA;AAAA,IACxF;AAAA,IAED,qBACC,gBAAAA;AAAA,MAAC;AAAA;AAAA,QACC,MAAK;AAAA,QACL,WAAU;AAAA,QAET,6BACG,uFACA;AAAA;AAAA,IACN;AAAA,IAED,eACC,gBAAAA,KAAC,OAAE,MAAK,SAAQ,WAAU,0CAA0C,uBAAY;AAAA,IAElF,gBAAAC,MAAC,SAAI,WAAU,cACZ;AAAA,sBACC,gBAAAD,KAAC,iBAAc,SAAS,MAAM,WAAW,EAAE,MAAM,iBAAiB,CAAC,GAAG,4BAAc,IAClF,oBACF,uBACE,gBAAAA;AAAA,QAAC;AAAA;AAAA,UACC,SAAS,MAAM,KAAK,yBAAyB;AAAA,UAC7C,UAAU,yBAAyB;AAAA,UAElC,6BAAmB,sBAAsB,wBAAwB,kBAAa;AAAA;AAAA,MACjF,IAEA,gBAAAA,KAAC,iBAAc,SAAS,MAAM,WAAW,EAAE,MAAM,WAAW,CAAC,GAAG,sBAAQ,IAG1E,gBAAAA,KAAC,iBAAc,SAAS,MAAM,KAAK,aAAa,GAAG,UAAU,WAC1D,sBAAY,oBAAe,qBAC9B;AAAA,MAEF,gBAAAA,KAAC,mBAAgB,SAAS,MAAM,WAAW,EAAE,MAAM,WAAW,CAAC,GAAG,qBAAO;AAAA,OAC3E;AAAA,KACF;AAEJ;AAEA,SAAS,MAAM,EAAE,OAAO,MAAM,SAAS,GAAgE;AACrG,SACE,gBAAAC,MAAC,SAAI,WAAU,yCACb;AAAA,oBAAAA,MAAC,UAAK,WAAU,yDACd;AAAA,sBAAAD,KAAC,aAAU,MAAM,IAAI,WAAU,YAAW;AAAA,MAC1C,gBAAAA,KAAC,UAAK,WAAU,qDAAoD,0BAAY;AAAA,OAClF;AAAA,IACA,gBAAAA,KAAC,QAAG,WAAU,wEAAwE,iBAAM;AAAA,IAC3F,QAAQ,gBAAAA,KAAC,OAAE,WAAU,6CAA6C,gBAAK;AAAA,IACvE;AAAA,KACH;AAEJ;AAEA,SAAS,cAAc,EAAE,UAAU,SAAS,SAAS,GAAuE;AAC1H,SACE,gBAAAA;AAAA,IAAC;AAAA;AAAA,MACC,MAAK;AAAA,MACL;AAAA,MACA;AAAA,MACA,WAAU;AAAA,MAET;AAAA;AAAA,EACH;AAEJ;AAEA,SAAS,gBAAgB,EAAE,UAAU,QAAQ,GAAmD;AAC9F,SACE,gBAAAA;AAAA,IAAC;AAAA;AAAA,MACC,MAAK;AAAA,MACL;AAAA,MACA,WAAU;AAAA,MAET;AAAA;AAAA,EACH;AAEJ;","names":["Button","jsx","jsxs","Button","Button","Heading","useState","jsx","jsxs","useState","Heading","Button","useState","jsx","jsx","jsxs","useState"]}
@@ -1882,15 +1882,56 @@
1882
1882
  .tangle-reading-article { width: 100%; max-width: var(--reading-max-width); overflow-wrap: anywhere; }
1883
1883
  .tangle-reading-nav a, .tangle-reading-outline a { display: block; padding: 0.5rem 0; color: hsl(var(--muted-foreground)); text-decoration: none; }
1884
1884
  .tangle-reading-nav a[aria-current]:not([aria-current="false"]), .tangle-reading-outline a[aria-current]:not([aria-current="false"]) { color: var(--accent-text); font-weight: 600; }
1885
+ /* The 13rem track exists only beside a nav, so an article with no nav keeps the full column. */
1885
1886
  @media(min-width: 64rem) {
1886
- .tangle-reading-shell { grid-template-columns: 13rem minmax(0,1fr); }
1887
+ .tangle-reading-shell:has(> .tangle-reading-nav) { grid-template-columns: 13rem minmax(0,1fr); }
1887
1888
  .tangle-reading-outline { display: none; }
1888
1889
  .tangle-reading-nav { position: sticky; top: var(--shell-header-height); align-self: start; max-height: calc(100dvh - var(--shell-header-height)); overflow: auto; }
1889
1890
  }
1890
1891
  @media(min-width: 80rem) {
1891
- .tangle-reading-shell:has(.tangle-reading-outline) { grid-template-columns: 13rem minmax(0,1fr) 11rem; }
1892
+ .tangle-reading-shell:has(> .tangle-reading-outline) { grid-template-columns: minmax(0,1fr) 11rem; }
1893
+ .tangle-reading-shell:where(:has(> .tangle-reading-nav)):has(> .tangle-reading-outline) { grid-template-columns: 13rem minmax(0,1fr) 11rem; }
1892
1894
  .tangle-reading-outline { display: block; position: sticky; top: var(--shell-header-height); align-self: start; }
1893
1895
  }
1896
+ .tangle-reading-header { grid-column: 1 / -1; min-width: 0; }
1897
+ /* PageShell measure="settings". The frame is the query container, so the layout follows the content area's width, not the viewport's.
1898
+ Below 60rem the navigation is a sticky tab strip whose track is the divider; from 60rem it is a sticky 13rem column beside a 48rem article.
1899
+ Without a nav the page is the 48rem column alone. */
1900
+ .tangle-settings-frame { container: tangle-settings / inline-size; width: 100%; min-width: 0; }
1901
+ .tangle-reading-shell[data-measure="settings"] { --tangle-settings-gutter: 1.5rem; grid-template-columns: minmax(0,1fr); gap: 0; max-width: calc(13rem + 2.5rem + 48rem + 4rem); padding: 1.5rem var(--tangle-settings-gutter) 3rem; }
1902
+ /* Without a nav the shell is the column and its gutters, so the centred shell centres the column and its header. */
1903
+ .tangle-reading-shell[data-measure="settings"]:not(:has(> .tangle-reading-nav)) { max-width: calc(48rem + 2 * var(--tangle-settings-gutter)); }
1904
+ .tangle-reading-shell[data-measure="settings"] > .tangle-reading-header { margin-bottom: 0.5rem; }
1905
+ .tangle-reading-shell[data-measure="settings"] > .tangle-reading-header > * { margin-bottom: 0; }
1906
+ .tangle-reading-shell[data-measure="settings"] > .tangle-reading-outline { display: none; }
1907
+ .tangle-reading-shell[data-measure="settings"] > .tangle-reading-article { max-width: 48rem; display: flex; flex-direction: column; gap: 1.5rem; }
1908
+ .tangle-reading-shell[data-measure="settings"] > .tangle-reading-nav { position: sticky; top: 0; z-index: 3; display: flex; align-items: flex-end; gap: 0.25rem; height: var(--shell-header-height); max-height: none; margin: 0 calc(-1 * var(--tangle-settings-gutter)) 1.25rem; padding: 0 var(--tangle-settings-gutter); overflow-x: auto; overflow-y: hidden; overscroll-behavior-x: contain; scrollbar-width: none; background: hsl(var(--background)); box-shadow: inset 0 -1px 0 hsl(var(--border)); }
1909
+ .tangle-reading-shell[data-measure="settings"] > .tangle-reading-nav::-webkit-scrollbar { display: none; }
1910
+ .tangle-reading-shell[data-measure="settings"] > .tangle-reading-nav > :is(ul, ol) { display: flex; flex: none; align-items: flex-end; gap: 0.25rem; margin: 0; padding: 0; list-style: none; }
1911
+ .tangle-reading-shell[data-measure="settings"] > .tangle-reading-nav a { flex: none; display: flex; align-items: center; gap: 0.5rem; min-height: var(--control-height-lg, 2.75rem); padding: 0 0.75rem; color: hsl(var(--muted-foreground)); font-size: var(--font-size-label, 0.875rem); font-weight: 500; line-height: 1.25rem; white-space: nowrap; text-decoration: none; transition: color var(--motion-control), background-color var(--motion-control), box-shadow var(--motion-control); }
1912
+ .tangle-reading-shell[data-measure="settings"] > .tangle-reading-nav a > svg { display: none; }
1913
+ .tangle-reading-shell[data-measure="settings"] > .tangle-reading-nav a > [data-count] { color: var(--text-dim); font-weight: 400; font-variant-numeric: tabular-nums; }
1914
+ .tangle-reading-shell[data-measure="settings"] > .tangle-reading-nav a:hover { color: hsl(var(--foreground)); box-shadow: inset 0 -2px 0 hsl(var(--hsl-ring) / 0.4); }
1915
+ .tangle-reading-shell[data-measure="settings"] > .tangle-reading-nav a[aria-current="page"] { color: var(--accent-text); font-weight: 500; background: hsl(var(--hsl-ring) / 0.07); box-shadow: inset 0 -2px 0 var(--ix-sel-ring); }
1916
+ .tangle-reading-shell[data-measure="settings"] > .tangle-reading-nav a:focus-visible { outline: 1px solid var(--focus-border); outline-offset: -1px; box-shadow: inset 0 0 0 4px var(--focus-halo); }
1917
+ @container tangle-settings (max-width: 40rem) {
1918
+ .tangle-reading-shell[data-measure="settings"] { --tangle-settings-gutter: 1rem; padding: 1rem var(--tangle-settings-gutter) 2.5rem; }
1919
+ .tangle-reading-shell[data-measure="settings"] > .tangle-reading-nav { margin-bottom: 1rem; }
1920
+ .tangle-reading-shell[data-measure="settings"] > .tangle-reading-article { gap: 1rem; }
1921
+ }
1922
+ @container tangle-settings (min-width: 60rem) {
1923
+ .tangle-reading-shell[data-measure="settings"] { --tangle-settings-gutter: 2rem; grid-template-columns: minmax(0,48rem); column-gap: 2.5rem; align-items: start; padding: 2rem; }
1924
+ .tangle-reading-shell[data-measure="settings"]:has(> .tangle-reading-nav) { grid-template-columns: 13rem minmax(0,48rem); }
1925
+ .tangle-reading-shell[data-measure="settings"] > .tangle-reading-header { margin-bottom: 1.75rem; }
1926
+ .tangle-reading-shell[data-measure="settings"] > .tangle-reading-nav { top: 2rem; flex-direction: column; align-items: stretch; gap: 2px; height: auto; margin: 0; padding: 0; overflow: visible; background: none; box-shadow: none; }
1927
+ .tangle-reading-shell[data-measure="settings"] > .tangle-reading-nav > :is(ul, ol) { flex-direction: column; align-items: stretch; gap: 2px; }
1928
+ .tangle-reading-shell[data-measure="settings"] > .tangle-reading-nav a { min-height: var(--control-height, 2.25rem); gap: 0.625rem; padding: 0 0.625rem; border-radius: var(--radius-md); }
1929
+ .tangle-reading-shell[data-measure="settings"] > .tangle-reading-nav a > svg { display: block; flex: none; width: 1rem; height: 1rem; }
1930
+ .tangle-reading-shell[data-measure="settings"] > .tangle-reading-nav a > [data-count] { margin-inline-start: auto; }
1931
+ .tangle-reading-shell[data-measure="settings"] > .tangle-reading-nav a:hover { background: var(--ix-hover-bg); box-shadow: none; }
1932
+ .tangle-reading-shell[data-measure="settings"] > .tangle-reading-nav a[aria-current="page"] { background: var(--ix-sel-bg); box-shadow: inset 0 0 0 1px var(--ix-sel-ring); }
1933
+ .tangle-reading-shell[data-measure="settings"] > .tangle-reading-nav a:focus-visible { outline-offset: 0; box-shadow: 0 0 0 4px var(--focus-halo); }
1934
+ }
1894
1935
  /* Native dialog has the same solid reading surface as React's Dialog/Sheet. */
1895
1936
  .tangle-native-dialog { max-width: min(32rem,calc(100% - 2rem)); max-height: calc(100dvh - 2rem); overflow: auto; margin: auto; padding: 1.5rem; border: 1px solid hsl(var(--border)); border-radius: var(--radius-lg); background: hsl(var(--card)); color: hsl(var(--card-foreground)); }
1896
1937
  .tangle-native-dialog::backdrop { background: var(--scrim); }
@@ -9,7 +9,7 @@ import {
9
9
  restrictTaxonomy,
10
10
  verifyCapabilityToken,
11
11
  verifyExpiringCapabilityToken
12
- } from "../chunk-75ZIWV4U.js";
12
+ } from "../chunk-QAF7ZTO3.js";
13
13
  import {
14
14
  DEFAULT_APP_TOOL_PATHS,
15
15
  DEFAULT_HEADER_NAMES,
@@ -23,7 +23,7 @@ import {
23
23
  unresolvableSurfaceCredential
24
24
  } from "../chunk-6A7MYOUI.js";
25
25
  import "../chunk-S5SRJJQG.js";
26
- import "../chunk-YXLN4PXK.js";
26
+ import "../chunk-2RCPPOQ4.js";
27
27
  import {
28
28
  APP_TOOL_NAMES,
29
29
  buildAppToolOpenAITools,
@@ -31,11 +31,11 @@ import {
31
31
  defineAppTool,
32
32
  findCustomTool,
33
33
  isAppToolName
34
- } from "../chunk-AJZ3EJB5.js";
34
+ } from "../chunk-IJAXOQJU.js";
35
35
  import "../chunk-UGWQLQDS.js";
36
36
  import {
37
37
  ToolInputError
38
- } from "../chunk-7BYY7QKC.js";
38
+ } from "../chunk-E65YV7VV.js";
39
39
  export {
40
40
  APP_TOOL_NAMES,
41
41
  DEFAULT_APP_TOOL_PATHS,
@@ -1,10 +1,10 @@
1
1
  import {
2
2
  AGENT_PROFILE_EDITOR_SECTIONS,
3
3
  AgentProfileEditor
4
- } from "../chunk-3RHAF2P5.js";
5
- import "../chunk-YESFGM56.js";
6
- import "../chunk-YGBEGBJY.js";
7
- import "../chunk-TJ4DYKF2.js";
4
+ } from "../chunk-A3CUVYRZ.js";
5
+ import "../chunk-5IS3GCMR.js";
6
+ import "../chunk-HEPEGY6Q.js";
7
+ import "../chunk-XG6FODYO.js";
8
8
  import "../chunk-RASGKEAL.js";
9
9
  import "../chunk-VBRUG4N5.js";
10
10
  import "../chunk-B7CL7ENS.js";
@@ -16,7 +16,7 @@ import {
16
16
  resolveAsyncValue,
17
17
  useAsyncResource,
18
18
  useConfirmedMutation
19
- } from "../../chunk-LN5RBVGP.js";
19
+ } from "../../chunk-AVP5SNIG.js";
20
20
  export {
21
21
  AsyncRequestError,
22
22
  AsyncView,
@@ -170,11 +170,10 @@ export declare function pickerRootClass(fullWidth: boolean): string;
170
170
  */
171
171
  export type PickerVariant = 'chip' | 'quiet' | 'field';
172
172
  /**
173
- * Trigger classes for a `field` picker. It matches `@tangle-network/ui`'s
174
- * compact `Input` (height, `rounded-lg`, `--bg-input` well, border hover, and
175
- * `:focus` halo) so a model or harness selector sits in a form as one more
176
- * field. Written out here because `/web-react` controls stay free of the
177
- * sandbox-ui peer.
173
+ * Trigger classes for a `field` picker: `@tangle-network/ui`'s own field
174
+ * presentation and `md` field size, the classes its `Input` and `SelectTrigger`
175
+ * draw, so a model, harness or timezone selector sits in a form as one more
176
+ * field — the same well on every plane, the same border, hover and focus halo.
178
177
  */
179
178
  export declare function fieldPickerTriggerClass({ interactive }?: {
180
179
  interactive?: boolean;
@@ -143,17 +143,17 @@ import {
143
143
  withoutRecordGridCreated,
144
144
  withoutRecordGridRemoved,
145
145
  withoutRecordGridUpdate
146
- } from "../chunk-6O2NQ7WD.js";
146
+ } from "../chunk-Y2SOQOJE.js";
147
+ import {
148
+ MENTION_PILL_CLASS
149
+ } from "../chunk-3HUFJ5LO.js";
147
150
  import {
148
151
  SessionHistoryPanel,
149
152
  formatSessionTimestamp,
150
153
  useInfiniteScroll,
151
154
  useSessionActions,
152
155
  useSessionHistory
153
- } from "../chunk-EQRVOMMS.js";
154
- import {
155
- MENTION_PILL_CLASS
156
- } from "../chunk-3HUFJ5LO.js";
156
+ } from "../chunk-KMIDRUUH.js";
157
157
  import "../chunk-FBVLEGEG.js";
158
158
  import {
159
159
  EvidenceLineageTable,
@@ -180,12 +180,12 @@ import {
180
180
  preloadWhenIdle,
181
181
  useComposerAttachments,
182
182
  useDictation
183
- } from "../chunk-BBHVV37T.js";
183
+ } from "../chunk-MSAGTFN4.js";
184
184
  import "../chunk-L7MB2LLM.js";
185
185
  import {
186
186
  WorkspaceInitial,
187
187
  WorkspaceSwitcher
188
- } from "../chunk-UDLA3NGY.js";
188
+ } from "../chunk-GNBBY3KN.js";
189
189
  import "../chunk-A2GG4D4A.js";
190
190
  import {
191
191
  tabTerminalConnectionId,
@@ -196,7 +196,7 @@ import {
196
196
  AGENT_PROFILE_EDITOR_SECTIONS,
197
197
  AgentProfileEditor,
198
198
  AgentProfileRegistryError
199
- } from "../chunk-3RHAF2P5.js";
199
+ } from "../chunk-A3CUVYRZ.js";
200
200
  import {
201
201
  AgentSessionControls,
202
202
  AgentSettingsPopover,
@@ -206,8 +206,8 @@ import {
206
206
  filterAcceptedFiles,
207
207
  isAcceptedFileType,
208
208
  renamePastedImages
209
- } from "../chunk-YESFGM56.js";
210
- import "../chunk-YGBEGBJY.js";
209
+ } from "../chunk-5IS3GCMR.js";
210
+ import "../chunk-HEPEGY6Q.js";
211
211
  import {
212
212
  DEFAULT_EFFORT_LEVELS,
213
213
  EFFORT_METER_SEGMENTS,
@@ -225,7 +225,7 @@ import {
225
225
  reconcileEffortLevels,
226
226
  usePending,
227
227
  usePopover
228
- } from "../chunk-TJ4DYKF2.js";
228
+ } from "../chunk-XG6FODYO.js";
229
229
  import {
230
230
  parseReviewQueueItem
231
231
  } from "../chunk-GEYACSFW.js";
@@ -236,7 +236,7 @@ import "../chunk-WSEXFTN4.js";
236
236
  import {
237
237
  ProviderLogo
238
238
  } from "../chunk-RASGKEAL.js";
239
- import "../chunk-LN5RBVGP.js";
239
+ import "../chunk-AVP5SNIG.js";
240
240
  import "../chunk-FQYAJYPW.js";
241
241
  import {
242
242
  ATTACHMENT_ACCEPT
@@ -16,11 +16,11 @@ import {
16
16
  } from "../chunk-3NVVBQ2U.js";
17
17
  import {
18
18
  defineAppTool
19
- } from "../chunk-AJZ3EJB5.js";
19
+ } from "../chunk-IJAXOQJU.js";
20
20
  import "../chunk-UGWQLQDS.js";
21
21
  import {
22
22
  ToolInputError
23
- } from "../chunk-7BYY7QKC.js";
23
+ } from "../chunk-E65YV7VV.js";
24
24
  import {
25
25
  isWorkProductStatus,
26
26
  parseAgentCheckInput,
@@ -5,6 +5,7 @@
5
5
  * a running export.
6
6
  */
7
7
  import { type ReactNode } from 'react';
8
+ import type { ExportProgress } from './types';
8
9
  export interface WorkspaceExportPanelProps {
9
10
  /** The mount path of the product's export routes, e.g. `/api/workspaces/ws-1/exports`. */
10
11
  endpoint: string;
@@ -18,4 +19,29 @@ export interface WorkspaceExportPanelProps {
18
19
  /** True when the product runs `continueRunning` on a cron, so the export finishes after the page closes. */
19
20
  continuesInBackground?: boolean;
20
21
  }
22
+ export interface UseWorkspaceExportOptions {
23
+ /** The mount path of the product's export routes. */
24
+ endpoint: string;
25
+ /** False skips loading; the server refuses non-owners regardless. */
26
+ enabled: boolean;
27
+ fetcher?: typeof fetch;
28
+ }
29
+ export interface WorkspaceExportState {
30
+ /** The newest export, if any. */
31
+ latest: ExportProgress | undefined;
32
+ /** The last request failure, as a sentence. */
33
+ error: string | null;
34
+ loading: boolean;
35
+ starting: boolean;
36
+ running: boolean;
37
+ start: () => Promise<void>;
38
+ /** Resumes a running export, or reloads the list. */
39
+ retry: () => void;
40
+ }
41
+ /**
42
+ * Starts an export, drives it to completion by calling `advance` while the
43
+ * page is open, and resumes a running one on mount. `WorkspaceExportPanel`
44
+ * and the settings `ExportSection` both draw from it.
45
+ */
46
+ export declare function useWorkspaceExport({ endpoint, enabled, fetcher }: UseWorkspaceExportOptions): WorkspaceExportState;
21
47
  export declare function WorkspaceExportPanel({ endpoint, canExport, title, description, className, fetcher, continuesInBackground }: WorkspaceExportPanelProps): import("react").JSX.Element | null;