{"$schema":"https://ui.shadcn.com/schema/registry-item.json","name":"email-draft-clean","type":"registry:ui","title":"Email Draft (Clean)","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-clean/email-draft-clean.tsx","type":"registry:ui","content":"\"use client\";\n\nimport { useEffect, useLayoutEffect, useRef, useState, type ReactNode, type RefObject } from \"react\";\n\n/*\n * Email Draft (Clean) – an agent-written email waiting for review, in a single self-contained file.\n * Clean style: no tray – one white card with hairline shadows. The record it's about (reference, status, amount)\n * heads the card; below it the email: recipient you can switch, an attachment you can remove, tone variants,\n * inline editing. The last row holds who wrote it, its state, Discard and Send.\n * Sending or discarding folds the email into a one-line receipt with Undo; only the content glides to its new height.\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-edc\", className].filter(Boolean).join(\" \")} data-phase={phase}>\n      <style href=\"ui-email-draft-clean\" precedence=\"default\">\n        {css}\n      </style>\n\n      {/* The record the email is about */}\n      <div className=\"ui-edc__record\">\n        <div className=\"ui-edc__ref\">\n          <span className=\"ui-edc__id\" title={reference}>\n            {reference}\n          </span>\n          {status && (\n            <span className=\"ui-edc__status\" dir=\"auto\" title={status}>\n              {status}\n            </span>\n          )}\n          <span className=\"ui-edc__amount\">{amount}</span>\n        </div>\n        <span className=\"ui-edc__account\" dir=\"auto\">\n          {account}\n        </span>\n      </div>\n\n      {/* Email ↔ receipt – only this part glides to its new height, the last row below always stays in view */}\n      <div className=\"ui-edc__outer\" ref={outer} data-menu={menu ? \"\" : undefined}>\n        <div ref={inner}>\n          {open ? (\n            <div className=\"ui-edc__draft\" data-sending={phase === \"sending\" ? \"\" : undefined}>\n              <div className=\"ui-edc__meta\">\n                <div className=\"ui-edc__to\" ref={menuRef}>\n                  <span className=\"ui-edc__label\">To</span>\n                  {to.email ? (\n                    <button\n                      type=\"button\"\n                      className=\"ui-edc__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-edc__name\" dir=\"auto\">\n                        {to.name}\n                      </span>\n                      <span className=\"ui-edc__email\">{to.email}</span>\n                      <svg viewBox=\"0 0 24 24\" aria-hidden=\"true\">\n                        <path d=\"m8 10 4 4 4-4\" />\n                      </svg>\n                    </button>\n                  ) : (\n                    <span className=\"ui-edc__email\">No recipient</span>\n                  )}\n                  {menu && (\n                    <ul className=\"ui-edc__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-edc__avatar\" aria-hidden=\"true\">\n                              {initials(c.name)}\n                            </span>\n                            <span className=\"ui-edc__menu-text\" dir=\"auto\">\n                              {c.name}\n                              <small>{c.email}</small>\n                            </span>\n                            {c.email === to.email && (\n                              <svg className=\"ui-edc__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-edc__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-edc__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-edc__attach\" onClick={() => setFile(attachment)}>\n                      <Icon>\n                        <path d=\"M12 6v12M6 12h12\" />\n                      </Icon>\n                      <span className=\"ui-edc__file-name\" title={attachment}>\n                        Attach {attachment}\n                      </span>\n                    </button>\n                  )\n                )}\n              </div>\n\n              <div className=\"ui-edc__body\">\n                {editing ? (\n                  <textarea\n                    ref={textRef}\n                    className=\"ui-edc__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-edc__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-edc__tune\">\n                <div className=\"ui-edc__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-edc__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                <span className=\"ui-edc__hint\">⌘ Enter to send</span>\n              </div>\n            </div>\n          ) : (\n            <div className=\"ui-edc__receipt\" role=\"status\">\n              <span className=\"ui-edc__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-edc__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-edc__undo\" onClick={undo}>\n                Undo\n              </button>\n            </div>\n          )}\n        </div>\n      </div>\n\n      {/* The last row of the card: who wrote it, its state, and the decision */}\n      <div className=\"ui-edc__foot\">\n        <span className=\"ui-edc__agent\" title={agent}>\n          {agent}\n        </span>\n        <span className=\"ui-edc__badge\" data-tone={badge.tone} key={badge.text}>\n          {badge.text}\n        </span>\n        {open && (\n          <div className=\"ui-edc__buttons\">\n            <button type=\"button\" className=\"ui-edc__secondary\" onClick={discard} disabled={phase === \"sending\"}>\n              Discard\n            </button>\n            <button type=\"button\" className=\"ui-edc__primary\" onClick={send} disabled={phase === \"sending\" || !to.email}>\n              {phase === \"sending\" ? (\n                <>\n                  <span className=\"ui-edc__spinner\" aria-hidden=\"true\" />\n                  Sending\n                </>\n              ) : (\n                \"Send email\"\n              )}\n            </button>\n          </div>\n        )}\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/* Colors and motion as variables – override them on .ui-edc */\n.ui-edc {\n  --ui-edc-card: #ffffff;\n  --ui-edc-strong: #000000;\n  --ui-edc-ink: var(--aui-ink, rgba(0, 0, 0, 0.88));\n  --ui-edc-text: var(--aui-muted, rgba(0, 0, 0, 0.61));\n  --ui-edc-muted: var(--aui-muted, rgba(0, 0, 0, 0.45));\n  --ui-edc-faint: var(--aui-placeholder, rgba(0, 0, 0, 0.27));\n  --ui-edc-icon: var(--aui-muted, rgba(0, 0, 0, 0.447));\n  --ui-edc-line: var(--aui-border, rgba(0, 0, 0, 0.06));\n  --ui-edc-fill: rgba(0, 0, 0, 0.06);\n  --ui-edc-wash: var(--aui-subtle, rgba(0, 0, 0, 0.03));\n  --ui-edc-solid: var(--aui-primary, rgba(0, 0, 0, 0.88));\n  --ui-edc-on-solid: var(--aui-on-primary, #fcfcfc);\n  --ui-edc-accent: rgba(0, 96, 226, 0.765);\n  --ui-edc-ok: var(--aui-success, #1e8a4f);\n  --ui-edc-ok-bg: color-mix(in srgb, var(--aui-green, #5fc88a) 8%, transparent);\n  --ui-edc-warn: #b48906;\n  --ui-edc-warn-bg: color-mix(in srgb, var(--aui-amber, #e8b000) 12%, transparent);\n  /* Strokes are shadows: a 0.5px hairline plus a soft lift */\n  --ui-edc-shadow: 0 0 0 0.5px rgba(0, 0, 0, 0.06), 0 1px 1px -1px rgba(0, 0, 0, 0.1), 0 1px 2px 0 rgba(0, 0, 0, 0.05);\n  --ui-edc-shadow-pop: var(--aui-shadow-popover, 0 0 0 0.5px rgba(0, 0, 0, 0.08), 0 12px 28px -10px rgba(0, 0, 0, 0.16), 0 1px 2px 0 rgba(0, 0, 0, 0.05));\n  --ui-edc-focus: var(--aui-focus, rgba(0, 96, 226, 0.7));\n  --ui-edc-ease: var(--aui-ease, cubic-bezier(0.22, 1, 0.36, 1));\n  position: relative;\n  box-sizing: border-box;\n  container-type: inline-size;\n  display: flex;\n  flex-direction: column;\n  width: 100%;\n  max-width: 480px;\n  border-radius: var(--aui-radius-lg, 10px);\n  background: var(--aui-surface, var(--ui-edc-card));\n  box-shadow: var(--aui-shadow-card, var(--ui-edc-shadow));\n  font-family: var(--aui-font, \"Inter\", \"InterVariable\", ui-sans-serif, system-ui, -apple-system, \"Segoe UI\", Roboto, sans-serif);\n  font-size: 13px;\n  line-height: 20px;\n  font-weight: 400;\n  color: var(--ui-edc-ink);\n  -webkit-font-smoothing: antialiased;\n}\n.ui-edc *, .ui-edc *::before, .ui-edc *::after { box-sizing: border-box; }\n:where(.ui-edc) button {\n  appearance: none;\n  margin: 0;\n  padding: 0;\n  border: 0;\n  background: none;\n  font: inherit;\n  color: inherit;\n  cursor: pointer;\n  -webkit-tap-highlight-color: transparent;\n}\n.ui-edc button:focus-visible, .ui-edc a:focus-visible { outline: 2px solid var(--ui-edc-focus); outline-offset: 2px; }\n:where(.ui-edc) svg {\n  display: block;\n  width: 16px;\n  height: 16px;\n  flex: none;\n  fill: none;\n  stroke: currentColor;\n  stroke-width: 1.6;\n  stroke-linecap: round;\n  stroke-linejoin: round;\n}\n\n/* ---------- The record, heading the card ---------- */\n\n.ui-edc__record { display: grid; padding: 12px 16px; border-bottom: 0.5px solid var(--ui-edc-line); }\n.ui-edc__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-edc__id { flex: 0 1 auto; min-width: 0; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; font-size: 15px; font-weight: 500; line-height: 24px; color: var(--ui-edc-strong); }\n.ui-edc__status {\n  flex: 0 100 auto;\n  min-width: 0;\n  overflow: hidden;\n  padding: 2px 6px;\n  border-radius: var(--aui-radius-sm, 5px);\n  background: var(--ui-edc-warn-bg);\n  font-size: 12px;\n  font-weight: 500;\n  line-height: 16px;\n  color: var(--ui-edc-warn);\n  white-space: nowrap;\n  text-overflow: ellipsis;\n}\n.ui-edc__amount {\n  flex: none;\n  margin-left: auto;\n  font-size: 15px;\n  font-weight: 500;\n  line-height: 24px;\n  font-variant-numeric: tabular-nums;\n  color: var(--ui-edc-strong);\n}\n.ui-edc__account { overflow-wrap: anywhere; font-size: 12px; line-height: 16px; color: var(--ui-edc-text); }\n\n/* ---------- The email: only this part changes height ---------- */\n\n.ui-edc__outer { position: relative; overflow: hidden; overflow: clip; }\n/* The recipient menu may reach out of the card while it's open – the height doesn't move then */\n.ui-edc__outer[data-menu] { overflow: visible; z-index: 2; }\n.ui-edc__outer[data-smooth] { transition: height 360ms var(--ui-edc-ease); }\n\n.ui-edc__draft { animation: ui-edc-in 320ms var(--ui-edc-ease) both; transition: opacity 220ms ease; }\n.ui-edc__draft[data-sending] { opacity: 0.6; pointer-events: none; }\n\n.ui-edc__meta {\n  display: flex;\n  min-width: 0;\n  align-items: center;\n  justify-content: space-between;\n  gap: 12px;\n  padding: 10px 12px 10px 16px;\n  border-bottom: 0.5px solid var(--ui-edc-line);\n}\n.ui-edc__to { position: relative; display: flex; align-items: center; gap: 8px; min-width: 0; }\n.ui-edc__label { flex: none; font-size: 13px; color: var(--ui-edc-muted); }\n/* Recipient: the button-switch look – a hairline, the address in gray */\n.ui-edc__recipient {\n  display: inline-flex;\n  align-items: center;\n  gap: 6px;\n  min-width: 0;\n  height: 28px;\n  padding: 0 6px 0 10px;\n  border-radius: calc(var(--aui-radius-sm, 5px) + 1px);\n  box-shadow: inset 0 0 0 0.5px var(--ui-edc-line);\n  font-size: 13px;\n  font-weight: 500;\n  white-space: nowrap;\n  color: var(--ui-edc-ink);\n  transition: background-color 160ms ease;\n}\n.ui-edc__recipient:hover,\n.ui-edc__recipient[aria-expanded=\"true\"] { background: var(--ui-edc-wash); }\n/* A long name shortens; the address gives way before it */\n.ui-edc__name { flex: 0 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; }\n.ui-edc__email { flex: 0 100 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; font-weight: 400; color: var(--ui-edc-muted); }\n.ui-edc__recipient svg { color: var(--ui-edc-icon); transition: transform 220ms var(--ui-edc-ease); }\n.ui-edc__recipient[aria-expanded=\"true\"] svg { transform: rotate(180deg); }\n\n/* Recipient menu: a white popover */\n.ui-edc__menu {\n  position: absolute;\n  top: calc(100% + 6px);\n  left: 26px;\n  z-index: 5;\n  display: grid;\n  gap: 2px;\n  width: 260px;\n  max-width: calc(100cqw - 40px);\n  max-height: 288px;\n  overflow-y: auto;\n  overscroll-behavior: contain;\n  margin: 0;\n  padding: 4px;\n  list-style: none;\n  border-radius: var(--aui-radius-lg, 10px);\n  background: var(--aui-overlay, var(--ui-edc-card));\n  box-shadow: var(--ui-edc-shadow-pop);\n  animation: ui-edc-menu 200ms var(--ui-edc-ease) both;\n  transform-origin: top left;\n}\n.ui-edc__menu button {\n  display: flex;\n  align-items: center;\n  gap: 10px;\n  width: 100%;\n  padding: 6px 8px;\n  border-radius: calc(var(--aui-radius-sm, 5px) + 1px);\n  text-align: left;\n  font-size: 13px;\n  line-height: 20px;\n  color: var(--ui-edc-ink);\n}\n.ui-edc__menu button:hover { background: var(--ui-edc-fill); }\n.ui-edc__avatar {\n  display: grid;\n  place-items: center;\n  width: 28px;\n  height: 28px;\n  flex: none;\n  border-radius: 6px;\n  background: var(--ui-edc-fill);\n  font-size: 10px;\n  font-weight: 500;\n  letter-spacing: 0.5px;\n  color: var(--ui-edc-text);\n}\n.ui-edc__menu-text { display: grid; flex: 1; min-width: 0; overflow-wrap: anywhere; }\n.ui-edc__menu-text small { overflow: hidden; font-size: 12px; line-height: 16px; white-space: nowrap; text-overflow: ellipsis; color: var(--ui-edc-muted); }\n.ui-edc__tick { color: var(--ui-edc-accent); stroke-width: 1.8; }\n\n/* Attachment */\n.ui-edc__file {\n  display: inline-flex;\n  align-items: center;\n  gap: 6px;\n  min-width: 0;\n  font-size: 13px;\n  white-space: nowrap;\n  color: var(--ui-edc-text);\n}\n.ui-edc__file > svg { color: var(--ui-edc-icon); }\n.ui-edc__file-name { min-width: 0; overflow: hidden; text-overflow: ellipsis; }\n.ui-edc__file button {\n  display: grid;\n  place-items: center;\n  flex: none;\n  width: 24px;\n  height: 24px;\n  margin-left: -2px;\n  border-radius: calc(var(--aui-radius-sm, 5px) + 1px);\n  color: var(--ui-edc-icon);\n  transition: background-color 160ms ease, color 160ms ease;\n}\n.ui-edc__file button svg { width: 14px; height: 14px; }\n.ui-edc__file button:hover { background: var(--ui-edc-wash); color: var(--ui-edc-ink); }\n.ui-edc__attach {\n  display: inline-flex;\n  align-items: center;\n  gap: 6px;\n  min-width: 0;\n  height: 28px;\n  padding: 0 8px 0 6px;\n  border-radius: calc(var(--aui-radius-sm, 5px) + 1px);\n  font-size: 13px;\n  white-space: nowrap;\n  color: var(--ui-edc-text);\n  transition: background-color 160ms ease, color 160ms ease;\n  animation: ui-edc-fade 220ms ease both;\n}\n.ui-edc__attach svg { color: var(--ui-edc-icon); }\n.ui-edc__attach:hover { background: var(--ui-edc-wash); color: var(--ui-edc-ink); }\n\n/* Body */\n.ui-edc__body { padding: 14px 16px 2px; }\n.ui-edc__text {\n  margin: -4px -6px;\n  padding: 4px 6px;\n  border-radius: calc(var(--aui-radius, 7px) - 1px);\n  font-size: 13px;\n  line-height: 20px;\n  color: var(--ui-edc-ink);\n  white-space: pre-line;\n  overflow-wrap: anywhere;\n  cursor: text;\n  transition: background-color 160ms ease;\n  animation: ui-edc-fade 280ms ease both;\n}\n.ui-edc__text:hover { background: var(--ui-edc-wash); }\n.ui-edc__text a {\n  color: var(--ui-edc-strong);\n  font-weight: 500;\n  text-decoration: underline;\n  text-decoration-color: var(--ui-edc-faint);\n  text-decoration-thickness: 1px;\n  text-underline-offset: 3px;\n  transition: text-decoration-color 160ms ease;\n}\n.ui-edc__text a:hover { text-decoration-color: currentColor; }\n.ui-edc__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, 7px) - 1px);\n  background: var(--ui-edc-wash);\n  box-shadow: inset 0 0 0 0.5px var(--ui-edc-line);\n  outline: none;\n  resize: none;\n  overflow: hidden;\n  font: inherit;\n  font-size: 13px;\n  line-height: 20px;\n  color: var(--ui-edc-strong);\n  caret-color: var(--ui-edc-accent);\n}\n\n/* Tones and the pencil */\n.ui-edc__tune {\n  display: flex;\n  align-items: center;\n  justify-content: space-between;\n  gap: 12px;\n  padding: 14px 12px 14px 16px;\n}\n.ui-edc__tones { display: flex; flex-wrap: wrap; align-items: center; gap: 4px; min-width: 0; }\n.ui-edc__tones button {\n  display: inline-flex;\n  align-items: center;\n  height: 28px;\n  padding: 4px 10px;\n  border-radius: calc(var(--aui-radius-sm, 5px) + 1px);\n  box-shadow: inset 0 0 0 0.5px var(--ui-edc-line);\n  font-size: 13px;\n  font-weight: 500;\n  line-height: 20px;\n  white-space: nowrap;\n  color: var(--ui-edc-text);\n  transition: background-color 160ms ease, color 160ms ease;\n}\n.ui-edc__tones button:hover { background: var(--ui-edc-wash); color: var(--ui-edc-ink); }\n.ui-edc__tones button[aria-pressed=\"true\"] { background: var(--ui-edc-fill); color: var(--ui-edc-ink); }\n/* Edit: a ghost icon button */\n.ui-edc__tones .ui-edc__edit-btn {\n  justify-content: center;\n  width: 28px;\n  margin-left: 4px;\n  padding: 0;\n  box-shadow: none;\n  color: var(--ui-edc-icon);\n}\n.ui-edc__tones .ui-edc__edit-btn:hover { color: var(--ui-edc-ink); }\n.ui-edc__tones .ui-edc__edit-btn[aria-pressed=\"true\"] { background: var(--ui-edc-fill); color: var(--ui-edc-ink); }\n.ui-edc__hint { flex: none; font-size: 12px; line-height: 16px; white-space: nowrap; color: var(--ui-edc-faint); }\n\n/* ---------- Receipt after send / discard ---------- */\n\n.ui-edc__receipt {\n  display: flex;\n  align-items: center;\n  gap: 10px;\n  padding: 12px 12px 12px 16px;\n  font-size: 13px;\n  color: var(--ui-edc-text);\n  animation: ui-edc-in 320ms var(--ui-edc-ease) both;\n}\n.ui-edc__receipt b { font-weight: 500; color: var(--ui-edc-strong); }\n.ui-edc__receipt-icon {\n  display: grid;\n  place-items: center;\n  width: 24px;\n  height: 24px;\n  flex: none;\n  border-radius: 6px;\n  background: var(--ui-edc-fill);\n  color: var(--ui-edc-icon);\n}\n.ui-edc__receipt-icon[data-tone=\"ok\"] { background: var(--ui-edc-ok-bg); color: var(--ui-edc-ok); }\n.ui-edc__receipt-icon svg { width: 14px; height: 14px; stroke-width: 2; }\n.ui-edc__receipt-text { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n.ui-edc__undo {\n  flex: none;\n  height: 28px;\n  padding: 0 10px;\n  border-radius: calc(var(--aui-radius-sm, 5px) + 1px);\n  font-size: 13px;\n  font-weight: 500;\n  color: var(--ui-edc-ink);\n  transition: background-color 160ms ease;\n}\n.ui-edc__undo:hover { background: var(--ui-edc-wash); }\n\n/* ---------- The last row ---------- */\n\n/* Discard and Send drop to their own row when the row runs out of room */\n.ui-edc__foot {\n  display: flex;\n  flex-wrap: wrap;\n  align-items: center;\n  gap: 8px;\n  min-height: 48px;\n  padding: 10px 10px 10px 16px;\n  border-top: 0.5px solid var(--ui-edc-line);\n}\n.ui-edc__agent { min-width: 0; overflow: hidden; font-size: 13px; white-space: nowrap; text-overflow: ellipsis; color: var(--ui-edc-ink); }\n.ui-edc__badge {\n  flex: none;\n  padding: 2px 6px;\n  border-radius: var(--aui-radius-sm, 5px);\n  font-size: 12px;\n  font-weight: 500;\n  line-height: 16px;\n  white-space: nowrap;\n  animation: ui-edc-fade 260ms ease both;\n}\n.ui-edc__badge[data-tone=\"ok\"] { background: var(--ui-edc-ok-bg); color: var(--ui-edc-ok); }\n.ui-edc__badge[data-tone=\"muted\"] { background: var(--ui-edc-fill); color: var(--ui-edc-text); }\n.ui-edc__buttons { display: flex; flex: none; gap: 8px; margin-left: auto; }\n.ui-edc__secondary,\n.ui-edc__primary {\n  display: inline-flex;\n  align-items: center;\n  gap: 6px;\n  height: 28px;\n  padding: 0 10px;\n  border-radius: calc(var(--aui-radius, 7px) - 1px);\n  font-size: 13px;\n  font-weight: 500;\n  line-height: 20px;\n  white-space: nowrap;\n  transition: background-color 160ms ease, box-shadow 160ms ease, transform 160ms var(--ui-edc-ease);\n}\n/* Discard: white with the card's hairline shadow */\n.ui-edc__secondary { background: var(--ui-edc-card); box-shadow: var(--ui-edc-shadow); color: var(--ui-edc-strong); }\n.ui-edc__secondary:hover:not(:disabled) { background: linear-gradient(var(--ui-edc-wash), var(--ui-edc-wash)), var(--ui-edc-card); }\n/* Send: the dark chip */\n.ui-edc__primary { background: var(--ui-edc-solid); color: var(--ui-edc-on-solid); }\n.ui-edc__primary:hover:not(:disabled) { background: var(--ui-edc-strong); }\n.ui-edc__secondary:disabled, .ui-edc__primary:disabled { cursor: default; }\n.ui-edc__secondary:not(:disabled):active, .ui-edc__primary:not(:disabled):active { transform: scale(0.97); }\n.ui-edc__spinner {\n  width: 12px;\n  height: 12px;\n  border: 1.5px solid color-mix(in srgb, var(--ui-edc-on-solid) 30%, transparent);\n  border-top-color: var(--ui-edc-on-solid);\n  border-radius: 50%;\n  animation: ui-edc-spin 700ms linear infinite;\n}\n\n@keyframes ui-edc-in { from { opacity: 0; transform: translateY(4px); } }\n@keyframes ui-edc-fade { from { opacity: 0; } }\n@keyframes ui-edc-menu { from { opacity: 0; transform: scale(0.97) translateY(-4px); } }\n@keyframes ui-edc-spin { to { transform: rotate(360deg); } }\n\n/* Narrow containers (phones): the address, hint and author step back */\n@container (max-width: 440px) {\n  .ui-edc__email, .ui-edc__hint { display: none; }\n}\n@container (max-width: 380px) {\n  .ui-edc__record { padding: 12px 14px; }\n  .ui-edc__meta, .ui-edc__tune, .ui-edc__receipt, .ui-edc__foot { padding-left: 14px; }\n  .ui-edc__body { padding-left: 14px; padding-right: 14px; }\n  .ui-edc[data-phase=\"draft\"] .ui-edc__agent,\n  .ui-edc[data-phase=\"sending\"] .ui-edc__agent { display: none; }\n  .ui-edc__tones { gap: 2px; }\n  .ui-edc__tones button { padding: 4px 8px; }\n  .ui-edc__tones .ui-edc__edit-btn { margin-left: 2px; }\n}\n/* Touch screens: taller hit targets */\n@media (pointer: coarse) {\n  .ui-edc__recipient, .ui-edc__tones button, .ui-edc__secondary, .ui-edc__primary, .ui-edc__undo, .ui-edc__attach { height: 34px; }\n  .ui-edc__tones .ui-edc__edit-btn { width: 34px; }\n  .ui-edc__file button { width: 30px; height: 30px; }\n  .ui-edc__menu button { padding: 9px 8px; }\n}\n@media (prefers-reduced-motion: reduce) {\n  .ui-edc__outer[data-smooth] { transition: none; }\n  .ui-edc__draft, .ui-edc__receipt, .ui-edc__text, .ui-edc__badge, .ui-edc__menu, .ui-edc__attach { animation: none; }\n}\n\n/* Text fields: no focus box while typing – also against global :focus-visible rules of the host page */\n.ui-edc input:not([type=\"checkbox\"]):not([type=\"radio\"]):focus-visible,\n.ui-edc textarea:focus-visible,\n.ui-edc [contenteditable]:focus-visible { outline: none; }\n\n/* Dark mode: follows a .dark class or data-theme=\"dark\" on any ancestor, e.g. <html> */\n:where(.dark, [data-theme=\"dark\"]) .ui-edc {\n  --ui-edc-card: #1c1c1e;\n  --ui-edc-strong: #ffffff;\n  --ui-edc-ink: var(--aui-ink, rgba(255, 255, 255, 0.9));\n  --ui-edc-text: var(--aui-muted, rgba(255, 255, 255, 0.62));\n  --ui-edc-muted: var(--aui-muted, rgba(255, 255, 255, 0.46));\n  --ui-edc-faint: var(--aui-placeholder, rgba(255, 255, 255, 0.3));\n  --ui-edc-icon: var(--aui-muted, rgba(255, 255, 255, 0.5));\n  --ui-edc-line: var(--aui-border, rgba(255, 255, 255, 0.08));\n  --ui-edc-fill: rgba(255, 255, 255, 0.08);\n  --ui-edc-wash: var(--aui-subtle, rgba(255, 255, 255, 0.04));\n  --ui-edc-solid: var(--aui-primary, rgba(255, 255, 255, 0.92));\n  --ui-edc-on-solid: var(--aui-on-primary, #161618);\n  --ui-edc-accent: var(--aui-blue, #4fb0fe);\n  --ui-edc-ok: var(--aui-green, #5fc88a);\n  --ui-edc-ok-bg: color-mix(in srgb, var(--aui-green, #7dcf9f) 14%, transparent);\n  --ui-edc-warn: var(--aui-amber, #e6c24d);\n  --ui-edc-warn-bg: color-mix(in srgb, var(--aui-amber, #e6c24d) 14%, transparent);\n  --ui-edc-shadow: 0 0 0 0.5px rgba(255, 255, 255, 0.1), 0 1px 2px 0 rgba(0, 0, 0, 0.4);\n  --ui-edc-shadow-pop: var(--aui-shadow-popover, 0 0 0 0.5px rgba(255, 255, 255, 0.12), 0 12px 28px -10px rgba(0, 0, 0, 0.6));\n  --ui-edc-focus: var(--aui-focus, rgba(77, 141, 255, 0.8));\n}\n:where(.dark, [data-theme=\"dark\"]) .ui-edc__primary:hover:not(:disabled) { background: #ffffff; }\n`;\n"}]}