{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "email",
  "type": "registry:component",
  "title": "Email",
  "description": "React Email compositions with Control UI colors and typography, image layouts, columns, and HTML or plain-text export.",
  "dependencies": [
    "react-email@^6.9.5"
  ],
  "registryDependencies": [
    "https://control-ui.dev/r/core.json"
  ],
  "files": [
    {
      "path": "src/registry/sources/control-ui/email/README.md",
      "target": "@components/control-ui/email/README.md",
      "type": "registry:file",
      "content": "# Email\n\nCompose branded emails with `react-email`. `EmailLayout` supplies a resolved Control UI theme to React Email's Tailwind renderer. `EmailHeading`, `EmailText`, `EmailButton`, and `EmailLink` apply semantic styles; compose them with React Email's `Section`, `Row`, `Column`, `Img`, and `Hr`.\n\n## Resolve the theme on the server\n\nRead the installed `styles/theme.css` and `styles/skin-theme.css` as strings, then pass them in that order to `emailThemeFromCss([coreCss, skinCss, overrideCss], \"light\")`. Include any Tailwind palette CSS before core if your theme references its variables. App overrides must use the same `[data-skin]` selectors as the theme. Pass only one skin's CSS, not the whole site's bundled stylesheet. Generate the theme at build time or reuse it across messages. Rebuild it when the theme changes.\n\n`createEmailTheme(tokens)` also accepts a map of resolved token values, for example from a theme editor. Both APIs return serializable `EmailTheme` data without browser dependencies. The default root size is 16px; pass the app's root pixel size as the last argument if different.\n\nColors use the existing Control UI evaluator: OKLCH, relative OKLCH, hex, and token aliases. Unresolved or unsupported values throw an error naming the token. Sizes convert from px/rem to px. Font families, heading weights, line heights, and letter spacing come from the theme. Body text uses `--text-body-lg`; secondary text uses `--text-body`. Email paragraph line height is 1.6 for reading.\n\nButtons use `--radius-control`, `--control-h-md` (derived from `--control-h`), `--padding-x`, and `--text-body`, matching the default Control UI button dimensions. Vertical padding is calculated from the target height and React Email's 120% label line height; wrapped labels can grow taller. Containers and inset panels use `--radius-panel`, and images use `--radius-scene`. Lengths support px/rem, zero, aliases, and nested binary `calc()` arithmetic; unsupported expressions fail before export. Email corners use standard `border-radius`; skin-specific corner shapes and effects remain web-only.\n\nThe outer background must be opaque. Translucent card and button fills, text, and borders are flattened against their email surfaces. Override a token with an opaque color when a custom composition puts it on a different surface. This output shares the theme's colors and typography; interactive effects and skin decorations do not transfer to email.\n\n## Compose and render\n\nRender an `EmailLayout` with a required `theme` and inbox `preview`, then put the themed components inside it. Use `className` for React Email utilities or `style` for per-instance adjustments. Layouts use table-backed `Row` and `Column`; use explicit percentage widths for side-by-side content. The container is fluid up to 600px.\n\nThe five included templates are `InvitationEmail`, `ProductEmail`, `EditorialEmail`, `NewsletterEmail`, and `SummaryEmail`. Their content, links, brand, images, and theme are supplied by props. Each can be copied and adapted independently. Keep summary metrics to a short row; use repeated rows for larger datasets.\n\nCall `await render(<YourEmail />)` from `react-email`, then `toPlainText(html)` for the plain-text alternative. Pass both to your existing delivery provider. This module does not send mail or require Resend. In Next.js, keep the rendering path on the server; if needed, add `react-email` to `serverExternalPackages`.\n\n## Fonts, images, and verification\n\nKeep fallback fonts in the theme. For a custom web font, pass React Email's `Font` through `EmailLayout`'s `head` prop and supply a publicly accessible font URL; recipients whose client cannot load it use the fallback. Supply public HTTPS image URLs and descriptive alt text. Prefer PNG or JPEG; GIF is suitable for animation. The gallery uses external sample photos and example.com links, which must be replaced before sending.\n\nThe chosen light or dark palette is baked into the generated HTML. Mail clients can still recolor it in their own dark mode. Browser previews show the generated email document, but do not emulate Gmail or Outlook. Verify actual deliveries in Gmail, Outlook, and Apple Mail, including mobile, blocked images, and dark mode, before using a template in production.\n"
    },
    {
      "path": "src/registry/sources/control-ui/email/email.tsx",
      "target": "@components/control-ui/email/email.tsx",
      "type": "registry:component",
      "content": "import type { ReactNode } from \"react\";\nimport {\n  Body,\n  Button,\n  type ButtonProps,\n  Container,\n  Head,\n  Heading,\n  type HeadingProps,\n  Html,\n  Link,\n  type LinkProps,\n  Preview,\n  pixelBasedPreset,\n  Tailwind,\n  type TailwindConfig,\n  Text,\n  type TextProps,\n} from \"react-email\";\nimport type { EmailTheme } from \"./theme\";\n\nfunction tailwindTheme(theme: EmailTheme): TailwindConfig {\n  return {\n    presets: [pixelBasedPreset],\n    theme: {\n      extend: {\n        colors: theme.colors,\n        borderRadius: theme.radii,\n        minHeight: { control: theme.button.height },\n        padding: { \"control-x\": theme.button.paddingInline, \"control-y\": theme.button.paddingBlock },\n        fontFamily: { body: theme.fonts.body, display: theme.fonts.display },\n        fontSize: {\n          ...Object.fromEntries(Object.entries(theme.text).map(([name, { fontSize, ...options }]) => [name, [fontSize, options]])),\n          control: [theme.button.fontSize, { lineHeight: theme.button.lineHeight }],\n        },\n      },\n    },\n  };\n}\n\nexport function EmailLayout({\n  theme,\n  preview,\n  children,\n  head,\n  lang = \"en\",\n  dir = \"ltr\",\n}: {\n  theme: EmailTheme;\n  preview: string;\n  children: ReactNode;\n  head?: ReactNode;\n  lang?: string;\n  dir?: \"ltr\" | \"rtl\";\n}) {\n  return (\n    <Html lang={lang} dir={dir}>\n      <Tailwind config={tailwindTheme(theme)}>\n        <Head>{head}</Head>\n        <Body className=\"m-0 bg-background p-4 font-body text-body text-foreground\">\n          <Preview>{preview}</Preview>\n          <Container className=\"mx-auto w-full max-w-[600px] rounded-panel bg-card p-6 text-card-foreground\">{children}</Container>\n        </Body>\n      </Tailwind>\n    </Html>\n  );\n}\n\nconst headingClasses = { h1: \"text-heading-1\", h2: \"text-heading-2\", h3: \"text-heading-3\", h4: \"text-heading-4\" };\n\nexport function EmailHeading({ as = \"h1\", className = \"\", ...props }: Omit<HeadingProps, \"as\"> & { as?: keyof typeof headingClasses }) {\n  return <Heading {...props} as={as} className={`mb-4 mt-0 font-display text-card-foreground ${headingClasses[as]} ${className}`} />;\n}\n\nexport function EmailText({ tone = \"default\", className = \"\", style, ...props }: TextProps & { tone?: \"default\" | \"muted\" }) {\n  const textColor = tone === \"muted\" ? \"text-muted-foreground\" : \"text-card-foreground\";\n  return (\n    <Text\n      {...props}\n      style={{ overflowWrap: \"break-word\", ...style }}\n      className={`mb-4 mt-0 font-body text-body ${textColor} ${className}`}\n    />\n  );\n}\n\nexport function EmailButton({ className = \"\", ...props }: ButtonProps) {\n  return (\n    <Button\n      {...props}\n      className={`box-border min-h-control rounded-control bg-primary px-control-x py-control-y text-center font-body text-control font-medium text-primary-foreground no-underline ${className}`}\n    />\n  );\n}\n\nexport function EmailLink({ className = \"\", ...props }: LinkProps) {\n  return <Link {...props} className={`font-body text-primary-text underline ${className}`} />;\n}\n"
    },
    {
      "path": "src/registry/sources/control-ui/email/length.ts",
      "target": "@components/control-ui/email/length.ts",
      "type": "registry:component",
      "content": "function parseLengthQuantity(value: string, rootFontSize: number) {\n  const match = /^(-?\\d*\\.?\\d+)(px|rem)?$/.exec(value.trim());\n  if (!match) return null;\n  return { amount: Number(match[1]) * (match[2] === \"rem\" ? rootFontSize : 1), unit: match[2] ? \"px\" : \"\" };\n}\n\nfunction calculateLengthExpression(expression: string, rootFontSize: number) {\n  const match = /^\\s*(-?\\d*\\.?\\d+(?:px|rem)?)\\s*([+*/-])\\s*(-?\\d*\\.?\\d+(?:px|rem)?)\\s*$/.exec(expression);\n  if (!match) return null;\n  const left = parseLengthQuantity(match[1], rootFontSize);\n  const right = parseLengthQuantity(match[3], rootFontSize);\n  if (!left || !right) return null;\n  const operator = match[2];\n  if ((operator === \"+\" || operator === \"-\") && left.unit === right.unit) {\n    return `${left.amount + (operator === \"+\" ? right.amount : -right.amount)}${left.unit}`;\n  }\n  if (operator === \"*\" && !(left.unit && right.unit)) return `${left.amount * right.amount}${left.unit || right.unit}`;\n  const dividesByScalar = operator === \"/\" && !right.unit && right.amount !== 0;\n  if (dividesByScalar) return `${left.amount / right.amount}${left.unit}`;\n  return null;\n}\n\nexport function emailLengthPixels(name: string, value: string, rootFontSize: number, allowZero = false): number {\n  let resolved = value;\n  for (let depth = 0; depth < 16 && resolved.includes(\"calc(\"); depth++) {\n    const simplified = resolved.replace(\n      /calc\\(([^()]*)\\)/g,\n      (original, expression: string) => calculateLengthExpression(expression, rootFontSize) ?? original,\n    );\n    if (simplified === resolved) break;\n    resolved = simplified;\n  }\n  const result = parseLengthQuantity(resolved, rootFontSize);\n  const isLength = result && (result.unit === \"px\" || result.amount === 0);\n  const isValidLength = isLength && Number.isFinite(result.amount) && (allowZero ? result.amount >= 0 : result.amount > 0);\n  if (!isValidLength) {\n    throw new Error(`Email theme: ${name} must resolve to a ${allowZero ? \"non-negative\" : \"positive\"} px/rem length, received ${value}.`);\n  }\n  return result.amount;\n}\n"
    },
    {
      "path": "src/registry/sources/control-ui/email/templates.tsx",
      "target": "@components/control-ui/email/templates.tsx",
      "type": "registry:component",
      "content": "import { Column, Hr, Img, Row, Section } from \"react-email\";\nimport { EmailButton, EmailHeading, EmailLayout, EmailLink, EmailText } from \"./email\";\nimport type { EmailTheme } from \"./theme\";\n\ntype EmailBrandProps = { theme: EmailTheme; brand: string; footer: string };\n\nfunction EmailFooter({ brand, children }: { brand: string; children: string }) {\n  return (\n    <>\n      <Hr className=\"my-6 border-0 border-t border-solid border-t-border\" />\n      <EmailText tone=\"muted\" className=\"mb-1 text-caption\">\n        {brand}\n      </EmailText>\n      <EmailText tone=\"muted\" className=\"mb-0 text-caption\">\n        {children}\n      </EmailText>\n    </>\n  );\n}\n\nexport function InvitationEmail({\n  theme,\n  brand,\n  footer,\n  inviter,\n  workspace,\n  inviteUrl,\n}: EmailBrandProps & {\n  inviter: string;\n  workspace: string;\n  inviteUrl: string;\n}) {\n  return (\n    <EmailLayout theme={theme} preview={`${inviter} invited you to ${workspace}`}>\n      <EmailText tone=\"muted\" className=\"mb-8 text-caption\">\n        {brand}\n      </EmailText>\n      <EmailHeading>A place for your next idea.</EmailHeading>\n      <EmailText>\n        {inviter} invited you to join <strong>{workspace}</strong>. Bring your work, share a little inspiration, and make something\n        together.\n      </EmailText>\n      <Section className=\"my-6 rounded-panel bg-muted p-5\">\n        <EmailHeading as=\"h3\">Your team is waiting</EmailHeading>\n        <EmailText className=\"mb-0\">Projects, conversations, and the details that move work forward. All in one shared space.</EmailText>\n      </Section>\n      <EmailButton href={inviteUrl}>Join {workspace}</EmailButton>\n      <EmailFooter brand={brand}>{footer}</EmailFooter>\n    </EmailLayout>\n  );\n}\n\nexport function ProductEmail({\n  theme,\n  brand,\n  footer,\n  title,\n  description,\n  imageUrl,\n  imageAlt,\n  actionUrl,\n}: EmailBrandProps & {\n  title: string;\n  description: string;\n  imageUrl: string;\n  imageAlt: string;\n  actionUrl: string;\n}) {\n  return (\n    <EmailLayout theme={theme} preview={title}>\n      <EmailText tone=\"muted\" className=\"mb-6 text-caption\">\n        {brand} / NEW RELEASE\n      </EmailText>\n      <Img src={imageUrl} alt={imageAlt} width=\"552\" className=\"mb-6 block h-auto w-full rounded-scene\" />\n      <EmailHeading>{title}</EmailHeading>\n      <EmailText>{description}</EmailText>\n      <EmailButton href={actionUrl}>Explore what’s new</EmailButton>\n      <EmailFooter brand={brand}>{footer}</EmailFooter>\n    </EmailLayout>\n  );\n}\n\nexport function EditorialEmail({\n  theme,\n  brand,\n  footer,\n  title,\n  description,\n  imageUrl,\n  imageAlt,\n  articleUrl,\n}: EmailBrandProps & {\n  title: string;\n  description: string;\n  imageUrl: string;\n  imageAlt: string;\n  articleUrl: string;\n}) {\n  return (\n    <EmailLayout theme={theme} preview={title}>\n      <EmailText tone=\"muted\" className=\"mb-6 text-caption\">\n        {brand} / IN GOOD COMPANY\n      </EmailText>\n      <EmailHeading>Fresh perspectives.</EmailHeading>\n      <Row>\n        <Column width=\"36%\" className=\"align-top\">\n          <Img src={imageUrl} alt={imageAlt} width=\"198\" className=\"block h-auto w-full rounded-scene\" />\n        </Column>\n        <Column width=\"64%\" className=\"pl-5 align-top\">\n          <EmailHeading as=\"h2\">{title}</EmailHeading>\n          <EmailText>{description}</EmailText>\n          <EmailLink href={articleUrl}>Read the story</EmailLink>\n        </Column>\n      </Row>\n      <EmailFooter brand={brand}>{footer}</EmailFooter>\n    </EmailLayout>\n  );\n}\n\nexport type EmailArticle = { title: string; description: string; href: string; imageUrl: string; imageAlt: string };\n\nexport function NewsletterEmail({\n  theme,\n  brand,\n  footer,\n  articles,\n  unsubscribeUrl,\n}: EmailBrandProps & {\n  articles: EmailArticle[];\n  unsubscribeUrl: string;\n}) {\n  return (\n    <EmailLayout theme={theme} preview=\"A few things worth making time for.\">\n      <EmailText tone=\"muted\" className=\"mb-6 text-caption\">\n        {brand} / THE WEEKLY EDIT\n      </EmailText>\n      <EmailHeading>A little room for inspiration.</EmailHeading>\n      <EmailText tone=\"muted\">A few things worth making time for. Stories, spaces, and ideas from our community.</EmailText>\n      {articles.map((article) => (\n        <Section key={article.href} className=\"mb-6\">\n          <Img src={article.imageUrl} alt={article.imageAlt} width=\"552\" className=\"mb-4 block h-auto w-full rounded-scene\" />\n          <EmailHeading as=\"h2\">{article.title}</EmailHeading>\n          <EmailText>{article.description}</EmailText>\n          <EmailLink href={article.href}>Read the story</EmailLink>\n        </Section>\n      ))}\n      <EmailFooter brand={brand}>{footer}</EmailFooter>\n      <EmailLink href={unsubscribeUrl} className=\"text-caption\">\n        Unsubscribe\n      </EmailLink>\n    </EmailLayout>\n  );\n}\n\nexport function SummaryEmail({\n  theme,\n  brand,\n  footer,\n  period,\n  metrics,\n  details,\n  dashboardUrl,\n}: EmailBrandProps & {\n  period: string;\n  metrics: { label: string; value: string }[];\n  details: { label: string; value: string }[];\n  dashboardUrl: string;\n}) {\n  return (\n    <EmailLayout theme={theme} preview={`Your team’s progress · ${period}`}>\n      <EmailText tone=\"muted\" className=\"mb-6 text-caption\">\n        {brand} / {period}\n      </EmailText>\n      <EmailHeading>Good work adds up.</EmailHeading>\n      <EmailText>Here’s what your team moved forward this week.</EmailText>\n      <Section className=\"my-6 rounded-panel bg-muted p-4\">\n        <Row className=\"table-fixed\">\n          {metrics.map((metric) => (\n            <Column key={metric.label} className=\"px-2 align-top\">\n              <EmailText className=\"mb-1 text-heading-2 font-semibold\">{metric.value}</EmailText>\n              <EmailText tone=\"muted\" className=\"mb-0 text-caption\">\n                {metric.label}\n              </EmailText>\n            </Column>\n          ))}\n        </Row>\n      </Section>\n      {details.map((detail) => (\n        <Row key={detail.label} className=\"table-fixed\">\n          <Column>\n            <EmailText>{detail.label}</EmailText>\n          </Column>\n          <Column align=\"right\">\n            <EmailText>{detail.value}</EmailText>\n          </Column>\n        </Row>\n      ))}\n      <EmailButton href={dashboardUrl}>View your workspace</EmailButton>\n      <EmailFooter brand={brand}>{footer}</EmailFooter>\n    </EmailLayout>\n  );\n}\n"
    },
    {
      "path": "src/registry/sources/control-ui/email/theme.ts",
      "target": "@components/control-ui/email/theme.ts",
      "type": "registry:component",
      "content": "import { composite, resolveColor, tokenMaps } from \"../scripts/contrast-eval.mjs\";\nimport { emailLengthPixels } from \"./length\";\n\nconst emailColors = [\n  \"background\",\n  \"foreground\",\n  \"card\",\n  \"card-foreground\",\n  \"primary\",\n  \"primary-foreground\",\n  \"primary-text\",\n  \"muted\",\n  \"muted-foreground\",\n  \"border\",\n] as const;\nconst headingSizes = [\"heading-1\", \"heading-2\", \"heading-3\", \"heading-4\"] as const;\n\ntype EmailColor = (typeof emailColors)[number];\ntype EmailHeadingSize = (typeof headingSizes)[number];\ntype EmailTypeStyle = { fontSize: string; lineHeight: string; fontWeight: string; letterSpacing: string };\n\nexport type EmailTheme = {\n  colors: Record<EmailColor, string>;\n  fonts: { body: string; display: string };\n  radii: { control: string; panel: string; scene: string };\n  button: { height: string; paddingInline: string; paddingBlock: string; fontSize: string; lineHeight: string };\n  text: Record<EmailHeadingSize | \"body\" | \"caption\", EmailTypeStyle>;\n};\n\nfunction resolveVariables(value: string, tokens: ReadonlyMap<string, string>, chain: string[] = []): string {\n  if (chain.length > 16) throw new Error(`Email theme: token chain exceeds 16 references (${chain.join(\" → \")}).`);\n  return value.replace(/var\\(\\s*(--[\\w-]+)\\s*(?:,\\s*((?:[^()]|\\([^()]*\\))*))?\\)/g, (_, name: string, fallback: string | undefined) => {\n    if (chain.includes(name)) throw new Error(`Email theme: circular reference to ${name}.`);\n    const resolved = tokens.get(name) ?? fallback;\n    if (resolved === undefined) throw new Error(`Email theme: missing ${name}.`);\n    return resolveVariables(resolved, tokens, [...chain, name]);\n  });\n}\n\nfunction tokenValue(name: string, tokens: ReadonlyMap<string, string>, fallback?: string) {\n  const value = tokens.get(name) ?? fallback;\n  if (value === undefined) throw new Error(`Email theme: missing ${name}. Include core theme.css before the skin theme.`);\n  const resolved = resolveVariables(value, tokens, [name]).trim();\n  if (!resolved || /var\\(|[;{}<>]/.test(resolved)) throw new Error(`Email theme: unsupported ${name}: ${value}.`);\n  return resolved;\n}\n\nfunction pixelSize(name: string, tokens: ReadonlyMap<string, string>, rootFontSize: number) {\n  return `${emailLengthPixels(name, tokenValue(name, tokens), rootFontSize)}px`;\n}\n\nfunction numericStyle(name: string, tokens: ReadonlyMap<string, string>, fallback: string) {\n  const value = tokenValue(name, tokens, fallback);\n  if (!/^\\d*\\.?\\d+(px|em)?$/.test(value)) throw new Error(`Email theme: unsupported ${name}: ${value}.`);\n  return value;\n}\n\nexport function createEmailTheme(tokens: ReadonlyMap<string, string>, rootFontSize = 16): EmailTheme {\n  if (!Number.isFinite(rootFontSize) || rootFontSize <= 0) throw new Error(\"Email theme: rootFontSize must be a positive pixel value.\");\n\n  function lengthPixels(name: string, allowZero = false) {\n    return emailLengthPixels(name, tokenValue(name, tokens), rootFontSize, allowZero);\n  }\n\n  const buttonHeight = lengthPixels(\"--control-h-md\");\n  const buttonFontSize = lengthPixels(\"--text-body\");\n  const reactEmailButtonLineHeight = buttonFontSize * 1.2;\n  const buttonPaddingBlock = Math.max(0, (buttonHeight - reactEmailButtonLineHeight) / 2);\n\n  function color(name: EmailColor) {\n    const result = resolveColor(`var(--${name})`, tokens);\n    if (\"unresolved\" in result) throw new Error(`Email theme: --${name}: ${result.unresolved}.`);\n    return result;\n  }\n\n  const background = color(\"background\");\n  if (background.alpha !== 1) throw new Error(\"Email theme: --background must be opaque.\");\n  const card = composite(color(\"card\"), background);\n  const primary = composite(color(\"primary\"), card);\n  function opaqueColor(name: EmailColor, surface = card) {\n    const result = composite(color(name), surface);\n    return `rgb(${Math.round(result.r)}, ${Math.round(result.g)}, ${Math.round(result.b)})`;\n  }\n\n  function heading(name: EmailHeadingSize): EmailTypeStyle {\n    const spacing = tokenValue(`--text-${name}--letter-spacing`, tokens, \"0\");\n    if (!/^-?\\d*\\.?\\d+(px|em)?$/.test(spacing)) throw new Error(`Email theme: unsupported ${name} letter spacing: ${spacing}.`);\n    return {\n      fontSize: pixelSize(`--text-${name}`, tokens, rootFontSize),\n      lineHeight: numericStyle(`--text-${name}--line-height`, tokens, \"1.3\"),\n      fontWeight: numericStyle(`--text-${name}--font-weight`, tokens, \"600\"),\n      letterSpacing: spacing,\n    };\n  }\n\n  return {\n    colors: {\n      background: opaqueColor(\"background\", background),\n      foreground: opaqueColor(\"foreground\", background),\n      card: opaqueColor(\"card\", background),\n      \"card-foreground\": opaqueColor(\"card-foreground\"),\n      primary: opaqueColor(\"primary\"),\n      \"primary-foreground\": opaqueColor(\"primary-foreground\", primary),\n      \"primary-text\": opaqueColor(\"primary-text\"),\n      muted: opaqueColor(\"muted\"),\n      \"muted-foreground\": opaqueColor(\"muted-foreground\"),\n      border: opaqueColor(\"border\"),\n    },\n    fonts: { body: tokenValue(\"--font-body\", tokens), display: tokenValue(\"--font-display\", tokens) },\n    radii: {\n      control: `${lengthPixels(\"--radius-control\", true)}px`,\n      panel: `${lengthPixels(\"--radius-panel\", true)}px`,\n      scene: `${lengthPixels(\"--radius-scene\", true)}px`,\n    },\n    button: {\n      height: `${buttonHeight}px`,\n      paddingInline: `${lengthPixels(\"--padding-x\", true)}px`,\n      paddingBlock: `${buttonPaddingBlock}px`,\n      fontSize: `${buttonFontSize}px`,\n      lineHeight: `${reactEmailButtonLineHeight}px`,\n    },\n    text: {\n      body: { fontSize: pixelSize(\"--text-body-lg\", tokens, rootFontSize), lineHeight: \"1.6\", fontWeight: \"400\", letterSpacing: \"0\" },\n      caption: { fontSize: pixelSize(\"--text-body\", tokens, rootFontSize), lineHeight: \"1.5\", fontWeight: \"400\", letterSpacing: \"0\" },\n      \"heading-1\": heading(\"heading-1\"),\n      \"heading-2\": heading(\"heading-2\"),\n      \"heading-3\": heading(\"heading-3\"),\n      \"heading-4\": heading(\"heading-4\"),\n    },\n  };\n}\n\nexport function emailThemeFromCss(cssSources: string[], mode: \"light\" | \"dark\" = \"light\", rootFontSize = 16): EmailTheme {\n  return createEmailTheme(tokenMaps(cssSources)[mode], rootFontSize);\n}\n"
    }
  ]
}
