{"$schema":"https://ui.shadcn.com/schema/registry-item.json","name":"change-summary-clean","type":"registry:ui","title":"Change Summary (Clean)","description":"What moved since last time – one metric per row with a colored trend","dependencies":[],"files":[{"path":"registry/change-summary-clean/change-summary-clean.tsx","type":"registry:ui","content":"\"use client\";\n\nimport type { ReactNode } from \"react\";\n\n/*\n * Change Summary (Clean) – what moved since last time, one metric per row, in a single self-contained file.\n * Clean style: no tray – one white card with hairline shadows. The heading is the first row of the card,\n * each metric sits under a 0.5px line with a small tinted trend mark and quiet gray text.\n * The styles are injected below, so no extra files are needed.\n */\n\nexport type MetricChange = {\n  label: string;\n  /** What happened, in words, e.g. \"Up 6.1% to 18.2K\" */\n  change: string;\n  /** good: green arrow · bad: red arrow · neutral: gray dash */\n  tone?: \"good\" | \"bad\" | \"neutral\";\n  /** Direction of the arrow – defaults to up for good, down for bad */\n  direction?: \"up\" | \"down\";\n};\n\nexport type ChangeSummaryProps = {\n  title?: string;\n  /** Small text on the right of the heading, e.g. \"This week\" */\n  period?: string;\n  icon?: ReactNode;\n  changes: MetricChange[];\n  className?: string;\n};\n\nexport function ChangeSummary({ title = \"What's changed\", period, icon, changes, className }: ChangeSummaryProps) {\n  return (\n    <>\n      <style href=\"ui-change-summary-clean\" precedence=\"default\">\n        {css}\n      </style>\n      <section className={[\"ui-csc\", className].filter(Boolean).join(\" \")} aria-label={title}>\n        <header className=\"ui-csc__head\">\n          <span className=\"ui-csc__title\">\n            <span className=\"ui-csc__icon\">{icon ?? <ChangesIcon />}</span>\n            <span className=\"ui-csc__title-text\" dir=\"auto\" title={title}>\n              {title}\n            </span>\n          </span>\n          {period && (\n            <span className=\"ui-csc__period\" dir=\"auto\" title={period}>\n              {period}\n            </span>\n          )}\n        </header>\n        {changes.length > 0 && (\n        <dl className=\"ui-csc__list\">\n          {changes.map((c, i) => {\n            // Anything but good or bad reads as neutral, so the mark always has its tint\n            const tone = c.tone === \"good\" || c.tone === \"bad\" ? c.tone : \"neutral\";\n            const direction = c.direction ?? (tone === \"bad\" ? \"down\" : \"up\");\n            return (\n              // The stagger stops after twelve rows, so a long list is all there at once\n              <div key={`${i}-${c.label}`} className=\"ui-csc__row\" style={{ animationDelay: `${120 + Math.min(i, 12) * 70}ms` }}>\n                <dt className=\"ui-csc__label\" dir=\"auto\" title={c.label}>\n                  {c.label}\n                </dt>\n                <dd className=\"ui-csc__change\">\n                  <span className=\"ui-csc__trend\" data-tone={tone} aria-hidden=\"true\">\n                    {tone === \"neutral\" ? <DashIcon /> : <ArrowIcon down={direction === \"down\"} />}\n                  </span>\n                  <span className=\"ui-csc__text\" dir=\"auto\" title={c.change}>\n                    {c.change}\n                  </span>\n                </dd>\n              </div>\n            );\n          })}\n        </dl>\n        )}\n      </section>\n    </>\n  );\n}\n\n/* ---------- Icons: thin lines, round caps ---------- */\n\nconst ChangesIcon = () => (\n  <svg viewBox=\"0 0 16 16\" width=\"16\" height=\"16\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.1\" strokeLinecap=\"round\" aria-hidden=\"true\">\n    <path d=\"M2.5 4h4M2.5 8h8M6.5 12h7M9.5 4h1\" />\n  </svg>\n);\n\nconst ArrowIcon = ({ down }: { down?: boolean }) => (\n  <svg viewBox=\"0 0 12 12\" width=\"12\" height=\"12\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.25\" strokeLinecap=\"round\" strokeLinejoin=\"round\" aria-hidden=\"true\">\n    {down ? <path d=\"M6 2.5v7M3 6.5l3 3 3-3\" /> : <path d=\"M6 9.5v-7M3 5.5l3-3 3 3\" />}\n  </svg>\n);\n\nconst DashIcon = () => (\n  <svg viewBox=\"0 0 12 12\" width=\"12\" height=\"12\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.25\" strokeLinecap=\"round\" aria-hidden=\"true\">\n    <path d=\"M3 6h6\" />\n  </svg>\n);\n\n/* ---------- Styles ---------- */\n\nconst css = /* css */ `\n/* Colors and motion as variables – override them on .ui-csc */\n.ui-csc {\n  --ui-csc-card: var(--aui-surface, #ffffff);\n  --ui-csc-ink: var(--aui-ink, rgba(0, 0, 0, 0.88));\n  --ui-csc-strong: var(--aui-ink, #000000);\n  --ui-csc-text: var(--aui-muted, rgba(0, 0, 0, 0.61));\n  --ui-csc-muted: var(--aui-muted, rgba(0, 0, 0, 0.45));\n  --ui-csc-icon: var(--aui-muted, rgba(0, 0, 0, 0.447));\n  --ui-csc-line: var(--aui-border, rgba(0, 0, 0, 0.06));\n  --ui-csc-wash: var(--aui-subtle, rgba(0, 0, 0, 0.015));\n  --ui-csc-good: var(--aui-success, #1e8a4f);\n  --ui-csc-good-fill: color-mix(in srgb, var(--aui-green, #5fc88a) 8%, transparent);\n  --ui-csc-bad: var(--aui-red, #f04438);\n  --ui-csc-bad-fill: color-mix(in srgb, var(--aui-red, #f04438) 8%, transparent);\n  --ui-csc-neutral-fill: var(--aui-subtle, rgba(0, 0, 0, 0.04));\n  /* Strokes are shadows: a 0.5px hairline plus a soft lift */\n  --ui-csc-shadow: var(--aui-shadow-card, 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-csc-ease: var(--aui-ease, cubic-bezier(0.22, 1, 0.36, 1));\n  box-sizing: border-box;\n  width: 100%;\n  max-width: 480px;\n  container-type: inline-size;\n  overflow: hidden;\n  border-radius: var(--aui-radius-lg, 10px);\n  background: var(--ui-csc-card);\n  box-shadow: var(--ui-csc-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-csc-ink);\n  -webkit-font-smoothing: antialiased;\n}\n.ui-csc *, .ui-csc *::before, .ui-csc *::after { box-sizing: border-box; }\n:where(.ui-csc) svg { display: block; flex: none; }\n\n/* Heading row: icon + title, the period on the right */\n.ui-csc__head {\n  display: flex;\n  align-items: center;\n  justify-content: space-between;\n  gap: 12px;\n  height: 44px;\n  padding: 0 16px;\n}\n.ui-csc__title {\n  display: inline-flex;\n  align-items: center;\n  gap: 8px;\n  min-width: 0;\n  font-weight: 500;\n  white-space: nowrap;\n  color: var(--ui-csc-strong);\n}\n.ui-csc__icon { display: grid; place-items: center; flex: none; width: 16px; height: 16px; overflow: hidden; color: var(--ui-csc-icon); }\n/* A custom icon – an image too – fits the 16px tile */\n.ui-csc__icon > :is(img, svg) { width: 16px; height: 16px; object-fit: contain; }\n.ui-csc__title-text { min-width: 0; overflow: hidden; text-overflow: ellipsis; }\n/* The period shortens before it pushes the title out */\n.ui-csc__period { flex: 0 1 auto; min-width: 0; max-width: 50%; overflow: hidden; font-size: 12px; line-height: 16px; white-space: nowrap; text-overflow: ellipsis; color: var(--ui-csc-muted); }\n\n/* One row per metric, each under a hairline */\n.ui-csc__list { margin: 0; }\n.ui-csc__row {\n  display: grid;\n  grid-template-columns: minmax(0, 0.8fr) minmax(0, 1.2fr);\n  align-items: center;\n  gap: 16px;\n  min-height: 48px;\n  padding: 0 16px;\n  border-top: 0.5px solid var(--ui-csc-line);\n  animation: ui-csc-in 520ms var(--ui-csc-ease) both;\n  transition: background-color 140ms ease;\n}\n.ui-csc__row:hover { background: var(--ui-csc-wash); }\n.ui-csc__label {\n  overflow: hidden;\n  font-weight: 500;\n  white-space: nowrap;\n  text-overflow: ellipsis;\n  overflow-wrap: anywhere;\n  text-align: start;\n  color: var(--ui-csc-ink);\n}\n.ui-csc__change {\n  display: flex;\n  align-items: center;\n  gap: 8px;\n  min-width: 0;\n  margin: 0;\n  color: var(--ui-csc-text);\n}\n/* The change keeps its numbers: it wraps up to three lines instead of being cut off */\n.ui-csc__text { display: -webkit-box; overflow: hidden; white-space: pre-line; overflow-wrap: anywhere; text-align: start; -webkit-line-clamp: 3; -webkit-box-orient: vertical; }\n\n/* Trend mark: a small tinted square, no strokes */\n.ui-csc__trend {\n  display: grid;\n  place-items: center;\n  flex: none;\n  width: 20px;\n  height: 20px;\n  border-radius: 5px;\n}\n.ui-csc__trend[data-tone=\"good\"] { background: var(--ui-csc-good-fill); color: var(--ui-csc-good); }\n.ui-csc__trend[data-tone=\"bad\"] { background: var(--ui-csc-bad-fill); color: var(--ui-csc-bad); }\n.ui-csc__trend[data-tone=\"neutral\"] { background: var(--ui-csc-neutral-fill); color: var(--ui-csc-icon); }\n\n/* Narrow: each metric stacks above its change, so the text wraps instead of being cut off */\n@container (max-width: 400px) {\n  .ui-csc__head { padding: 0 14px; }\n  .ui-csc__row { grid-template-columns: minmax(0, 1fr); gap: 4px; padding: 10px 14px; }\n  .ui-csc__label { white-space: normal; }\n  .ui-csc__change { align-items: flex-start; }\n}\n/* Touch screens: a little more room per row */\n@media (pointer: coarse) {\n  .ui-csc__row { min-height: 52px; }\n}\n\n@keyframes ui-csc-in {\n  from { opacity: 0; transform: translateY(4px); }\n}\n@media (prefers-reduced-motion: reduce) {\n  .ui-csc__row { animation: none; 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-csc {\n  --ui-csc-card: var(--aui-surface, #1c1c1e);\n  --ui-csc-ink: var(--aui-ink, rgba(255, 255, 255, 0.9));\n  --ui-csc-strong: var(--aui-ink, #ffffff);\n  --ui-csc-text: var(--aui-muted, rgba(255, 255, 255, 0.62));\n  --ui-csc-muted: var(--aui-muted, rgba(255, 255, 255, 0.46));\n  --ui-csc-icon: var(--aui-muted, rgba(255, 255, 255, 0.5));\n  --ui-csc-line: var(--aui-border, rgba(255, 255, 255, 0.08));\n  --ui-csc-wash: var(--aui-subtle, rgba(255, 255, 255, 0.025));\n  --ui-csc-good: var(--aui-green, #5fc88a);\n  --ui-csc-good-fill: color-mix(in srgb, var(--aui-green, #7dcf9f) 14%, transparent);\n  --ui-csc-bad: var(--aui-red, #ff6b5f);\n  --ui-csc-bad-fill: color-mix(in srgb, var(--aui-red, #ff6b5f) 14%, transparent);\n  --ui-csc-neutral-fill: var(--aui-subtle, rgba(255, 255, 255, 0.08));\n  --ui-csc-shadow: var(--aui-shadow-card, 0 0 0 0.5px rgba(255, 255, 255, 0.1), 0 1px 2px 0 rgba(0, 0, 0, 0.4));\n}\n`;\n"}]}