{"$schema":"https://ui.shadcn.com/schema/registry-item.json","name":"code-block","type":"registry:ui","title":"Code Block","description":"Code to read and copy – a header with the file name or language and a copy button, line numbers, highlighted lines, long lines that scroll inside and a small built-in colorizer","dependencies":[],"files":[{"path":"registry/code-block/code-block.tsx","type":"registry:ui","content":"\"use client\";\n\nimport { useEffect, useLayoutEffect, useMemo, useRef, useState, type CSSProperties } from \"react\";\n\n/*\n * Code Block – a single self-contained file.\n * Code on a white card inside a light-gray tray: the tray carries the file name (or the language) and a copy button\n * that turns into a check for a moment. Optional line numbers that stay put while long lines scroll sideways, highlighted lines,\n * wrapping instead of scrolling, and a max height after which the code scrolls inside.\n * A tiny built-in colorizer for TypeScript / JavaScript, JSON, Bash and Python – no highlighter to install;\n * every other language is shown as plain text.\n * The styles are injected below, so no extra files are needed.\n */\n\nexport type CodeBlockProps = {\n  /** The code – copied exactly as given */\n  code: string;\n  /** ts, tsx, js, jsx, json, bash, sh, python … – colors the code when known, otherwise plain text */\n  language?: string;\n  /** Shown in the header, e.g. \"agent.config.ts\" – without it the header names the language */\n  filename?: string;\n  /** Numbers in front of every line, they stay in place while the code scrolls sideways */\n  showLineNumbers?: boolean;\n  /** Lines to mark, counted from 1 – e.g. [3, 4, 5] */\n  highlightLines?: number[];\n  /** Long lines wrap instead of scrolling sideways */\n  wrap?: boolean;\n  /** After this height the code scrolls inside, e.g. 320 or \"40vh\" */\n  maxHeight?: number | string;\n  /** The copy button in the header */\n  copyable?: boolean;\n  /** Called after the code was copied – e.g. for a toast */\n  onCopy?: (code: string) => void;\n  className?: string;\n  style?: CSSProperties;\n};\n\ntype Kind = \"com\" | \"str\" | \"kw\" | \"num\" | \"lit\" | \"fn\" | \"key\" | \"var\";\ntype Token = [Kind | null, string];\n\nexport function CodeBlock({\n  code,\n  language,\n  filename,\n  showLineNumbers = false,\n  highlightLines,\n  wrap = false,\n  maxHeight,\n  copyable = true,\n  onCopy,\n  className,\n  style,\n}: CodeBlockProps) {\n  // One trailing newline is how files end – it shouldn't show as an empty last line\n  const source = typeof code === \"string\" ? code : code == null ? \"\" : String(code);\n  const shown = source.replace(/\\r\\n?/g, \"\\n\").replace(/\\n$/, \"\");\n  const lang = resolve(language);\n  const lines = useMemo(() => toLines(tokenize(shown, lang)), [shown, lang]);\n  const marked = useMemo(() => new Set(Array.isArray(highlightLines) ? highlightLines : []), [highlightLines]);\n  const label = filename || languageName(language);\n\n  const scroller = useRef<HTMLDivElement>(null);\n  const [scrolls, setScrolls] = useState(false);\n  const [copied, setCopied] = useState(false);\n\n  // A scrolling block is reachable by Tab, so keyboard users can scroll it with the arrow keys\n  useLayoutEffect(() => {\n    const el = scroller.current;\n    if (!el) return;\n    const check = () => setScrolls(el.scrollWidth > el.clientWidth + 1 || el.scrollHeight > el.clientHeight + 1);\n    check();\n    const ro = new ResizeObserver(check);\n    ro.observe(el);\n    if (el.firstElementChild) ro.observe(el.firstElementChild);\n    return () => ro.disconnect();\n  }, [shown, wrap, maxHeight, showLineNumbers]);\n\n  useEffect(() => {\n    if (!copied) return;\n    const t = window.setTimeout(() => setCopied(false), 1400);\n    return () => window.clearTimeout(t);\n  }, [copied]);\n\n  const copy = () =>\n    copyText(source).then((ok) => {\n      if (!ok) return;\n      setCopied(true);\n      onCopy?.(source);\n    });\n\n  const header = !!label || copyable;\n  const digits = String(lines.length).length;\n\n  return (\n    <figure\n      className={[\"ui-code\", className].filter(Boolean).join(\" \")}\n      data-wrap={wrap || undefined}\n      data-numbers={showLineNumbers || undefined}\n      style={{ ...style, [\"--ui-code-digits\" as string]: digits }}\n    >\n      {/* React 19 hoists this into <head> once, no matter how many blocks render */}\n      <style href=\"ui-code-block\" precedence=\"default\">\n        {css}\n      </style>\n      {header && (\n        <figcaption className=\"ui-code__head\">\n          <span className=\"ui-code__label\" dir=\"auto\" title={label || undefined}>\n            {label}\n          </span>\n          {copyable && (\n            <button\n              type=\"button\"\n              className=\"ui-code__copy\"\n              data-copied={copied || undefined}\n              aria-label={copied ? \"Copied\" : \"Copy code\"}\n              title={copied ? \"Copied\" : \"Copy code\"}\n              onClick={copy}\n            >\n              <svg className=\"ui-code__copy-icon\" viewBox=\"0 0 16 16\" aria-hidden=\"true\">\n                <rect x=\"5.5\" y=\"5.5\" width=\"8.5\" height=\"8.5\" rx=\"2\" />\n                <path d=\"M10.5 3.75v-.25A1.5 1.5 0 0 0 9 2H3.5A1.5 1.5 0 0 0 2 3.5V9a1.5 1.5 0 0 0 1.5 1.5h.25\" />\n              </svg>\n              <svg className=\"ui-code__copy-done\" viewBox=\"0 0 16 16\" aria-hidden=\"true\">\n                <path d=\"M3.5 8.4 6.6 11.3 12.5 4.9\" />\n              </svg>\n            </button>\n          )}\n        </figcaption>\n      )}\n      {/* Screen readers hear the copy – the button's new name alone isn't announced */}\n      {copyable && (\n        <span className=\"ui-code__sr\" role=\"status\">\n          {copied ? \"Copied\" : \"\"}\n        </span>\n      )}\n      <div\n        ref={scroller}\n        className=\"ui-code__scroll\"\n        style={maxHeight != null ? { maxHeight } : undefined}\n        tabIndex={scrolls ? 0 : undefined}\n        role={scrolls ? \"region\" : undefined}\n        aria-label={scrolls ? `${label || \"Code\"}, code` : undefined}\n      >\n        <pre className=\"ui-code__pre\" dir=\"ltr\">\n          <code className=\"ui-code__code\">\n            {lines.map((line, i) => (\n              <span key={i} className=\"ui-code__line\" data-marked={marked.has(i + 1) || undefined}>\n                {showLineNumbers && (\n                  <span className=\"ui-code__ln\" aria-hidden=\"true\">\n                    {i + 1}\n                  </span>\n                )}\n                <span className=\"ui-code__text\">\n                  {line.map(([kind, text], j) =>\n                    kind ? (\n                      <span key={j} className={`ui-code__t-${kind}`}>\n                        {text}\n                      </span>\n                    ) : (\n                      text\n                    ),\n                  )}\n                </span>\n              </span>\n            ))}\n          </code>\n        </pre>\n      </div>\n    </figure>\n  );\n}\n\n/* ---------- The colorizer ---------- */\n\ntype Lang = \"js\" | \"json\" | \"bash\" | \"python\";\n\nconst ALIASES: Record<string, Lang> = {\n  ts: \"js\", tsx: \"js\", typescript: \"js\", js: \"js\", jsx: \"js\", javascript: \"js\", mjs: \"js\", cjs: \"js\",\n  json: \"json\", jsonc: \"json\",\n  bash: \"bash\", sh: \"bash\", shell: \"bash\", zsh: \"bash\", console: \"bash\",\n  python: \"python\", py: \"python\",\n};\n\nconst NAMES: Record<string, string> = {\n  ts: \"TypeScript\", typescript: \"TypeScript\", tsx: \"TSX\", js: \"JavaScript\", javascript: \"JavaScript\", jsx: \"JSX\",\n  mjs: \"JavaScript\", cjs: \"JavaScript\", json: \"JSON\", jsonc: \"JSON\", bash: \"Bash\", sh: \"Shell\", shell: \"Shell\",\n  zsh: \"Zsh\", console: \"Terminal\", python: \"Python\", py: \"Python\",\n};\n\nconst resolve = (language?: string): Lang | null => (language ? ALIASES[language.toLowerCase()] ?? null : null);\nconst languageName = (language?: string) => (language ? NAMES[language.toLowerCase()] ?? language : \"\");\n\nconst END = \"(?![\\\\s\\\\S])\";\nconst BLOCK_COMMENT = `\\\\/\\\\*[\\\\s\\\\S]*?(?:\\\\*\\\\/|${END})`;\n\n/** Each language: [kind, pattern] in order – at one spot the first that matches wins */\nconst RULES: Record<Lang, [Kind, string][]> = {\n  js: [\n    [\"com\", `\\\\/\\\\/[^\\\\n]*|${BLOCK_COMMENT}`],\n    [\"str\", `\"(?:[^\"\\\\\\\\\\\\n]|\\\\\\\\.)*\"?|'(?:[^'\\\\\\\\\\\\n]|\\\\\\\\.)*'?|\\`(?:[^\\`\\\\\\\\]|\\\\\\\\[\\\\s\\\\S])*\\`?`],\n    [\"num\", `\\\\b0[xXbBoO][\\\\da-fA-F_]+n?\\\\b|\\\\b\\\\d[\\\\d_]*(?:\\\\.\\\\d+)?(?:[eE][+-]?\\\\d+)?n?\\\\b`],\n    [\"lit\", `\\\\b(?:true|false|null|undefined|NaN|Infinity)\\\\b`],\n    [\n      \"kw\",\n      `\\\\b(?:abstract|as|async|await|break|case|catch|class|const|continue|debugger|declare|default|delete|do|else|enum|export|extends|finally|for|from|function|if|implements|import|in|instanceof|interface|keyof|let|new|of|private|protected|public|readonly|return|satisfies|static|super|switch|this|throw|try|type|typeof|var|void|while|with|yield)\\\\b`,\n    ],\n    [\"fn\", `(?<![\\\\w$])[A-Za-z_$][\\\\w$]*(?=\\\\s*\\\\()`],\n  ],\n  json: [\n    [\"com\", `\\\\/\\\\/[^\\\\n]*|${BLOCK_COMMENT}`],\n    [\"key\", `\"(?:[^\"\\\\\\\\\\\\n]|\\\\\\\\.)*\"(?=\\\\s*:)`],\n    [\"str\", `\"(?:[^\"\\\\\\\\\\\\n]|\\\\\\\\.)*\"?`],\n    [\"num\", `-?\\\\b\\\\d+(?:\\\\.\\\\d+)?(?:[eE][+-]?\\\\d+)?\\\\b`],\n    [\"lit\", `\\\\b(?:true|false|null)\\\\b`],\n  ],\n  bash: [\n    [\"com\", `(?<![^\\\\s;|&(])#[^\\\\n]*`],\n    [\"str\", `\"(?:[^\"\\\\\\\\]|\\\\\\\\[\\\\s\\\\S])*\"?|'[^']*'?`],\n    [\"var\", `\\\\$\\\\{[^}\\\\n]*\\\\}?|\\\\$[A-Za-z_]\\\\w*|\\\\$[0-9@#?*$!-]`],\n    [\"kw\", `\\\\b(?:if|then|else|elif|fi|for|in|do|done|while|until|case|esac|function|return|export|local|readonly|unset|exit)\\\\b`],\n    // The command: the first word of a line or after a pipe, ;, && or $( – but not NAME=value\n    [\"fn\", `(?<=^[ \\\\t]*|[|;&(][ \\\\t]*)[A-Za-z_.\\\\/~][\\\\w.\\\\/~+-]*(?![\\\\w=])`],\n  ],\n  python: [\n    [\"com\", `#[^\\\\n]*`],\n    [\n      \"str\",\n      `(?:\\\\b[rRbBuUfF]{1,2})?(?:\"\"\"[\\\\s\\\\S]*?(?:\"\"\"|${END})|'''[\\\\s\\\\S]*?(?:'''|${END})|\"(?:[^\"\\\\\\\\\\\\n]|\\\\\\\\.)*\"?|'(?:[^'\\\\\\\\\\\\n]|\\\\\\\\.)*'?)`,\n    ],\n    [\"fn\", `@[A-Za-z_][\\\\w.]*`],\n    [\"num\", `\\\\b0[xXoObB][\\\\da-fA-F_]+\\\\b|\\\\b\\\\d[\\\\d_]*(?:\\\\.\\\\d+)?(?:[eE][+-]?\\\\d+)?j?\\\\b`],\n    [\"lit\", `\\\\b(?:True|False|None|self|cls)\\\\b`],\n    [\n      \"kw\",\n      `\\\\b(?:and|as|assert|async|await|break|case|class|continue|def|del|elif|else|except|finally|for|from|global|if|import|in|is|lambda|match|nonlocal|not|or|pass|raise|return|try|while|with|yield)\\\\b`,\n    ],\n    [\"fn\", `\\\\b[A-Za-z_]\\\\w*(?=\\\\s*\\\\()`],\n  ],\n};\n\nconst compiled = new Map<Lang, { re: RegExp; kinds: Kind[] }>();\nfunction grammar(lang: Lang) {\n  let g = compiled.get(lang);\n  if (!g) {\n    const rules = RULES[lang];\n    g = { re: new RegExp(rules.map(([, p]) => `(${p})`).join(\"|\"), \"gm\"), kinds: rules.map(([k]) => k) };\n    compiled.set(lang, g);\n  }\n  return g;\n}\n\nfunction tokenize(text: string, lang: Lang | null): Token[] {\n  if (!lang || !text) return [[null, text]];\n  const { re, kinds } = grammar(lang);\n  re.lastIndex = 0;\n  const out: Token[] = [];\n  let last = 0;\n  let m: RegExpExecArray | null;\n  while ((m = re.exec(text))) {\n    if (!m[0]) {\n      re.lastIndex++;\n      continue;\n    }\n    if (m.index > last) out.push([null, text.slice(last, m.index)]);\n    const group = m.findIndex((g, i) => i > 0 && g !== undefined);\n    out.push([kinds[group - 1] ?? null, m[0]]);\n    last = m.index + m[0].length;\n  }\n  if (last < text.length) out.push([null, text.slice(last)]);\n  return out;\n}\n\n/** Splits the tokens into lines – a comment or string that runs over several lines keeps its color on each */\nfunction toLines(tokens: Token[]): Token[][] {\n  const lines: Token[][] = [[]];\n  for (const [kind, text] of tokens) {\n    text.split(\"\\n\").forEach((part, i) => {\n      if (i) lines.push([]);\n      if (part) lines[lines.length - 1].push([kind, part]);\n    });\n  }\n  return lines;\n}\n\nasync function copyText(text: string) {\n  try {\n    await navigator.clipboard.writeText(text);\n    return true;\n  } catch {\n    // Older browsers and non-secure contexts\n    const area = document.createElement(\"textarea\");\n    area.value = text;\n    area.setAttribute(\"readonly\", \"\");\n    area.style.cssText = \"position:fixed;opacity:0;pointer-events:none\";\n    document.body.appendChild(area);\n    area.select();\n    let ok = false;\n    try {\n      ok = document.execCommand(\"copy\");\n    } catch {\n      ok = false;\n    }\n    area.remove();\n    return ok;\n  }\n}\n\n/* ---------- Styles ---------- */\n\nconst css = /* css */ `\n/* Colors as variables – override them on .ui-code (see Theming in the docs) */\n.ui-code {\n  --ui-code-tray: var(--aui-subtle, #f4f4f4);\n  --ui-code-bg: var(--aui-surface, #ffffff);\n  --ui-code-line: var(--aui-border, #e7e7e7);\n  --ui-code-ink: var(--aui-ink, #171717);\n  --ui-code-muted: var(--aui-muted, #737373);\n  --ui-code-faint: #b4b4b4;\n  --ui-code-icon: var(--aui-muted, #8a8a8a);\n  --ui-code-wash: rgba(0, 0, 0, 0.05);\n  --ui-code-mark: rgba(0, 96, 226, 0.06);\n  --ui-code-mark-edge: rgba(0, 96, 226, 0.5);\n  --ui-code-focus: var(--aui-focus, rgba(0, 96, 226, 0.7));\n  --ui-code-ease: var(--aui-ease, cubic-bezier(0.22, 1, 0.36, 1));\n  --ui-code-mono: var(--aui-font-mono, ui-monospace, \"SF Mono\", SFMono-Regular, Menlo, Consolas, monospace);\n  --ui-code-r: calc(var(--aui-radius, 10px) + 2px);\n  --ui-code-pad: 3px;\n  /* Tokens */\n  --ui-code-com: #9a9a9a;\n  --ui-code-str: #0b8576;\n  --ui-code-kw: #8a35d6;\n  --ui-code-num: #b25e00;\n  --ui-code-lit: #b25e00;\n  --ui-code-fn: #1f63c9;\n  --ui-code-key: #171717;\n  --ui-code-var: #1f63c9;\n\n  box-sizing: border-box;\n  position: relative;\n  display: flex;\n  flex-direction: column;\n  min-width: 0;\n  margin: 0;\n  padding: var(--ui-code-pad);\n  border-radius: var(--ui-code-r);\n  background: var(--ui-code-tray);\n  color: var(--ui-code-ink);\n  font-family: var(--aui-font, \"Inter\", ui-sans-serif, system-ui, -apple-system, \"Segoe UI\", Roboto, sans-serif);\n  font-size: 13.5px;\n  line-height: 20px;\n  -webkit-font-smoothing: antialiased;\n}\n.ui-code *, .ui-code *::before, .ui-code *::after { box-sizing: border-box; }\n\n/* Header on the tray: the name on the left, copy on the right – the button as far from the right edge as from the top */\n.ui-code__head {\n  display: flex;\n  flex: none;\n  align-items: center;\n  gap: 8px;\n  height: 32px;\n  padding: 0 3px 0 13px;\n}\n.ui-code__label {\n  flex: 1;\n  min-width: 0;\n  overflow: hidden;\n  font-size: 12.5px;\n  line-height: 16px;\n  font-weight: 500;\n  color: var(--ui-code-muted);\n  white-space: nowrap;\n  text-overflow: ellipsis;\n}\n.ui-code__sr { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }\n\n/* Copy: a ghost button on the tray; the copy glyph blurs into a check */\n.ui-code__copy {\n  all: unset;\n  position: relative;\n  display: grid;\n  flex: none;\n  place-items: center;\n  width: 26px;\n  height: 26px;\n  border-radius: calc(var(--ui-code-r) - 5px);\n  color: var(--ui-code-icon);\n  cursor: pointer;\n  -webkit-tap-highlight-color: transparent;\n  transition: background-color 160ms ease, color 160ms ease;\n}\n.ui-code__copy svg {\n  position: absolute;\n  width: 15px;\n  height: 15px;\n  fill: none;\n  stroke: currentColor;\n  stroke-width: 1.4;\n  stroke-linecap: round;\n  stroke-linejoin: round;\n  transition: opacity 200ms ease, transform 320ms var(--ui-code-ease), filter 200ms ease;\n}\n.ui-code__copy-icon rect { fill: none; stroke: currentColor; }\n.ui-code__copy .ui-code__copy-done { opacity: 0; transform: scale(0.6); filter: blur(2px); stroke-width: 1.7; }\n.ui-code__copy[data-copied] { color: var(--ui-code-ink); }\n.ui-code__copy[data-copied] .ui-code__copy-icon { opacity: 0; transform: scale(0.6); filter: blur(2px); }\n.ui-code__copy[data-copied] .ui-code__copy-done { opacity: 1; transform: none; filter: none; }\n.ui-code__copy:focus-visible { outline: 2px solid var(--ui-code-focus); outline-offset: 2px; }\n@media (hover: hover) {\n  .ui-code__copy:hover { background: var(--ui-code-wash); color: var(--ui-code-ink); }\n}\n\n/* The white card with the code: scrolls sideways (or wraps) and, past maxHeight, down – never wider than its container */\n.ui-code__scroll {\n  position: relative;\n  flex: 1 1 auto;\n  min-width: 0;\n  min-height: 0;\n  overflow: auto;\n  overscroll-behavior-x: contain;\n  border-radius: calc(var(--ui-code-r) - var(--ui-code-pad));\n  background: var(--ui-code-bg);\n  box-shadow: 0 0 0 1px var(--ui-code-line), 0 1px 2px rgba(0, 0, 0, 0.04);\n  scrollbar-width: thin;\n  scrollbar-color: rgba(0, 0, 0, 0.18) transparent;\n}\n.ui-code__scroll:focus-visible { outline: 2px solid var(--ui-code-focus); outline-offset: -2px; }\n.ui-code__pre {\n  margin: 0;\n  padding: 12px 0;\n  font-family: var(--ui-code-mono);\n  font-size: 12.5px;\n  line-height: 20px;\n  color: var(--ui-code-ink);\n  tab-size: 2;\n  text-align: left;\n}\n.ui-code__code { display: block; width: max-content; min-width: 100%; font: inherit; }\n.ui-code[data-wrap] .ui-code__code { width: auto; }\n\n.ui-code__line { display: flex; min-height: 20px; padding: 0 16px; }\n.ui-code__text { flex: 1 0 auto; white-space: pre; }\n.ui-code[data-wrap] .ui-code__text { flex: 1 1 auto; min-width: 0; white-space: pre-wrap; overflow-wrap: anywhere; }\n.ui-code__line[data-marked] { background: var(--ui-code-mark); box-shadow: inset 2px 0 0 var(--ui-code-mark-edge); }\n\n/* Line numbers stay in place while long lines scroll sideways */\n.ui-code[data-numbers] .ui-code__line { padding-left: 0; }\n.ui-code__ln {\n  position: sticky;\n  left: 0;\n  z-index: 1;\n  flex: none;\n  min-width: calc(var(--ui-code-digits, 2) * 1ch + 32px);\n  padding: 0 14px 0 18px;\n  background: var(--ui-code-bg);\n  color: var(--ui-code-faint);\n  text-align: right;\n  font-variant-numeric: tabular-nums;\n  -webkit-user-select: none;\n  user-select: none;\n}\n.ui-code__line[data-marked] .ui-code__ln {\n  background: linear-gradient(var(--ui-code-mark), var(--ui-code-mark)), var(--ui-code-bg);\n  box-shadow: inset 2px 0 0 var(--ui-code-mark-edge);\n  color: var(--ui-code-muted);\n}\n\n.ui-code__t-com { color: var(--ui-code-com); }\n.ui-code__t-str { color: var(--ui-code-str); }\n.ui-code__t-kw { color: var(--ui-code-kw); }\n.ui-code__t-num { color: var(--ui-code-num); }\n.ui-code__t-lit { color: var(--ui-code-lit); }\n.ui-code__t-fn { color: var(--ui-code-fn); }\n.ui-code__t-key { color: var(--ui-code-key); }\n.ui-code__t-var { color: var(--ui-code-var); }\n\n/* Touch screens: a bigger hit area around the copy button, the look stays */\n@media (pointer: coarse) {\n  .ui-code__copy::after { content: \"\"; position: absolute; inset: -5px; }\n}\n\n@media (prefers-reduced-motion: reduce) {\n  .ui-code__copy, .ui-code__copy svg { transition: none; }\n}\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-code {\n  --ui-code-tray: var(--aui-subtle, #1d1d20);\n  --ui-code-bg: var(--aui-surface, #161618);\n  --ui-code-line: var(--aui-border, rgba(255, 255, 255, 0.1));\n  --ui-code-ink: var(--aui-ink, #ededed);\n  --ui-code-muted: var(--aui-muted, #8b8b92);\n  --ui-code-faint: #55555b;\n  --ui-code-icon: var(--aui-muted, #8b8b92);\n  --ui-code-wash: rgba(255, 255, 255, 0.07);\n  --ui-code-mark: rgba(77, 141, 255, 0.1);\n  --ui-code-mark-edge: rgba(77, 141, 255, 0.6);\n  --ui-code-focus: var(--aui-focus, rgba(77, 141, 255, 0.8));\n  --ui-code-com: #6e6e75;\n  --ui-code-str: var(--aui-teal, #4fc3b4);\n  --ui-code-kw: #cfaef5;\n  --ui-code-num: var(--aui-orange, #f2a15c);\n  --ui-code-lit: var(--aui-orange, #f2a15c);\n  --ui-code-fn: #7cb4ff;\n  --ui-code-key: #ededed;\n  --ui-code-var: #7cb4ff;\n}\n:where(.dark, [data-theme=\"dark\"]) .ui-code__scroll { box-shadow: 0 0 0 1px var(--ui-code-line); scrollbar-color: rgba(255, 255, 255, 0.2) transparent; }\n`;\n"}]}