{"$schema":"https://ui.shadcn.com/schema/registry-item.json","name":"email-draft","type":"registry:ui","title":"Email Draft","description":"Agent-written email for review – switch recipient and tone, edit inline, remove the attachment, send or discard with undo","dependencies":[],"files":[{"path":"registry/email-draft/email-draft.tsx","type":"registry:ui","content":"\"use client\";\n\nimport { useEffect, useLayoutEffect, useRef, useState, type ReactNode, type RefObject } from \"react\";\n\n/*\n * Email Draft – an agent-written email waiting for review, in a single self-contained file.\n * The record it's about sits on the gray tray (reference, status, amount); the white card holds the email:\n * recipient you can switch, an attachment you can remove, tone variants, inline editing, Discard and Send.\n * Sending or discarding folds the card into a one-line receipt with Undo; heights glide throughout.\n * The styles are injected below, so no extra files are needed.\n */\n\nexport type DraftContact = { name: string; email: string };\n\nexport type DraftTone = { id: string; label: string; body: (contact: DraftContact) => string };\n\nexport type EmailDraftProps = {\n  /** Reference of the record, e.g. a subscription or invoice number */\n  reference?: string;\n  /** Account or company under the reference */\n  account?: string;\n  /** Amount shown on the right */\n  amount?: string;\n  /** Status chip next to the reference */\n  status?: string;\n  /** Who wrote the draft */\n  agent?: string;\n  contacts?: DraftContact[];\n  attachment?: string | null;\n  /** Text variants to switch between – the first one is shown first */\n  tones?: DraftTone[];\n  /** Label and target of the link appended to the email */\n  link?: { label: string; href: string };\n  onSend?: (email: { to: DraftContact; body: string; attachment: string | null }) => void;\n  onDiscard?: () => void;\n  className?: string;\n};\n\nconst defaultContacts: DraftContact[] = [\n  { name: \"Jonas Weber\", email: \"jonas@northwind.io\" },\n  { name: \"Lena Hart\", email: \"lena@northwind.io\" },\n  { name: \"Finance team\", email: \"billing@northwind.io\" },\n];\n\nconst first = (c: DraftContact) => c.name.trim().split(/\\s+/)[0] ?? \"\";\n// Two capitals from whole letters – emoji and stray spaces are skipped\nconst initials = (name: string) =>\n  name\n    .trim()\n    .split(/\\s+/)\n    .map((w) => w.match(/[\\p{L}\\p{N}]/u)?.[0] ?? \"\")\n    .join(\"\")\n    .slice(0, 2)\n    .toUpperCase();\nconst escape = (s: string) => s.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n// Without contacts there is no one to send to – the recipient button and Send step back\nconst NO_ONE: DraftContact = { name: \"\", email: \"\" };\n\nconst defaultTones: DraftTone[] = [\n  {\n    id: \"friendly\",\n    label: \"Friendly\",\n    body: (c) =>\n      `Hi ${first(c)}, a heads-up that your Growth plan renews on October 9 for $8,900 a year. If you'd like to add seats or switch to monthly billing, you can review the quote here:`,\n  },\n  {\n    id: \"short\",\n    label: \"Short\",\n    body: (c) => `Hi ${first(c)}, your Growth plan renews on October 9 ($8,900/year). Quote for changes:`,\n  },\n  {\n    id: \"formal\",\n    label: \"Formal\",\n    body: (c) =>\n      `Dear ${c.name}, this is a reminder that your Growth subscription is scheduled to renew on October 9 at $8,900 per year. Should you wish to adjust seats or billing, please review the attached quote:`,\n  },\n];\n\ntype Phase = \"draft\" | \"sending\" | \"sent\" | \"discarded\";\n\nexport function EmailDraft({\n  reference = \"SUB-1182\",\n  account = \"Northwind Logistics\",\n  amount = \"$8,900\",\n  status = \"Renews in 5 days\",\n  agent = \"Renewal agent\",\n  contacts = defaultContacts,\n  attachment = \"Renewal-quote.pdf\",\n  tones = defaultTones,\n  link = { label: \"Review quote\", href: \"#\" },\n  onSend,\n  onDiscard,\n  className,\n}: EmailDraftProps) {\n  const [to, setTo] = useState<DraftContact>(contacts[0] ?? NO_ONE);\n  const [file, setFile] = useState<string | null>(attachment);\n  const [tone, setTone] = useState(tones[0]?.id ?? \"\");\n  // Edited text wins over the generated variant until the tone or recipient changes\n  const [edited, setEdited] = useState<string | null>(null);\n  const [editing, setEditing] = useState(false);\n  const [menu, setMenu] = useState(false);\n  const [phase, setPhase] = useState<Phase>(\"draft\");\n  const [toneKey, setToneKey] = useState(0);\n  const inner = useRef<HTMLDivElement>(null);\n  const outer = useSmoothHeight(inner);\n  const textRef = useRef<HTMLTextAreaElement>(null);\n  const menuRef = useRef<HTMLDivElement>(null);\n  const timers = useRef<number[]>([]);\n\n  const generated = tones.find((t) => t.id === tone)?.body(to) ?? \"\";\n  const body = edited ?? generated;\n\n  useEffect(() => () => timers.current.forEach((t) => window.clearTimeout(t)), []);\n\n  // Close the recipient menu on outside click or Escape\n  useEffect(() => {\n    if (!menu) return;\n    const onDown = (e: PointerEvent) => {\n      if (!menuRef.current?.contains(e.target as Node)) setMenu(false);\n    };\n    const onKey = (e: KeyboardEvent) => e.key === \"Escape\" && setMenu(false);\n    document.addEventListener(\"pointerdown\", onDown);\n    document.addEventListener(\"keydown\", onKey);\n    return () => {\n      document.removeEventListener(\"pointerdown\", onDown);\n      document.removeEventListener(\"keydown\", onKey);\n    };\n  }, [menu]);\n\n  // The edit field grows with its text\n  useLayoutEffect(() => {\n    const el = textRef.current;\n    if (!el) return;\n    el.style.height = \"auto\";\n    el.style.height = `${el.scrollHeight}px`;\n  }, [editing, body]);\n\n  const startEditing = () => {\n    setEdited(body);\n    setEditing(true);\n    requestAnimationFrame(() => {\n      const el = textRef.current;\n      if (el) {\n        el.focus();\n        el.setSelectionRange(el.value.length, el.value.length);\n      }\n    });\n  };\n\n  const pickTone = (id: string) => {\n    if (id === tone && edited === null) return;\n    setTone(id);\n    setEdited(null);\n    setEditing(false);\n    setToneKey((k) => k + 1);\n  };\n\n  const pickContact = (c: DraftContact) => {\n    setTo(c);\n    setMenu(false);\n    // Keep manual edits, but follow the new name in the generated text – the full name first, then the first name alone\n    const full = to.name.trim();\n    const parts = [full && escape(full), first(to) && `\\\\b${escape(first(to))}\\\\b`].filter(Boolean);\n    if (edited !== null && parts.length) setEdited(edited.replace(new RegExp(parts.join(\"|\"), \"g\"), (m) => (m === full ? c.name.trim() : first(c))));\n  };\n\n  const send = () => {\n    if (phase !== \"draft\" || !to.email) return;\n    setEditing(false);\n    setPhase(\"sending\");\n    timers.current.push(\n      window.setTimeout(() => {\n        setPhase(\"sent\");\n        onSend?.({ to, body: `${body} ${link.label}: ${link.href}`, attachment: file });\n      }, 900),\n    );\n  };\n\n  const discard = () => {\n    setEditing(false);\n    setPhase(\"discarded\");\n    onDiscard?.();\n  };\n\n  const undo = () => setPhase(\"draft\");\n\n  const open = phase === \"draft\" || phase === \"sending\";\n  const badge =\n    phase === \"sent\" ? { text: \"Sent\", tone: \"ok\" } : phase === \"discarded\" ? { text: \"Discarded\", tone: \"muted\" } : { text: \"Ready for review\", tone: \"ok\" };\n\n  return (\n    <div className={[\"ui-ed\", className].filter(Boolean).join(\" \")}>\n      <style href=\"ui-email-draft\" precedence=\"default\">\n        {css}\n      </style>\n\n      {/* The record the email is about */}\n      <div className=\"ui-ed__record\">\n        <div className=\"ui-ed__ref\">\n          <span className=\"ui-ed__id\" title={reference}>\n            {reference}\n          </span>\n          {status && (\n            <span className=\"ui-ed__status\" dir=\"auto\" title={status}>\n              {status}\n            </span>\n          )}\n          <span className=\"ui-ed__amount\">{amount}</span>\n        </div>\n        <span className=\"ui-ed__account\" dir=\"auto\">\n          {account}\n        </span>\n      </div>\n\n      {/* Card ↔ receipt, the height glides between them */}\n      <div className=\"ui-ed__outer\" ref={outer}>\n        <div ref={inner}>\n          {open ? (\n            <div className=\"ui-ed__card\" data-sending={phase === \"sending\" ? \"\" : undefined}>\n              <div className=\"ui-ed__meta\">\n                <div className=\"ui-ed__to\" ref={menuRef}>\n                  <span className=\"ui-ed__label\">to</span>\n                  {to.email ? (\n                    <button\n                      type=\"button\"\n                      className=\"ui-ed__recipient\"\n                      aria-haspopup=\"listbox\"\n                      aria-expanded={menu}\n                      title={`${to.name} <${to.email}>`}\n                      onClick={() => setMenu((m) => !m)}\n                    >\n                      <span className=\"ui-ed__name\" dir=\"auto\">\n                        {to.name}\n                      </span>{\" \"}\n                      <span className=\"ui-ed__email\">({to.email})</span>\n                      <svg viewBox=\"0 0 24 24\" aria-hidden=\"true\">\n                        <path d=\"m7 10 5 5 5-5\" />\n                      </svg>\n                    </button>\n                  ) : (\n                    <span className=\"ui-ed__email\">No recipient</span>\n                  )}\n                  {menu && (\n                    <ul className=\"ui-ed__menu\" role=\"listbox\" aria-label=\"Recipient\">\n                      {contacts.map((c, i) => (\n                        <li key={`${c.email}-${i}`}>\n                          <button type=\"button\" role=\"option\" aria-selected={c.email === to.email} onClick={() => pickContact(c)}>\n                            <span className=\"ui-ed__avatar\" aria-hidden=\"true\">\n                              {initials(c.name)}\n                            </span>\n                            <span className=\"ui-ed__menu-text\" dir=\"auto\">\n                              {c.name}\n                              <small>{c.email}</small>\n                            </span>\n                            {c.email === to.email && (\n                              <svg className=\"ui-ed__tick\" viewBox=\"0 0 24 24\" aria-hidden=\"true\">\n                                <path d=\"m6 12.5 4 4 8-9\" />\n                              </svg>\n                            )}\n                          </button>\n                        </li>\n                      ))}\n                    </ul>\n                  )}\n                </div>\n                {file ? (\n                  <span className=\"ui-ed__file\">\n                    <Icon>\n                      <path d=\"m15.5 7.5-6.4 6.4a1.8 1.8 0 0 0 2.5 2.5l6.7-6.7a3.5 3.5 0 0 0-5-5l-6.9 6.9a5.2 5.2 0 0 0 7.4 7.4l6-6\" />\n                    </Icon>\n                    <span className=\"ui-ed__file-name\" title={file}>\n                      {file}\n                    </span>\n                    <button type=\"button\" aria-label={`Remove ${file}`} onClick={() => setFile(null)}>\n                      <Icon>\n                        <path d=\"M7 7l10 10M17 7 7 17\" />\n                      </Icon>\n                    </button>\n                  </span>\n                ) : (\n                  attachment && (\n                    <button type=\"button\" className=\"ui-ed__attach\" onClick={() => setFile(attachment)}>\n                      <Icon>\n                        <path d=\"M12 6v12M6 12h12\" />\n                      </Icon>\n                      <span className=\"ui-ed__file-name\" title={attachment}>\n                        Attach {attachment}\n                      </span>\n                    </button>\n                  )\n                )}\n              </div>\n\n              <div className=\"ui-ed__body\">\n                {editing ? (\n                  <textarea\n                    ref={textRef}\n                    className=\"ui-ed__edit\"\n                    dir=\"auto\"\n                    value={edited ?? \"\"}\n                    onChange={(e) => setEdited(e.target.value)}\n                    onKeyDown={(e) => {\n                      if (e.key === \"Enter\" && (e.metaKey || e.ctrlKey)) {\n                        e.preventDefault();\n                        send();\n                      }\n                      if (e.key === \"Escape\") setEditing(false);\n                    }}\n                    onBlur={() => setEditing(false)}\n                    aria-label=\"Email text\"\n                  />\n                ) : (\n                  <p key={toneKey} className=\"ui-ed__text\" dir=\"auto\" onClick={startEditing} title=\"Click to edit\">\n                    {body}{\" \"}\n                    <a href={link.href} onClick={(e) => e.stopPropagation()}>\n                      {link.label}\n                    </a>\n                  </p>\n                )}\n              </div>\n\n              <div className=\"ui-ed__actions\">\n                <div className=\"ui-ed__tones\" role=\"group\" aria-label=\"Tone\">\n                  {tones.map((t) => (\n                    <button key={t.id} type=\"button\" aria-pressed={tone === t.id && edited === null} onClick={() => pickTone(t.id)}>\n                      {t.label}\n                    </button>\n                  ))}\n                  <button type=\"button\" className=\"ui-ed__edit-btn\" aria-pressed={editing} aria-label=\"Edit text\" onClick={startEditing}>\n                    <Icon>\n                      <path d=\"M14.5 5.5 18.5 9.5M5 19l1-4L15.5 5.5l4 4L10 19l-5 0Z\" />\n                    </Icon>\n                  </button>\n                </div>\n                <div className=\"ui-ed__buttons\">\n                  <button type=\"button\" className=\"ui-ed__secondary\" onClick={discard} disabled={phase === \"sending\"}>\n                    Discard\n                  </button>\n                  <button type=\"button\" className=\"ui-ed__primary\" onClick={send} disabled={phase === \"sending\" || !to.email}>\n                    {phase === \"sending\" ? (\n                      <>\n                        <span className=\"ui-ed__spinner\" aria-hidden=\"true\" />\n                        Sending\n                      </>\n                    ) : (\n                      \"Send email\"\n                    )}\n                  </button>\n                </div>\n              </div>\n            </div>\n          ) : (\n            <div className=\"ui-ed__receipt\" role=\"status\">\n              <span className=\"ui-ed__receipt-icon\" data-tone={phase === \"sent\" ? \"ok\" : \"muted\"} aria-hidden=\"true\">\n                <Icon>{phase === \"sent\" ? <path d=\"m6 12.5 4 4 8-9\" /> : <path d=\"M7 7l10 10M17 7 7 17\" />}</Icon>\n              </span>\n              <span className=\"ui-ed__receipt-text\">\n                {phase === \"sent\" ? (\n                  <>\n                    Sent to <b dir=\"auto\">{to.name}</b>\n                    {file ? ` with ${file}` : \"\"}\n                  </>\n                ) : (\n                  \"Draft discarded\"\n                )}\n              </span>\n              <button type=\"button\" className=\"ui-ed__undo\" onClick={undo}>\n                Undo\n              </button>\n            </div>\n          )}\n        </div>\n      </div>\n\n      <div className=\"ui-ed__foot\">\n        <span className=\"ui-ed__agent\" title={agent}>\n          {agent}\n        </span>\n        <span className=\"ui-ed__badge\" data-tone={badge.tone} key={badge.text}>\n          {badge.text}\n        </span>\n        {open && <span className=\"ui-ed__hint\">⌘ Enter to send</span>}\n      </div>\n    </div>\n  );\n}\n\nconst Icon = ({ children }: { children: ReactNode }) => (\n  <svg viewBox=\"0 0 24 24\" aria-hidden=\"true\">\n    {children}\n  </svg>\n);\n\n/** The outer box follows the inner box's height, with a transition after the first frame */\nfunction useSmoothHeight(inner: RefObject<HTMLElement | null>) {\n  const outer = useRef<HTMLDivElement>(null);\n  useLayoutEffect(() => {\n    const o = outer.current;\n    const i = inner.current;\n    if (!o || !i) return;\n    const sync = () => {\n      o.style.height = `${i.offsetHeight}px`;\n    };\n    sync();\n    const ro = new ResizeObserver(sync);\n    ro.observe(i);\n    const frame = requestAnimationFrame(() => o.setAttribute(\"data-smooth\", \"\"));\n    return () => {\n      ro.disconnect();\n      cancelAnimationFrame(frame);\n    };\n  }, [inner]);\n  return outer;\n}\n\n/* ---------- Styles ---------- */\n\nconst css = /* css */ `\n.ui-ed {\n  --ui-ed-tray: var(--aui-subtle, #f0f0f0);\n  --ui-ed-card: #ffffff;\n  --ui-ed-card-line: var(--aui-border, #e5e5e5);\n  --ui-ed-line: var(--aui-border, #ececec);\n  --ui-ed-ink: var(--aui-ink, #171717);\n  --ui-ed-text: var(--aui-ink, #404040);\n  --ui-ed-muted: var(--aui-muted, #8f8f8f);\n  --ui-ed-chip: #f5f5f5;\n  --ui-ed-chip-line: #ebebeb;\n  --ui-ed-hover: var(--aui-subtle, #f5f5f5);\n  --ui-ed-warn: var(--aui-warning, #b25e00);\n  --ui-ed-warn-bg: #fdeedd;\n  --ui-ed-ok: var(--aui-success, #1e8a4f);\n  --ui-ed-ok-bg: #e6f5ec;\n  --ui-ed-btn-top: #323137;\n  --ui-ed-btn-bottom: #201e25;\n  --ui-ed-btn-ring: #0d0d0d;\n  --ui-ed-btn-text: #ffffff;\n  --ui-ed-focus: var(--aui-focus, rgba(0, 96, 226, 0.7));\n  --ui-ed-shadow: 0 1px 2px rgba(0, 0, 0, 0.06);\n  --ui-ed-ease: var(--aui-ease, cubic-bezier(0.22, 1, 0.36, 1));\n  width: 100%;\n  max-width: 520px;\n  container-type: inline-size;\n  padding: 6px;\n  border-radius: calc(var(--aui-radius-lg, 16px) + 4px);\n  background: var(--ui-ed-tray);\n  font-family: var(--aui-font, \"Inter\", ui-sans-serif, system-ui, -apple-system, \"Segoe UI\", Roboto, sans-serif);\n  color: var(--ui-ed-ink);\n  -webkit-font-smoothing: antialiased;\n}\n.ui-ed *, .ui-ed *::before, .ui-ed *::after { box-sizing: border-box; }\n.ui-ed button { font: inherit; color: inherit; margin: 0; cursor: pointer; -webkit-tap-highlight-color: transparent; }\n.ui-ed button:focus-visible, .ui-ed a:focus-visible { outline: 2px solid var(--ui-ed-focus); outline-offset: 2px; }\n.ui-ed svg { width: 15px; height: 15px; flex: none; fill: none; stroke: currentColor; stroke-width: 1.7; stroke-linecap: round; stroke-linejoin: round; }\n\n/* ---------- Record on the tray ---------- */\n\n.ui-ed__record { display: grid; gap: 2px; padding: 8px 10px 10px; }\n.ui-ed__ref { display: flex; align-items: center; gap: 8px; min-width: 0; }\n/* The status gives way first, then the reference – the amount never does */\n.ui-ed__id { flex: 0 1 auto; min-width: 0; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; font-size: 15px; font-weight: 500; letter-spacing: -0.01em; }\n.ui-ed__status {\n  flex: 0 100 auto;\n  min-width: 0;\n  overflow: hidden;\n  text-overflow: ellipsis;\n  padding: 2px 8px;\n  border-radius: calc(var(--aui-radius-sm, 7px) + 1px);\n  background: var(--ui-ed-warn-bg);\n  font-size: 12.5px;\n  font-weight: 500;\n  color: var(--ui-ed-warn);\n  white-space: nowrap;\n}\n.ui-ed__amount { flex: none; margin-left: auto; white-space: nowrap; font-size: 15px; font-weight: 500; font-variant-numeric: tabular-nums; }\n.ui-ed__account { overflow-wrap: anywhere; font-size: 13px; color: var(--ui-ed-muted); }\n\n.ui-ed__outer { position: relative; }\n.ui-ed__outer[data-smooth] { transition: height 360ms var(--ui-ed-ease); }\n\n/* ---------- Email card ---------- */\n\n.ui-ed__card {\n  border: 1px solid var(--ui-ed-card-line);\n  border-radius: var(--aui-radius-lg, 16px);\n  background: var(--aui-surface, var(--ui-ed-card));\n  box-shadow: var(--ui-ed-shadow);\n  animation: ui-ed-in 320ms var(--ui-ed-ease) both;\n  transition: opacity 220ms ease;\n}\n.ui-ed__card[data-sending] { opacity: 0.7; pointer-events: none; }\n\n.ui-ed__meta {\n  display: flex;\n  min-width: 0;\n  align-items: center;\n  justify-content: space-between;\n  gap: 12px;\n  margin: 0 14px;\n  padding: 12px 0 11px;\n  border-bottom: 1px solid var(--ui-ed-line);\n}\n.ui-ed__to { position: relative; display: flex; align-items: center; gap: 6px; min-width: 0; }\n.ui-ed__label { font-size: 13px; color: var(--ui-ed-muted); }\n.ui-ed__recipient {\n  display: inline-flex;\n  align-items: center;\n  gap: 4px;\n  min-width: 0;\n  height: 26px;\n  padding: 0 6px 0 8px;\n  border: 0;\n  border-radius: calc(var(--aui-radius-sm, 7px) + 1px);\n  background: var(--ui-ed-chip);\n  box-shadow: inset 0 0 0 1px var(--aui-border, var(--ui-ed-chip-line));\n  font-size: 13px;\n  white-space: nowrap;\n  overflow: hidden;\n  transition: background-color 160ms ease;\n}\n.ui-ed__recipient:hover { background: color-mix(in srgb, var(--ui-ed-chip) 80%, var(--ui-ed-ink) 6%); }\n/* A long name shortens; the address gives way before it */\n.ui-ed__name { min-width: 0; overflow: hidden; text-overflow: ellipsis; }\n.ui-ed__email { flex: 0 100 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; color: var(--ui-ed-muted); }\n.ui-ed__recipient svg { width: 14px; height: 14px; color: var(--ui-ed-muted); transition: transform 220ms var(--ui-ed-ease); }\n.ui-ed__recipient[aria-expanded=\"true\"] svg { transform: rotate(180deg); }\n\n.ui-ed__menu {\n  position: absolute;\n  top: calc(100% + 6px);\n  left: 18px;\n  z-index: 5;\n  display: grid;\n  gap: 2px;\n  min-width: 250px;\n  max-width: calc(100cqw - 36px);\n  max-height: 288px;\n  overflow-y: auto;\n  overscroll-behavior: contain;\n  margin: 0;\n  padding: 5px;\n  list-style: none;\n  border-radius: calc(var(--aui-radius-lg, 16px) - 4px);\n  background: var(--aui-overlay, var(--ui-ed-card));\n  box-shadow: var(--aui-shadow-popover, 0 0 0 1px var(--ui-ed-card-line), 0 10px 30px rgba(0, 0, 0, 0.1));\n  animation: ui-ed-menu 200ms var(--ui-ed-ease) both;\n  transform-origin: top left;\n}\n.ui-ed__menu button {\n  display: flex;\n  align-items: center;\n  gap: 10px;\n  width: 100%;\n  padding: 7px 8px;\n  border: 0;\n  border-radius: calc(var(--aui-radius-sm, 7px) + 1px);\n  background: none;\n  text-align: left;\n  font-size: 13px;\n}\n.ui-ed__menu button:hover { background: var(--ui-ed-hover); }\n.ui-ed__avatar {\n  display: grid;\n  place-items: center;\n  width: 26px;\n  height: 26px;\n  flex: none;\n  border-radius: 50%;\n  background: var(--ui-ed-chip);\n  box-shadow: inset 0 0 0 1px var(--ui-ed-chip-line);\n  font-size: 10.5px;\n  font-weight: 600;\n  color: var(--ui-ed-text);\n}\n.ui-ed__menu-text { display: grid; flex: 1; min-width: 0; overflow-wrap: anywhere; }\n.ui-ed__menu-text small { font-size: 12px; color: var(--ui-ed-muted); overflow: hidden; white-space: nowrap; text-overflow: ellipsis; }\n.ui-ed__tick { color: var(--ui-ed-ink); }\n\n.ui-ed__file {\n  display: inline-flex;\n  align-items: center;\n  gap: 5px;\n  min-width: 0;\n  font-size: 13px;\n  color: var(--ui-ed-muted);\n  white-space: nowrap;\n}\n/* The file name shortens, the remove button always stays in reach */\n.ui-ed__file-name { min-width: 0; overflow: hidden; text-overflow: ellipsis; }\n.ui-ed__file button,\n.ui-ed__attach {\n  display: grid;\n  place-items: center;\n  border: 0;\n  background: none;\n  color: var(--ui-ed-muted) !important;\n  transition: background-color 160ms ease, color 160ms ease;\n}\n.ui-ed__file button { flex: none; width: 20px; height: 20px; padding: 0; border-radius: calc(var(--aui-radius-sm, 7px) - 1px); }\n.ui-ed__file button svg { width: 13px; height: 13px; }\n.ui-ed__file button:hover { background: var(--ui-ed-hover); color: var(--ui-ed-ink) !important; }\n.ui-ed__attach { display: inline-flex; min-width: 0; gap: 4px; padding: 3px 6px; border-radius: calc(var(--aui-radius-sm, 7px) + 1px); font-size: 13px; white-space: nowrap; }\n.ui-ed__attach:hover { background: var(--ui-ed-hover); color: var(--ui-ed-ink) !important; }\n\n/* Body */\n.ui-ed__body { padding: 12px 14px 4px; }\n.ui-ed__text {\n  margin: -4px -6px;\n  padding: 4px 6px;\n  border-radius: calc(var(--aui-radius, 10px) - 2px);\n  font-size: 15px;\n  line-height: 1.6;\n  color: var(--ui-ed-text);\n  white-space: pre-line;\n  overflow-wrap: anywhere;\n  cursor: text;\n  transition: background-color 160ms ease;\n  animation: ui-ed-fade 280ms ease both;\n}\n.ui-ed__text:hover { background: var(--ui-ed-hover); }\n.ui-ed__text a {\n  color: var(--ui-ed-text);\n  text-decoration: underline;\n  text-decoration-color: color-mix(in srgb, var(--ui-ed-text) 35%, transparent);\n  text-decoration-thickness: 1.5px;\n  text-underline-offset: 4px;\n}\n.ui-ed__text a:hover { text-decoration-color: currentColor; }\n.ui-ed__edit {\n  display: block;\n  width: calc(100% + 12px);\n  margin: -4px -6px;\n  padding: 4px 6px;\n  border: 0;\n  border-radius: calc(var(--aui-radius, 10px) - 2px);\n  background: var(--ui-ed-hover);\n  box-shadow: inset 0 0 0 1px var(--aui-border, var(--ui-ed-chip-line));\n  outline: none;\n  resize: none;\n  overflow: hidden;\n  font: inherit;\n  font-size: 15px;\n  line-height: 1.6;\n  color: var(--ui-ed-ink);\n}\n\n/* Actions */\n.ui-ed__actions {\n  display: flex;\n  align-items: center;\n  justify-content: space-between;\n  gap: 10px;\n  flex-wrap: wrap;\n  padding: 10px 10px 10px 14px;\n}\n.ui-ed__tones { display: flex; flex-wrap: wrap; align-items: center; gap: 2px; min-width: 0; }\n.ui-ed__tones button {\n  display: inline-flex;\n  align-items: center;\n  height: 28px;\n  padding: 0 9px;\n  border: 0;\n  border-radius: calc(var(--aui-radius-sm, 7px) + 1px);\n  background: none;\n  font-size: 12.5px;\n  color: var(--ui-ed-muted) !important;\n  transition: background-color 160ms ease, color 160ms ease;\n}\n.ui-ed__tones button:hover { color: var(--ui-ed-ink) !important; }\n.ui-ed__tones button[aria-pressed=\"true\"] { background: var(--aui-subtle, var(--ui-ed-chip)); color: var(--ui-ed-ink) !important; box-shadow: inset 0 0 0 1px var(--aui-border, var(--ui-ed-chip-line)); }\n.ui-ed__tones .ui-ed__edit-btn { width: 28px; padding: 0; justify-content: center; margin-left: 4px; }\n.ui-ed__buttons { display: flex; gap: 8px; margin-left: auto; }\n.ui-ed__secondary,\n.ui-ed__primary {\n  display: inline-flex;\n  align-items: center;\n  gap: 7px;\n  height: 36px;\n  padding: 0 14px;\n  border: 0;\n  border-radius: var(--aui-radius, 10px);\n  font-size: 14px;\n  font-weight: 500;\n  transition: background-color 160ms ease, transform 160ms ease, filter 160ms ease;\n}\n.ui-ed__secondary { background: var(--ui-ed-card); box-shadow: inset 0 0 0 1px var(--ui-ed-card-line); color: var(--ui-ed-text) !important; }\n.ui-ed__secondary:hover { background: var(--ui-ed-hover); }\n.ui-ed__primary {\n  background: linear-gradient(180deg, var(--ui-ed-btn-top), var(--ui-ed-btn-bottom));\n  box-shadow: 0 0 0 1px var(--ui-ed-btn-ring), inset 0 1px 0 rgba(255, 255, 255, 0.12);\n  color: var(--ui-ed-btn-text) !important;\n}\n.ui-ed__primary:hover { filter: brightness(1.12); }\n.ui-ed__secondary:active, .ui-ed__primary:active { transform: scale(0.98); }\n.ui-ed__spinner {\n  width: 13px;\n  height: 13px;\n  border: 1.8px solid color-mix(in srgb, var(--ui-ed-btn-text) 30%, transparent);\n  border-top-color: var(--ui-ed-btn-text);\n  border-radius: 50%;\n  animation: ui-ed-spin 700ms linear infinite;\n}\n\n/* ---------- Receipt after send / discard ---------- */\n\n.ui-ed__receipt {\n  display: flex;\n  align-items: center;\n  gap: 10px;\n  padding: 12px 10px 12px 12px;\n  border: 1px solid var(--ui-ed-card-line);\n  border-radius: var(--aui-radius-lg, 16px);\n  background: var(--aui-surface, var(--ui-ed-card));\n  box-shadow: var(--ui-ed-shadow);\n  font-size: 14px;\n  color: var(--ui-ed-text);\n  animation: ui-ed-in 320ms var(--ui-ed-ease) both;\n}\n.ui-ed__receipt b { font-weight: 500; color: var(--ui-ed-ink); }\n.ui-ed__receipt-icon {\n  display: grid;\n  place-items: center;\n  width: 26px;\n  height: 26px;\n  flex: none;\n  border-radius: 50%;\n  background: var(--ui-ed-chip);\n  color: var(--ui-ed-muted);\n}\n.ui-ed__receipt-icon[data-tone=\"ok\"] { background: var(--ui-ed-ok-bg); color: var(--ui-ed-ok); }\n.ui-ed__receipt-icon svg { width: 14px; height: 14px; stroke-width: 2.2; }\n.ui-ed__receipt-text { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n.ui-ed__undo {\n  padding: 4px 8px;\n  border: 0;\n  border-radius: calc(var(--aui-radius-sm, 7px) + 1px);\n  background: none;\n  font-size: 13px;\n  font-weight: 500;\n  color: var(--ui-ed-ink) !important;\n  transition: background-color 160ms ease;\n}\n.ui-ed__undo:hover { background: var(--ui-ed-hover); }\n\n/* ---------- Footer on the tray ---------- */\n\n.ui-ed__foot { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; padding: 10px 10px 6px; }\n.ui-ed__agent { min-width: 0; overflow-wrap: anywhere; font-size: 14px; color: var(--ui-ed-ink); }\n.ui-ed__badge {\n  flex: none;\n  white-space: nowrap;\n  padding: 2px 8px;\n  border-radius: calc(var(--aui-radius-sm, 7px) + 1px);\n  font-size: 12.5px;\n  font-weight: 500;\n  animation: ui-ed-fade 260ms ease both;\n}\n.ui-ed__badge[data-tone=\"ok\"] { background: var(--ui-ed-ok-bg); color: var(--ui-ed-ok); }\n.ui-ed__badge[data-tone=\"muted\"] { background: var(--aui-subtle, var(--ui-ed-chip)); color: var(--ui-ed-muted); }\n.ui-ed__hint { margin-left: auto; font-size: 12px; color: var(--ui-ed-muted); }\n\n@keyframes ui-ed-in { from { opacity: 0; transform: translateY(4px) scale(0.99); } }\n@keyframes ui-ed-fade { from { opacity: 0; } }\n@keyframes ui-ed-menu { from { opacity: 0; transform: scale(0.96) translateY(-4px); } }\n@keyframes ui-ed-spin { to { transform: rotate(360deg); } }\n\n@media (max-width: 480px) {\n  .ui-ed__email, .ui-ed__hint { display: none; }\n}\n@media (prefers-reduced-motion: reduce) {\n  .ui-ed__outer[data-smooth] { transition: none; }\n  .ui-ed__card, .ui-ed__receipt, .ui-ed__text, .ui-ed__badge, .ui-ed__menu { animation: none; }\n}\n\n\n/* Text fields: no focus box while typing – also against global :focus-visible rules of the host page */\n.ui-ed input:not([type=\"checkbox\"]):not([type=\"radio\"]):focus-visible,\n.ui-ed textarea:focus-visible,\n.ui-ed [contenteditable]:focus-visible { outline: none; }\n/* Dark mode: follows a .dark class or data-theme=\"dark\" on any ancestor, e.g. <html> */\n:where(.dark, [data-theme=\"dark\"]) .ui-ed {\n  --ui-ed-tray: var(--aui-subtle, #161618);\n  --ui-ed-card: #232326;\n  --ui-ed-card-line: var(--aui-border, rgba(255, 255, 255, 0.08));\n  --ui-ed-line: var(--aui-border, rgba(255, 255, 255, 0.07));\n  --ui-ed-ink: var(--aui-ink, #ededed);\n  --ui-ed-text: var(--aui-ink, #c4c4c4);\n  --ui-ed-muted: var(--aui-muted, #8f8f8f);\n  --ui-ed-chip: #2a2a2d;\n  --ui-ed-chip-line: rgba(255, 255, 255, 0.08);\n  --ui-ed-hover: var(--aui-subtle, rgba(255, 255, 255, 0.05));\n  --ui-ed-warn: var(--aui-orange, #f2a15c);\n  --ui-ed-warn-bg: color-mix(in srgb, var(--aui-orange, #f2a15c) 14%, transparent);\n  --ui-ed-ok: var(--aui-success, #7dcf9f);\n  --ui-ed-ok-bg: color-mix(in srgb, var(--aui-green, #7dcf9f) 14%, transparent);\n  --ui-ed-btn-top: #f4f4f5;\n  --ui-ed-btn-bottom: #e4e4e7;\n  --ui-ed-btn-ring: rgba(0, 0, 0, 0.6);\n  --ui-ed-btn-text: #121213;\n  --ui-ed-focus: var(--aui-focus, rgba(77, 141, 255, 0.8));\n  --ui-ed-shadow: 0 1px 2px rgba(0, 0, 0, 0.4);\n}\n`;\n"}]}