{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "all",
  "title": "buena-graphs",
  "description": "Every graph component, in one install.",
  "dependencies": [],
  "files": [
    {
      "path": "registry/default/graph-activity/graph-activity.tsx",
      "content": "\"use client\"\n\nimport { motion, useReducedMotion } from \"@/registry/default/motion-static/motion-static\"\n\nimport { Graph, GraphBody } from \"@/registry/default/graph-frame/graph-frame\"\nimport {\n  fadeUp,\n  intensityClass,\n  intensityGlyph,\n  intensityLevel,\n  resolveGlyphs,\n  staggerList,\n  type Glyphs,\n  type GraphPalette,\n} from \"@/registry/default/graph-motion/graph-motion\"\nimport { cn } from \"@/lib/utils\"\n\nconst MONTHS = [\n  \"Jan\",\n  \"Feb\",\n  \"Mar\",\n  \"Apr\",\n  \"May\",\n  \"Jun\",\n  \"Jul\",\n  \"Aug\",\n  \"Sep\",\n  \"Oct\",\n  \"Nov\",\n  \"Dec\",\n]\n\nconst DAY_MS = 86_400_000\n\ntype ActivityDay = {\n  date: string\n  count: number\n}\n\ntype ActivityCell = {\n  date: string\n  count: number\n  inRange: boolean\n}\n\ntype GraphActivityProps = {\n  title: string\n  days: ActivityDay[]\n  weekStartsOn?: 0 | 1\n  max?: number\n  legend?: boolean\n  caption?: string | false\n  glyphs?: Glyphs\n  palette?: GraphPalette\n  corner?: string\n  className?: string\n}\n\nfunction parseUTC(iso: string) {\n  const [year, month, day] = iso.split(\"-\").map(Number)\n  return Date.UTC(year, month - 1, day)\n}\n\nfunction toISO(utc: number) {\n  return new Date(utc).toISOString().slice(0, 10)\n}\n\nfunction buildWeeks(days: ActivityDay[], weekStartsOn: 0 | 1) {\n  if (days.length === 0) {\n    return [] as ActivityCell[][]\n  }\n\n  const counts = new Map<string, number>()\n  let min = Number.POSITIVE_INFINITY\n  let max = Number.NEGATIVE_INFINITY\n\n  for (const day of days) {\n    const time = parseUTC(day.date)\n    counts.set(day.date, day.count)\n    if (time < min) min = time\n    if (time > max) max = time\n  }\n\n  const lead = (new Date(min).getUTCDay() - weekStartsOn + 7) % 7\n  const trail = (weekStartsOn + 6 - new Date(max).getUTCDay() + 7) % 7\n  const first = min - lead * DAY_MS\n  const last = max + trail * DAY_MS\n  const weeks: ActivityCell[][] = []\n  let week: ActivityCell[] = []\n\n  for (let time = first; time <= last; time += DAY_MS) {\n    const date = toISO(time)\n    const inRange = time >= min && time <= max\n    week.push({\n      date,\n      count: inRange ? (counts.get(date) ?? 0) : 0,\n      inRange,\n    })\n    if (week.length === 7) {\n      weeks.push(week)\n      week = []\n    }\n  }\n\n  return weeks\n}\n\nfunction monthLabels(weeks: ActivityCell[][]) {\n  return weeks.map((week) => {\n    const start = week.find((cell) => {\n      if (!cell.inRange) {\n        return false\n      }\n\n      return new Date(parseUTC(cell.date)).getUTCDate() === 1\n    })\n\n    if (!start) {\n      return \"\"\n    }\n\n    return MONTHS[new Date(parseUTC(start.date)).getUTCMonth()] ?? \"\"\n  })\n}\n\nfunction dayLabels(weekStartsOn: 0 | 1) {\n  return weekStartsOn === 1\n    ? [\"M\", \"\", \"W\", \"\", \"F\", \"\", \"\"]\n    : [\"\", \"M\", \"\", \"W\", \"\", \"F\", \"\"]\n}\n\nfunction IntensityScale({\n  glyphs,\n  palette,\n}: {\n  glyphs: readonly string[]\n  palette?: GraphPalette\n}) {\n  return (\n    <p className=\"flex items-center gap-2 text-graph-muted\">\n      <span>Less</span>\n      <span aria-hidden=\"true\" className=\"flex select-none\">\n        {glyphs.map((glyph, index) => (\n          <span\n            className={cn(\n              \"w-[1ch] text-center\",\n              intensityClass(\n                Math.round((index / Math.max(glyphs.length - 1, 1)) * 4),\n                palette\n              )\n            )}\n            key={`${glyph}-${index}`}\n          >\n            {glyph}\n          </span>\n        ))}\n      </span>\n      <span>More</span>\n    </p>\n  )\n}\n\nfunction GraphActivity({\n  title,\n  days,\n  weekStartsOn = 0,\n  max,\n  legend = true,\n  caption,\n  glyphs,\n  palette,\n  corner,\n  className,\n}: GraphActivityProps) {\n  const reduce = useReducedMotion()\n  const item = fadeUp(reduce)\n  const list = staggerList(reduce, 0.01)\n  const weeks = buildWeeks(days, weekStartsOn)\n  const months = monthLabels(weeks)\n  const labels = dayLabels(weekStartsOn)\n  const peak = max ?? Math.max(0, ...days.map((day) => day.count), 0)\n  const total = days.reduce((sum, day) => sum + day.count, 0)\n  const summary = `${total.toLocaleString(\"en-US\")} contributions`\n  const set = resolveGlyphs(glyphs)\n  const quiet = set[0] ?? \"·\"\n\n  return (\n    <Graph title={title} className={className} corner={corner}>\n      <GraphBody className=\"flex flex-col gap-4\">\n        <div className=\"flex w-full flex-col gap-1\">\n          <div className=\"flex h-[1.25em] w-full\">\n            <span className=\"w-[2ch] shrink-0\" />\n            {months.map((month, index) => (\n              <span className=\"relative min-w-[1ch] flex-1\" key={`m-${index}`}>\n                {month ? (\n                  <span className=\"absolute bottom-0 left-0 whitespace-nowrap text-graph-muted\">\n                    {month}\n                  </span>\n                ) : null}\n              </span>\n            ))}\n          </div>\n          <div className=\"flex w-full\">\n            <div className=\"flex w-[2ch] shrink-0 flex-col\">\n              {labels.map((label, index) => (\n                <span\n                  className=\"flex h-[1.15em] items-center text-graph-muted\"\n                  key={`d-${index}`}\n                >\n                  {label}\n                </span>\n              ))}\n            </div>\n            <motion.div\n              className=\"flex min-w-0 flex-1\"\n              initial={reduce ? false : \"hidden\"}\n              variants={list}\n              viewport={{ once: true, amount: 0.2 }}\n              whileInView=\"show\"\n            >\n              {weeks.map((week, weekIndex) => (\n                <motion.div\n                  className={cn(\n                    \"flex min-w-[1ch] flex-1 flex-col\",\n                    !reduce && \"will-change-[transform,opacity]\"\n                  )}\n                  key={week[0]?.date ?? weekIndex}\n                  variants={item}\n                >\n                  {week.map((cell) => {\n                    const level = cell.inRange\n                      ? intensityLevel(cell.count, peak)\n                      : 0\n\n                    return (\n                      <span\n                        aria-hidden=\"true\"\n                        className={cn(\n                          \"flex h-[1.15em] w-full items-center justify-center leading-none select-none\",\n                          cell.inRange\n                            ? intensityClass(level, palette)\n                            : \"text-transparent\"\n                        )}\n                        key={cell.date}\n                      >\n                        {cell.inRange ? intensityGlyph(level, set) : quiet}\n                      </span>\n                    )\n                  })}\n                </motion.div>\n              ))}\n            </motion.div>\n          </div>\n        </div>\n        {caption === false && !legend ? null : (\n          <div\n            className={cn(\n              \"flex flex-wrap items-center gap-3\",\n              caption === false ? \"justify-end\" : \"justify-between\"\n            )}\n          >\n            {caption === false ? null : (\n              <p className=\"text-graph-muted tabular-nums\">\n                {caption ?? summary}\n              </p>\n            )}\n            {legend ? <IntensityScale glyphs={set} palette={palette} /> : null}\n          </div>\n        )}\n        <span className=\"sr-only\">\n          {total} contributions across {days.length} days\n          {caption ? `. ${caption}` : \"\"}\n        </span>\n      </GraphBody>\n    </Graph>\n  )\n}\n\nexport { GraphActivity }\nexport type { ActivityDay, GraphActivityProps }\n",
      "type": "registry:component"
    },
    {
      "path": "registry/default/graph-arrow/graph-arrow.tsx",
      "content": "\"use client\"\n\nimport { cn } from \"@/lib/utils\"\n\nfunction GraphArrow({\n  accent = false,\n  stretch = false,\n  className,\n}: {\n  accent?: boolean\n  stretch?: boolean\n  className?: string\n}) {\n  return (\n    <div\n      aria-hidden=\"true\"\n      className={cn(\n        \"flex min-w-6 items-center gap-1\",\n        stretch && \"min-w-10 flex-1\",\n        accent ? \"text-graph-accent\" : \"text-graph-frame\",\n        className\n      )}\n    >\n      {stretch ? (\n        <span className=\"h-px min-w-6 flex-1 border-t border-dashed border-current\" />\n      ) : (\n        <span>- - -</span>\n      )}\n      <span className=\"shrink-0\">▶</span>\n    </div>\n  )\n}\n\nexport { GraphArrow }\n",
      "type": "registry:component"
    },
    {
      "path": "registry/default/graph-bars/graph-bars.tsx",
      "content": "\"use client\"\n\nimport { motion, useReducedMotion } from \"@/registry/default/motion-static/motion-static\"\n\nimport { GraphArrow } from \"@/registry/default/graph-arrow/graph-arrow\"\nimport { Graph, GraphBody } from \"@/registry/default/graph-frame/graph-frame\"\nimport {\n  fillDelay,\n  graphTransition,\n  toneClass,\n  trackMarks,\n  type Glyphs,\n  type GraphPalette,\n} from \"@/registry/default/graph-motion/graph-motion\"\nimport { cn } from \"@/lib/utils\"\n\ntype BarSeries = {\n  label: string\n  values: number[]\n  size?: \"sm\" | \"lg\"\n}\n\ntype GraphBarsProps = {\n  title: string\n  from: BarSeries\n  to: BarSeries\n  processor?: string\n  glyphs?: Glyphs\n  palette?: GraphPalette\n  corner?: string\n  className?: string\n}\n\nfunction MiniBars({\n  values,\n  height,\n  delay = 0,\n  tone = \"accent\",\n  fill,\n  palette,\n}: {\n  values: number[]\n  height: number\n  delay?: number\n  tone?: \"accent\" | \"muted\"\n  fill: string\n  palette?: GraphPalette\n}) {\n  const reduce = useReducedMotion()\n  const max = Math.max(...values, 1)\n\n  return (\n    <div className=\"flex items-end gap-1\">\n      {values.map((value, index) => {\n        const level = Math.round((value / max) * (height - 1))\n\n        return (\n          <span className=\"flex w-[1ch] flex-col justify-end\" key={index}>\n            {Array.from({ length: height }, (_, row) => {\n              const fromBottom = height - 1 - row\n              const on = fromBottom <= level\n\n              return (\n                <motion.span\n                  className={cn(\n                    \"h-[1em] w-full text-center\",\n                    on\n                      ? tone === \"accent\"\n                        ? toneClass(palette, \"primary\")\n                        : toneClass(palette, \"secondary\")\n                      : \"text-transparent\"\n                  )}\n                  initial={reduce || !on ? false : { opacity: 0 }}\n                  key={row}\n                  transition={graphTransition(reduce, {\n                    delay: delay + fillDelay(reduce, index, 0.03),\n                  })}\n                  viewport={{ once: true }}\n                  whileInView={{ opacity: 1 }}\n                >\n                  {on ? fill : \" \"}\n                </motion.span>\n              )\n            })}\n          </span>\n        )\n      })}\n    </div>\n  )\n}\n\nfunction GraphBars({\n  title,\n  from,\n  to,\n  processor,\n  glyphs,\n  palette,\n  corner,\n  className,\n}: GraphBarsProps) {\n  const marks = trackMarks(glyphs)\n  const fromHeight = from.size === \"lg\" ? 8 : 5\n  const toHeight = to.size === \"lg\" ? 8 : 5\n\n  return (\n    <Graph title={title} className={className} corner={corner}>\n      <GraphBody>\n        <div className=\"flex flex-col items-center gap-8 sm:flex-row sm:items-end sm:justify-center sm:gap-8\">\n          <div className=\"flex flex-col items-center gap-3\">\n            <MiniBars\n              delay={0.04}\n              fill={marks.fill}\n              height={fromHeight}\n              palette={palette}\n              tone=\"muted\"\n              values={from.values}\n            />\n            <p className={toneClass(palette, \"secondary\")}>{from.label}</p>\n          </div>\n\n          <div className=\"flex items-center justify-center gap-3 text-graph-muted max-sm:rotate-90\">\n            <GraphArrow />\n            {processor ? <span>{processor}</span> : null}\n            <GraphArrow />\n          </div>\n\n          <div className=\"flex flex-col items-center gap-3\">\n            <MiniBars\n              delay={0.16}\n              fill={marks.fill}\n              height={toHeight}\n              palette={palette}\n              values={to.values}\n            />\n            <p className=\"text-foreground\">{to.label}</p>\n          </div>\n        </div>\n      </GraphBody>\n    </Graph>\n  )\n}\n\nexport { GraphBars }\nexport type { BarSeries, GraphBarsProps }\n",
      "type": "registry:component"
    },
    {
      "path": "registry/default/graph-bullet/graph-bullet.tsx",
      "content": "\"use client\"\n\nimport { motion, useReducedMotion } from \"@/registry/default/motion-static/motion-static\"\n\nimport {\n  Graph,\n  GraphBody,\n  GraphTick,\n  GraphTrack,\n} from \"@/registry/default/graph-frame/graph-frame\"\nimport {\n  fadeUp,\n  staggerList,\n  toneClass,\n  trackMarks,\n  type Glyphs,\n  type GraphPalette,\n} from \"@/registry/default/graph-motion/graph-motion\"\n\ntype BulletItem = {\n  label: string\n  value: number\n  target?: number\n  max?: number\n  display?: string\n}\n\ntype GraphBulletProps = {\n  title: string\n  items: BulletItem[]\n  ticks?: number\n  glyphs?: Glyphs\n  palette?: GraphPalette\n  corner?: string\n  className?: string\n}\n\nfunction formatItem(item: BulletItem) {\n  if (item.display) {\n    return item.display\n  }\n\n  const value = item.value.toLocaleString(\"en-US\", {\n    maximumFractionDigits: Number.isInteger(item.value) ? 0 : 1,\n  })\n\n  if (item.target == null) {\n    return value\n  }\n\n  const target = item.target.toLocaleString(\"en-US\", {\n    maximumFractionDigits: Number.isInteger(item.target) ? 0 : 1,\n  })\n\n  return `${value} / ${target}`\n}\n\nfunction GraphBullet({\n  title,\n  items,\n  ticks = 20,\n  glyphs,\n  palette,\n  corner,\n  className,\n}: GraphBulletProps) {\n  const reduce = useReducedMotion()\n  const item = fadeUp(reduce)\n  const list = staggerList(reduce, 0.05)\n  const marks = trackMarks(glyphs, {\n    empty: \"-\",\n    rest: \"=\",\n    fill: \"=\",\n  })\n\n  return (\n    <Graph title={title} className={className} corner={corner}>\n      <GraphBody className=\"flex flex-col gap-3\">\n        <motion.ul\n          className=\"flex w-full flex-col gap-2\"\n          initial={reduce ? false : \"hidden\"}\n          role=\"list\"\n          variants={list}\n          viewport={{ once: true, amount: 0.4 }}\n          whileInView=\"show\"\n        >\n          {items.map((entry) => {\n            const peak =\n              entry.max ?? Math.max(entry.value, entry.target ?? 0, 1)\n            const filled = Math.min(\n              ticks,\n              Math.round((Math.max(entry.value, 0) / peak) * ticks)\n            )\n            const mark =\n              entry.target == null\n                ? null\n                : Math.min(\n                    ticks - 1,\n                    Math.max(\n                      0,\n                      Math.round((Math.max(entry.target, 0) / peak) * ticks)\n                    )\n                  )\n\n            return (\n              <motion.li\n                aria-label={`${entry.label} ${formatItem(entry)}`}\n                className=\"grid grid-cols-[7rem_minmax(0,1fr)_7rem] items-center gap-x-4\"\n                key={entry.label}\n                variants={item}\n              >\n                <span className=\"truncate text-foreground\">{entry.label}</span>\n                <span className=\"flex min-w-0 items-center\">\n                  <span aria-hidden=\"true\" className=\"text-graph-frame\">\n                    [\n                  </span>\n                  <GraphTrack>\n                    {Array.from({ length: ticks }, (_, index) => {\n                      const isMark = mark != null && index === mark\n                      const isFill = index < filled\n\n                      return (\n                        <GraphTick\n                          className={\n                            isMark\n                              ? toneClass(palette, \"secondary\")\n                              : isFill\n                                ? mark != null && index > mark\n                                  ? toneClass(palette, \"secondary\")\n                                  : toneClass(palette, \"primary\")\n                                : \"text-graph-frame\"\n                          }\n                          key={index}\n                        >\n                          {isMark ? \"|\" : isFill ? marks.fill : marks.empty}\n                        </GraphTick>\n                      )\n                    })}\n                  </GraphTrack>\n                  <span aria-hidden=\"true\" className=\"text-graph-frame\">\n                    ]\n                  </span>\n                </span>\n                <span className=\"text-right text-graph-muted tabular-nums\">\n                  {formatItem(entry)}\n                </span>\n              </motion.li>\n            )\n          })}\n        </motion.ul>\n      </GraphBody>\n    </Graph>\n  )\n}\n\nexport { GraphBullet }\nexport type { BulletItem, GraphBulletProps }\n",
      "type": "registry:component"
    },
    {
      "path": "registry/default/graph-calendar/graph-calendar.tsx",
      "content": "\"use client\"\n\nimport { motion, useReducedMotion } from \"@/registry/default/motion-static/motion-static\"\n\nimport { Graph, GraphBody } from \"@/registry/default/graph-frame/graph-frame\"\nimport {\n  fadeUp,\n  isMonoPalette,\n  staggerList,\n  toneClass,\n  type GraphPalette,\n} from \"@/registry/default/graph-motion/graph-motion\"\nimport { cn } from \"@/lib/utils\"\n\nconst WEEKDAYS_SUN = [\"S\", \"M\", \"T\", \"W\", \"T\", \"F\", \"S\"]\nconst WEEKDAYS_MON = [\"M\", \"T\", \"W\", \"T\", \"F\", \"S\", \"S\"]\nconst MONTHS = [\n  \"January\",\n  \"February\",\n  \"March\",\n  \"April\",\n  \"May\",\n  \"June\",\n  \"July\",\n  \"August\",\n  \"September\",\n  \"October\",\n  \"November\",\n  \"December\",\n]\n\ntype CalendarMark = {\n  day: number\n  accent?: boolean\n}\n\ntype GraphCalendarProps = {\n  title?: string\n  year: number\n  month: number\n  weekStartsOn?: 0 | 1\n  marks?: CalendarMark[] | number[]\n  today?: number\n  palette?: GraphPalette\n  corner?: string\n  className?: string\n}\n\nfunction monthLength(year: number, monthIndex: number) {\n  return new Date(Date.UTC(year, monthIndex + 1, 0)).getUTCDate()\n}\n\nfunction leadingBlanks(year: number, monthIndex: number, weekStartsOn: 0 | 1) {\n  const weekday = new Date(Date.UTC(year, monthIndex, 1)).getUTCDay()\n  return (weekday - weekStartsOn + 7) % 7\n}\n\nfunction markSet(marks: GraphCalendarProps[\"marks\"]) {\n  const map = new Map<number, boolean>()\n\n  if (!marks) {\n    return map\n  }\n\n  for (const mark of marks) {\n    if (typeof mark === \"number\") {\n      map.set(mark, true)\n      continue\n    }\n\n    map.set(mark.day, mark.accent ?? true)\n  }\n\n  return map\n}\n\nfunction GraphCalendar({\n  title,\n  year,\n  month,\n  weekStartsOn = 1,\n  marks,\n  today,\n  palette,\n  corner,\n  className,\n}: GraphCalendarProps) {\n  const reduce = useReducedMotion()\n  const item = fadeUp(reduce)\n  const list = staggerList(reduce, 0.04)\n  const monthIndex = month - 1\n  const days = monthLength(year, monthIndex)\n  const pad = leadingBlanks(year, monthIndex, weekStartsOn)\n  const highlighted = markSet(marks)\n  const headers = weekStartsOn === 1 ? WEEKDAYS_MON : WEEKDAYS_SUN\n  const trailing = (7 - ((pad + days) % 7)) % 7\n  const caption = title ?? `${MONTHS[monthIndex]} ${year}`\n  const grid: (number | null)[] = [\n    ...Array.from({ length: pad }, () => null),\n    ...Array.from({ length: days }, (_, index) => index + 1),\n    ...Array.from({ length: trailing }, () => null),\n  ]\n  const weeks: (number | null)[][] = []\n\n  for (let index = 0; index < grid.length; index += 7) {\n    weeks.push(grid.slice(index, index + 7))\n  }\n\n  return (\n    <Graph title={caption} className={className} corner={corner}>\n      <GraphBody className=\"flex flex-col gap-3\">\n        <div\n          aria-hidden=\"true\"\n          className=\"grid grid-cols-7 justify-items-center\"\n        >\n          {headers.map((header, index) => (\n            <span\n              className=\"w-[4ch] text-center text-graph-muted\"\n              key={`${header}-${index}`}\n            >\n              {header}\n            </span>\n          ))}\n        </div>\n        <motion.div\n          aria-hidden=\"true\"\n          className=\"flex flex-col gap-1\"\n          initial={reduce ? false : \"hidden\"}\n          variants={list}\n          viewport={{ once: true, amount: 0.4 }}\n          whileInView=\"show\"\n        >\n          {weeks.map((week, weekIndex) => (\n            <motion.div\n              className=\"grid grid-cols-7 justify-items-center\"\n              key={weekIndex}\n              variants={item}\n            >\n              {week.map((day, dayIndex) => {\n                const inMonth = day != null\n                const accent = inMonth && highlighted.get(day) === true\n                const isToday = inMonth && today === day\n\n                return (\n                  <span\n                    className={cn(\n                      \"w-[4ch] text-center tabular-nums\",\n                      !inMonth && \"text-transparent\",\n                      inMonth && !accent && !isToday && \"text-foreground\",\n                      accent && toneClass(palette, \"primary\"),\n                      isToday &&\n                        !accent &&\n                        toneClass(\n                          palette,\n                          isMonoPalette(palette) ? \"primary\" : \"secondary\"\n                        )\n                    )}\n                    key={`${weekIndex}-${dayIndex}`}\n                  >\n                    {inMonth ? (isToday ? `[${day}]` : day) : \"\\u00a0\"}\n                  </span>\n                )\n              })}\n            </motion.div>\n          ))}\n        </motion.div>\n        <span className=\"sr-only\">\n          {MONTHS[monthIndex]} {year}\n          {today ? `, today ${today}` : \"\"}\n          {highlighted.size > 0\n            ? `, marked ${[...highlighted.keys()].join(\", \")}`\n            : \"\"}\n        </span>\n      </GraphBody>\n    </Graph>\n  )\n}\n\nexport { GraphCalendar }\nexport type { CalendarMark, GraphCalendarProps }\n",
      "type": "registry:component"
    },
    {
      "path": "registry/default/graph-cells/graph-cells.tsx",
      "content": "\"use client\"\n\nimport { motion, useReducedMotion } from \"@/registry/default/motion-static/motion-static\"\n\nimport { Graph, GraphBody } from \"@/registry/default/graph-frame/graph-frame\"\nimport {\n  fillDelay,\n  graphTransition,\n  isMonoPalette,\n  seriesClass,\n  trackMarks,\n  type Glyphs,\n  type GraphPalette,\n} from \"@/registry/default/graph-motion/graph-motion\"\nimport { cn } from \"@/lib/utils\"\n\ntype CellGrid = {\n  label: string\n  cells: number[][]\n}\n\ntype GraphCellsProps = {\n  title: string\n  items: CellGrid[]\n  glyphs?: Glyphs\n  palette?: GraphPalette\n  corner?: string\n  className?: string\n}\n\nfunction GraphCells({\n  title,\n  items,\n  glyphs,\n  palette,\n  corner,\n  className,\n}: GraphCellsProps) {\n  const reduce = useReducedMotion()\n  const marks = trackMarks(glyphs, {\n    empty: \"·\",\n    rest: \"░\",\n    fill: \"█\",\n  })\n\n  return (\n    <Graph title={title} className={className} corner={corner}>\n      <GraphBody>\n        <div className=\"@container flex flex-col items-center gap-10 @min-[28rem]:flex-row @min-[28rem]:justify-center @min-[28rem]:gap-12\">\n          {items.map((item, itemIndex) => (\n            <div className=\"flex flex-col items-center gap-4\" key={item.label}>\n              <div aria-hidden=\"true\" className=\"flex flex-col gap-1\">\n                {item.cells.map((row, rowIndex) => (\n                  <div className=\"flex gap-1\" key={rowIndex}>\n                    {row.map((cell, cellIndex) => {\n                      const filled = cell === 1\n\n                      return (\n                        <motion.span\n                          className={cn(\n                            \"w-[1ch] text-center select-none\",\n                            filled\n                              ? isMonoPalette(palette)\n                                ? \"text-graph-accent\"\n                                : seriesClass(palette, itemIndex)\n                              : \"text-graph-frame\"\n                          )}\n                          initial={reduce || !filled ? false : { opacity: 0 }}\n                          key={cellIndex}\n                          transition={graphTransition(reduce, {\n                            delay: fillDelay(\n                              reduce,\n                              itemIndex * 8 + rowIndex * 5 + cellIndex\n                            ),\n                          })}\n                          viewport={{ once: true }}\n                          whileInView={{ opacity: 1 }}\n                        >\n                          {filled ? marks.fill : marks.empty}\n                        </motion.span>\n                      )\n                    })}\n                  </div>\n                ))}\n              </div>\n              <p\n                className={\n                  isMonoPalette(palette)\n                    ? \"text-graph-muted\"\n                    : seriesClass(palette, itemIndex)\n                }\n              >\n                {item.label}\n              </p>\n            </div>\n          ))}\n        </div>\n      </GraphBody>\n    </Graph>\n  )\n}\n\nexport { GraphCells }\nexport type { CellGrid, GraphCellsProps }\n",
      "type": "registry:component"
    },
    {
      "path": "registry/default/graph-clock/graph-clock.ts",
      "content": "\"use client\"\n\nimport { useEffect, useState } from \"react\"\n\nexport function parseInstant(value: Date | number | string) {\n  if (value instanceof Date) {\n    return value.getTime()\n  }\n\n  if (typeof value === \"number\") {\n    return Number.isFinite(value) ? value : Number.NaN\n  }\n\n  return Date.parse(value)\n}\n\nexport function pad2(value: number) {\n  return String(Math.trunc(value)).padStart(2, \"0\")\n}\n\nexport function formatHms(ms: number) {\n  const total = Math.max(0, Math.floor(ms / 1000))\n  const days = Math.floor(total / 86400)\n  const hours = Math.floor((total % 86400) / 3600)\n  const minutes = Math.floor((total % 3600) / 60)\n  const seconds = total % 60\n  const clock = `${pad2(hours)}:${pad2(minutes)}:${pad2(seconds)}`\n\n  if (days > 0) {\n    return `${days}d ${clock}`\n  }\n\n  return clock\n}\n\nexport function formatAgo(ms: number) {\n  const seconds = Math.max(0, Math.floor(ms / 1000))\n\n  if (seconds < 60) {\n    return `${seconds}s ago`\n  }\n\n  const minutes = Math.floor(seconds / 60)\n\n  if (minutes < 60) {\n    return `${minutes}m ago`\n  }\n\n  const hours = Math.floor(minutes / 60)\n\n  if (hours < 48) {\n    return `${hours}h ago`\n  }\n\n  return `${Math.floor(hours / 24)}d ago`\n}\n\nexport function formatClock(ms: number) {\n  const date = new Date(ms)\n\n  return `${pad2(date.getHours())}:${pad2(date.getMinutes())}:${pad2(date.getSeconds())}`\n}\n\nexport function useGraphNow(interval = 1000) {\n  const [now, setNow] = useState<number | null>(null)\n\n  useEffect(() => {\n    setNow(Date.now())\n    const id = window.setInterval(() => setNow(Date.now()), interval)\n    return () => window.clearInterval(id)\n  }, [interval])\n\n  return now\n}\n",
      "type": "registry:lib"
    },
    {
      "path": "registry/default/graph-compare/graph-compare.tsx",
      "content": "\"use client\"\n\nimport { motion, useReducedMotion } from \"@/registry/default/motion-static/motion-static\"\n\nimport { Graph, GraphBody } from \"@/registry/default/graph-frame/graph-frame\"\nimport {\n  DIM_OPACITY,\n  fadeUp,\n  isMonoPalette,\n  seriesClass,\n  staggerList,\n  type GraphPalette,\n} from \"@/registry/default/graph-motion/graph-motion\"\nimport { cn } from \"@/lib/utils\"\n\ntype CompareCell = string | boolean\n\ntype CompareRow = {\n  label: string\n  values: CompareCell[]\n}\n\ntype GraphCompareProps = {\n  title: string\n  columns: string[]\n  rows: CompareRow[]\n  accent?: string\n  palette?: GraphPalette\n  corner?: string\n  className?: string\n}\n\nfunction cellText(value: CompareCell) {\n  if (typeof value === \"boolean\") {\n    return value ? \"✓\" : \"–\"\n  }\n\n  return value\n}\n\nfunction GraphCompare({\n  title,\n  columns,\n  rows,\n  accent,\n  palette,\n  corner,\n  className,\n}: GraphCompareProps) {\n  const reduce = useReducedMotion()\n  const item = fadeUp(reduce)\n  const list = staggerList(reduce, 0.04)\n  const template = `minmax(7rem,1fr) repeat(${columns.length}, minmax(4.5rem, 7rem))`\n\n  return (\n    <Graph title={title} className={className} corner={corner}>\n      <GraphBody className=\"overflow-x-auto\">\n        <div className=\"flex min-w-lg flex-col gap-3\">\n          <div\n            className=\"grid items-end gap-x-4\"\n            style={{ gridTemplateColumns: template }}\n          >\n            <span />\n            {columns.map((column, index) => {\n              const focused = Boolean(accent) && column === accent\n              const mono = isMonoPalette(palette)\n\n              return (\n                <span\n                  className={cn(\n                    \"text-right\",\n                    mono\n                      ? focused\n                        ? \"text-graph-accent\"\n                        : \"text-graph-muted\"\n                      : seriesClass(palette, index)\n                  )}\n                  key={column}\n                >\n                  {column}\n                </span>\n              )\n            })}\n          </div>\n          <motion.ul\n            className=\"flex flex-col gap-2\"\n            initial={reduce ? false : \"hidden\"}\n            role=\"list\"\n            variants={list}\n            viewport={{ once: true, amount: 0.4 }}\n            whileInView=\"show\"\n          >\n            {rows.map((row) => (\n              <motion.li\n                aria-label={`${row.label}: ${columns\n                  .map((column, index) => `${column} ${cellText(row.values[index] ?? \"\")}`)\n                  .join(\", \")}`}\n                className=\"grid items-baseline gap-x-4\"\n                key={row.label}\n                style={{ gridTemplateColumns: template }}\n                variants={item}\n              >\n                <span className=\"truncate text-foreground\">{row.label}</span>\n                {columns.map((column, index) => {\n                  const value = row.values[index]\n                  const focused = Boolean(accent) && column === accent\n                  const dim = Boolean(accent) && !focused\n                  const mark = typeof value === \"boolean\"\n                  const on = value === true\n                  const mono = isMonoPalette(palette)\n\n                  return (\n                    <span\n                      className={cn(\n                        \"text-right\",\n                        !mark && \"tabular-nums\",\n                        on &&\n                          (mono\n                            ? (focused || !accent) && \"text-graph-accent\"\n                            : seriesClass(palette, index)),\n                        on && mono && dim && \"text-foreground\",\n                        mark && !on && \"text-graph-frame\",\n                        !mark && focused && \"text-foreground\",\n                        !mark && dim && \"text-graph-muted\"\n                      )}\n                      key={`${row.label}-${column}`}\n                      style={\n                        dim && !on && mono\n                          ? { opacity: DIM_OPACITY }\n                          : undefined\n                      }\n                    >\n                      {value == null ? \"\" : cellText(value)}\n                    </span>\n                  )\n                })}\n              </motion.li>\n            ))}\n          </motion.ul>\n        </div>\n      </GraphBody>\n    </Graph>\n  )\n}\n\nexport { GraphCompare }\nexport type { CompareCell, CompareRow, GraphCompareProps }\n",
      "type": "registry:component"
    },
    {
      "path": "registry/default/graph-countdown/graph-countdown.tsx",
      "content": "\"use client\"\n\nimport { motion, useReducedMotion } from \"@/registry/default/motion-static/motion-static\"\n\nimport { Graph, GraphBody } from \"@/registry/default/graph-frame/graph-frame\"\nimport {\n  formatHms,\n  parseInstant,\n  useGraphNow,\n} from \"@/registry/default/graph-clock/graph-clock\"\nimport {\n  fadeUp,\n  toneClass,\n  type GraphPalette,\n} from \"@/registry/default/graph-motion/graph-motion\"\nimport { cn } from \"@/lib/utils\"\n\ntype GraphCountdownProps = {\n  title: string\n  to: Date | number | string\n  done?: string\n  caption?: string\n  palette?: GraphPalette\n  corner?: string\n  className?: string\n}\n\nfunction GraphCountdown({\n  title,\n  to,\n  done = \"done\",\n  caption,\n  palette,\n  corner,\n  className,\n}: GraphCountdownProps) {\n  const reduce = useReducedMotion()\n  const enter = fadeUp(reduce)\n  const now = useGraphNow()\n  const target = parseInstant(to)\n  const remaining =\n    now == null || !Number.isFinite(target) ? null : target - now\n  const finished = remaining != null && remaining <= 0\n  const value =\n    remaining == null ? \"00:00:00\" : finished ? done : formatHms(remaining)\n\n  return (\n    <Graph title={title} className={className} corner={corner}>\n      <GraphBody>\n        <motion.div\n          className=\"flex flex-col gap-2\"\n          initial={reduce ? false : \"hidden\"}\n          variants={enter}\n          viewport={{ once: true, amount: 0.5 }}\n          whileInView=\"show\"\n        >\n          <p\n            className={cn(\n              \"text-3xl tracking-tight tabular-nums sm:text-4xl\",\n              finished ? \"text-graph-muted\" : toneClass(palette, \"primary\")\n            )}\n          >\n            {value}\n          </p>\n          {caption ? <p className=\"text-graph-muted\">{caption}</p> : null}\n        </motion.div>\n        <span className=\"sr-only\">\n          {finished ? done : `remaining ${value}`}\n        </span>\n      </GraphBody>\n    </Graph>\n  )\n}\n\nexport { GraphCountdown }\nexport type { GraphCountdownProps }\n",
      "type": "registry:component"
    },
    {
      "path": "registry/default/graph-diff/graph-diff.tsx",
      "content": "\"use client\"\n\nimport { motion, useReducedMotion } from \"@/registry/default/motion-static/motion-static\"\n\nimport {\n  Graph,\n  GraphBody,\n  GraphRule,\n} from \"@/registry/default/graph-frame/graph-frame\"\nimport {\n  fadeUp,\n  staggerList,\n  toneClass,\n  type GraphPalette,\n} from \"@/registry/default/graph-motion/graph-motion\"\nimport { cn } from \"@/lib/utils\"\n\ntype DiffSign = \"add\" | \"remove\" | \"keep\"\n\ntype DiffRow = {\n  label: string\n  value: string\n  sign?: DiffSign\n}\n\ntype GraphDiffProps = {\n  title: string\n  rows: DiffRow[]\n  footer?: DiffRow\n  palette?: GraphPalette\n  corner?: string\n  className?: string\n}\n\nconst signGlyph: Record<DiffSign, string> = {\n  add: \"+\",\n  remove: \"-\",\n  keep: \" \",\n}\n\nfunction DiffLine({\n  row,\n  variants,\n  palette,\n}: {\n  row: DiffRow\n  variants: ReturnType<typeof fadeUp>\n  palette?: GraphPalette\n}) {\n  const sign = row.sign ?? \"keep\"\n  const tone =\n    sign === \"add\"\n      ? toneClass(palette, \"primary\")\n      : sign === \"remove\"\n        ? toneClass(palette, \"secondary\")\n        : sign === \"keep\"\n          ? \"text-foreground\"\n          : toneClass(palette, \"empty\")\n  const mark = sign === \"keep\" ? toneClass(palette, \"empty\") : tone\n\n  return (\n    <motion.div\n      className=\"grid grid-cols-[1.25rem_minmax(0,1fr)_8ch] items-baseline gap-x-3\"\n      variants={variants}\n    >\n      <span aria-hidden=\"true\" className={cn(\"text-center select-none\", mark)}>\n        {signGlyph[sign]}\n      </span>\n      <span className={tone}>{row.label}</span>\n      <span className={cn(\"text-right tabular-nums\", tone)}>{row.value}</span>\n    </motion.div>\n  )\n}\n\nfunction GraphDiff({\n  title,\n  rows,\n  footer,\n  palette,\n  corner,\n  className,\n}: GraphDiffProps) {\n  const reduce = useReducedMotion()\n  const item = fadeUp(reduce)\n  const list = staggerList(reduce, 0.04)\n\n  return (\n    <Graph title={title} className={className} corner={corner}>\n      <GraphBody className=\"flex flex-col gap-3\">\n        <motion.ul\n          role=\"list\"\n          className=\"flex flex-col gap-2\"\n          initial={reduce ? false : \"hidden\"}\n          variants={list}\n          viewport={{ once: true, amount: 0.4 }}\n          whileInView=\"show\"\n        >\n          {rows.map((row) => (\n            <li key={row.label}>\n              <DiffLine palette={palette} row={row} variants={item} />\n            </li>\n          ))}\n        </motion.ul>\n        {footer ? (\n          <>\n            <GraphRule />\n            <motion.div\n              initial={reduce ? false : \"hidden\"}\n              variants={list}\n              viewport={{ once: true }}\n              whileInView=\"show\"\n            >\n              <DiffLine palette={palette} row={footer} variants={item} />\n            </motion.div>\n          </>\n        ) : null}\n      </GraphBody>\n    </Graph>\n  )\n}\n\nexport { GraphDiff }\nexport type { DiffRow, DiffSign, GraphDiffProps }\n",
      "type": "registry:component"
    },
    {
      "path": "registry/default/graph-flow/graph-flow.tsx",
      "content": "\"use client\"\n\nimport { motion, useReducedMotion } from \"@/registry/default/motion-static/motion-static\"\n\nimport { GraphArrow } from \"@/registry/default/graph-arrow/graph-arrow\"\nimport { Graph, GraphBody } from \"@/registry/default/graph-frame/graph-frame\"\nimport {\n  fadeUp,\n  staggerList,\n  toneClass as paletteTone,\n  type GraphPalette,\n} from \"@/registry/default/graph-motion/graph-motion\"\nimport { cn } from \"@/lib/utils\"\n\ntype FlowTone = \"default\" | \"accent\" | \"muted\"\n\ntype FlowNode = {\n  label: string\n  tone?: FlowTone\n  stretch?: boolean\n}\n\ntype FlowRow = {\n  nodes: FlowNode[]\n}\n\ntype GraphFlowProps = {\n  title: string\n  rows: FlowRow[]\n  palette?: GraphPalette\n  corner?: string\n  className?: string\n}\n\nfunction nodeTone(palette: GraphPalette | undefined): Record<FlowTone, string> {\n  return {\n    default: \"text-foreground\",\n    accent: paletteTone(palette, \"primary\"),\n    muted: paletteTone(palette, \"secondary\"),\n  }\n}\n\nfunction GraphFlow({\n  title,\n  rows,\n  palette,\n  corner,\n  className,\n}: GraphFlowProps) {\n  const reduce = useReducedMotion()\n  const item = fadeUp(reduce)\n  const list = staggerList(reduce, 0.08)\n  const tones = nodeTone(palette)\n\n  return (\n    <Graph title={title} className={className} corner={corner}>\n      <GraphBody className=\"flex flex-col gap-7\">\n        <motion.div\n          className=\"flex flex-col gap-7\"\n          initial={reduce ? false : \"hidden\"}\n          variants={list}\n          viewport={{ once: true, amount: 0.5 }}\n          whileInView=\"show\"\n        >\n          {rows.map((row, rowIndex) => (\n            <motion.div\n              key={rowIndex}\n              className=\"flex min-w-0 flex-wrap items-center gap-x-3 gap-y-2 sm:flex-nowrap\"\n              variants={item}\n            >\n              {row.nodes.map((node, nodeIndex) => {\n                const tone = node.tone ?? \"default\"\n                const live = tone === \"accent\"\n\n                return (\n                  <div\n                    key={`${node.label}-${nodeIndex}`}\n                    className={cn(\n                      \"flex min-w-0 items-center gap-3\",\n                      node.stretch && \"min-w-16 flex-1\"\n                    )}\n                  >\n                    {nodeIndex > 0 ? (\n                      <GraphArrow accent={live} stretch={node.stretch} />\n                    ) : null}\n                    <span\n                      className={cn(\"shrink-0 whitespace-nowrap\", tones[tone])}\n                    >\n                      {node.label}\n                    </span>\n                  </div>\n                )\n              })}\n            </motion.div>\n          ))}\n        </motion.div>\n      </GraphBody>\n    </Graph>\n  )\n}\n\nexport { GraphFlow }\nexport type { FlowNode, FlowRow, GraphFlowProps }\n",
      "type": "registry:component"
    },
    {
      "path": "registry/default/graph-frame/graph-frame.tsx",
      "content": "\"use client\"\n\nimport * as React from \"react\"\n\nimport { cn } from \"@/lib/utils\"\n\nfunction GraphCorners({ mark = \"+\" }: { mark?: string }) {\n  return (\n    <>\n      <span\n        aria-hidden=\"true\"\n        className=\"pointer-events-none absolute top-0 left-0 z-10 block -translate-x-1/2 -translate-y-1/2 bg-background px-0.5 text-graph-frame\"\n      >\n        {mark}\n      </span>\n      <span\n        aria-hidden=\"true\"\n        className=\"pointer-events-none absolute top-0 right-0 z-10 block translate-x-1/2 -translate-y-1/2 bg-background px-0.5 text-graph-frame\"\n      >\n        {mark}\n      </span>\n      <span\n        aria-hidden=\"true\"\n        className=\"pointer-events-none absolute bottom-0 left-0 z-10 block -translate-x-1/2 translate-y-1/2 bg-background px-0.5 text-graph-frame\"\n      >\n        {mark}\n      </span>\n      <span\n        aria-hidden=\"true\"\n        className=\"pointer-events-none absolute right-0 bottom-0 z-10 block translate-x-1/2 translate-y-1/2 bg-background px-0.5 text-graph-frame\"\n      >\n        {mark}\n      </span>\n    </>\n  )\n}\n\nfunction GraphTitle({\n  className,\n  children,\n  ...props\n}: React.ComponentProps<\"figcaption\">) {\n  return (\n    <figcaption\n      className={cn(\n        \"absolute top-0 left-1/2 z-10 -translate-x-1/2 -translate-y-1/2 bg-background px-2.5 tracking-wide whitespace-nowrap uppercase\",\n        className\n      )}\n      {...props}\n    >\n      <span className=\"graph-title-ink text-graph-accent\">[ {children} ]</span>\n    </figcaption>\n  )\n}\n\nfunction GraphBody({ className, ...props }: React.ComponentProps<\"div\">) {\n  return (\n    <div className={cn(\"px-5 py-7 sm:px-8 sm:py-8\", className)} {...props} />\n  )\n}\n\nfunction GraphRule({ className, ...props }: React.ComponentProps<\"div\">) {\n  return (\n    <div\n      aria-hidden=\"true\"\n      className={cn(\"graph-rule w-full\", className)}\n      {...props}\n    />\n  )\n}\n\nfunction GraphTrack({ className, ...props }: React.ComponentProps<\"span\">) {\n  return (\n    <span\n      aria-hidden=\"true\"\n      className={cn(\"flex w-full min-w-0 select-none\", className)}\n      {...props}\n    />\n  )\n}\n\nfunction GraphTick({ className, ...props }: React.ComponentProps<\"span\">) {\n  return (\n    <span\n      className={cn(\"min-w-[1ch] flex-1 text-center\", className)}\n      {...props}\n    />\n  )\n}\n\nfunction Graph({\n  title,\n  corner = \"+\",\n  className,\n  children,\n  ...props\n}: React.ComponentProps<\"figure\"> & {\n  title?: string\n  corner?: string\n}) {\n  const captionId = React.useId()\n\n  return (\n    <figure\n      aria-labelledby={title ? captionId : undefined}\n      className={cn(\n        \"relative min-w-0 graph-frame font-mono text-sm text-foreground\",\n        className\n      )}\n      {...props}\n    >\n      {title ? <GraphTitle id={captionId}>{title}</GraphTitle> : null}\n      <GraphCorners mark={corner} />\n      {children}\n    </figure>\n  )\n}\n\nexport {\n  Graph,\n  GraphBody,\n  GraphCorners,\n  GraphRule,\n  GraphTick,\n  GraphTitle,\n  GraphTrack,\n}\n",
      "type": "registry:ui"
    },
    {
      "path": "registry/default/graph-funnel/graph-funnel.tsx",
      "content": "\"use client\"\n\nimport { motion, useReducedMotion } from \"@/registry/default/motion-static/motion-static\"\n\nimport {\n  Graph,\n  GraphBody,\n  GraphTick,\n  GraphTrack,\n} from \"@/registry/default/graph-frame/graph-frame\"\nimport {\n  fadeUp,\n  isMonoPalette,\n  seriesClass,\n  seriesDim,\n  staggerList,\n  trackMarks,\n  type Glyphs,\n  type GraphPalette,\n} from \"@/registry/default/graph-motion/graph-motion\"\n\ntype FunnelStep = {\n  label: string\n  value: number\n  display?: string\n}\n\ntype GraphFunnelProps = {\n  title: string\n  steps: FunnelStep[]\n  ticks?: number\n  stage?: string\n  glyphs?: Glyphs\n  palette?: GraphPalette\n  corner?: string\n  className?: string\n}\n\nfunction GraphFunnel({\n  title,\n  steps,\n  ticks = 20,\n  stage,\n  glyphs,\n  palette,\n  corner,\n  className,\n}: GraphFunnelProps) {\n  const reduce = useReducedMotion()\n  const item = fadeUp(reduce)\n  const list = staggerList(reduce, 0.05)\n  const max = Math.max(...steps.map((step) => step.value), 1)\n  const head = steps[0]?.value || 1\n  const marks = trackMarks(glyphs)\n\n  return (\n    <Graph title={title} className={className} corner={corner}>\n      <GraphBody>\n        <motion.ol\n          className=\"flex flex-col gap-3\"\n          initial={reduce ? false : \"hidden\"}\n          role=\"list\"\n          variants={list}\n          viewport={{ once: true, amount: 0.4 }}\n          whileInView=\"show\"\n        >\n          {steps.map((step, index) => {\n            const width = Math.max(1, Math.round((step.value / max) * ticks))\n            const percent = Math.round((step.value / head) * 100)\n            const focused = Boolean(stage) && step.label === stage\n            const dim = Boolean(stage) && !focused\n\n            return (\n              <motion.li\n                className=\"grid grid-cols-[7rem_minmax(0,1fr)_8ch_4ch] items-center gap-x-4\"\n                key={step.label}\n                style={seriesDim(palette, !dim)}\n                variants={item}\n              >\n                <span className=\"truncate text-foreground\">{step.label}</span>\n                <GraphTrack>\n                  {Array.from({ length: ticks }, (_, cell) => {\n                    const filled = cell < width\n\n                    return (\n                      <GraphTick\n                        className={\n                          filled\n                            ? isMonoPalette(palette)\n                              ? \"text-graph-accent\"\n                              : seriesClass(palette, index)\n                            : \"text-graph-frame\"\n                        }\n                        key={cell}\n                      >\n                        {filled ? marks.fill : marks.empty}\n                      </GraphTick>\n                    )\n                  })}\n                </GraphTrack>\n                <span className=\"text-right text-foreground tabular-nums\">\n                  {step.display ?? step.value.toLocaleString()}\n                </span>\n                <span className=\"text-right text-graph-muted tabular-nums\">\n                  {index === 0 ? \"\" : `${percent}%`}\n                </span>\n              </motion.li>\n            )\n          })}\n        </motion.ol>\n      </GraphBody>\n    </Graph>\n  )\n}\n\nexport { GraphFunnel }\nexport type { FunnelStep, GraphFunnelProps }\n",
      "type": "registry:component"
    },
    {
      "path": "registry/default/graph-gantt/graph-gantt.tsx",
      "content": "\"use client\"\n\nimport { motion, useReducedMotion } from \"@/registry/default/motion-static/motion-static\"\n\nimport {\n  Graph,\n  GraphBody,\n  GraphTick,\n  GraphTrack,\n} from \"@/registry/default/graph-frame/graph-frame\"\nimport {\n  clamp01,\n  fadeUp,\n  seriesDim,\n  staggerList,\n  toneClass,\n  trackMarks,\n  type Glyphs,\n  type GraphPalette,\n} from \"@/registry/default/graph-motion/graph-motion\"\nimport { cn } from \"@/lib/utils\"\n\ntype GanttItem = {\n  label: string\n  start: number\n  end: number\n  accent?: boolean\n  complete?: number\n}\n\ntype GraphGanttProps = {\n  title: string\n  items: GanttItem[]\n  ticks?: string[]\n  columns?: number\n  stage?: string\n  progress?: number\n  glyphs?: Glyphs\n  palette?: GraphPalette\n  corner?: string\n  className?: string\n}\n\nfunction GraphGantt({\n  title,\n  items,\n  ticks,\n  columns = 24,\n  stage,\n  progress,\n  glyphs,\n  palette,\n  corner,\n  className,\n}: GraphGanttProps) {\n  const reduce = useReducedMotion()\n  const item = fadeUp(reduce)\n  const list = staggerList(reduce, 0.05)\n  const playhead =\n    progress == null ? null : Math.round(clamp01(progress) * (columns - 1))\n  const marks = trackMarks(glyphs)\n\n  return (\n    <Graph title={title} className={className} corner={corner}>\n      <GraphBody className=\"flex flex-col gap-4\">\n        {playhead != null ? (\n          <div className=\"grid grid-cols-[7rem_minmax(0,1fr)] gap-x-4\">\n            <span />\n            <GraphTrack>\n              {Array.from({ length: columns }, (_, index) => (\n                <GraphTick\n                  className={\n                    index === playhead\n                      ? toneClass(palette, \"primary\")\n                      : \"text-transparent\"\n                  }\n                  key={index}\n                >\n                  ▾\n                </GraphTick>\n              ))}\n            </GraphTrack>\n          </div>\n        ) : null}\n        <motion.ul\n          className=\"flex flex-col gap-2\"\n          initial={reduce ? false : \"hidden\"}\n          role=\"list\"\n          variants={list}\n          viewport={{ once: true, amount: 0.4 }}\n          whileInView=\"show\"\n        >\n          {items.map((entry) => {\n            const start = Math.round(clamp01(entry.start) * columns)\n            const end = Math.max(\n              start + 1,\n              Math.round(clamp01(entry.end) * columns)\n            )\n            const span = end - start\n            const done = Math.round(clamp01(entry.complete ?? 1) * span)\n            const focused = stage\n              ? entry.label === stage\n              : Boolean(entry.accent)\n            const dim = Boolean(stage) && !focused\n\n            return (\n              <motion.li\n                aria-label={`${entry.label} from ${Math.round(entry.start * 100)}% to ${Math.round(entry.end * 100)}%${\n                  entry.complete != null\n                    ? `, ${Math.round(entry.complete * 100)}% complete`\n                    : \"\"\n                }`}\n                className=\"grid grid-cols-[7rem_minmax(0,1fr)] items-center gap-x-4\"\n                key={entry.label}\n                style={seriesDim(palette, !dim)}\n                variants={item}\n              >\n                <span\n                  className={cn(\n                    \"truncate\",\n                    focused ? toneClass(palette, \"primary\") : \"text-foreground\"\n                  )}\n                >\n                  {entry.label}\n                </span>\n                <GraphTrack>\n                  {Array.from({ length: columns }, (_, index) => {\n                    const inBar = index >= start && index < end\n                    const filled = inBar && index < start + done\n                    const rest = inBar && !filled\n\n                    return (\n                      <GraphTick\n                        className={\n                          filled\n                            ? focused\n                              ? toneClass(palette, \"primary\")\n                              : \"text-foreground\"\n                            : rest\n                              ? toneClass(palette, \"secondary\")\n                              : toneClass(palette, \"empty\")\n                        }\n                        key={index}\n                      >\n                        {filled ? marks.fill : rest ? marks.rest : marks.empty}\n                      </GraphTick>\n                    )\n                  })}\n                </GraphTrack>\n              </motion.li>\n            )\n          })}\n        </motion.ul>\n        {ticks && ticks.length > 0 ? (\n          <div className=\"grid grid-cols-[7rem_minmax(0,1fr)] gap-x-4\">\n            <span />\n            <div className=\"flex justify-between text-graph-muted\">\n              {ticks.map((tick) => (\n                <span key={tick}>{tick}</span>\n              ))}\n            </div>\n          </div>\n        ) : null}\n      </GraphBody>\n    </Graph>\n  )\n}\n\nexport { GraphGantt }\nexport type { GanttItem, GraphGanttProps }\n",
      "type": "registry:component"
    },
    {
      "path": "registry/default/graph-heatmap/graph-heatmap.tsx",
      "content": "\"use client\"\n\nimport { motion, useReducedMotion } from \"@/registry/default/motion-static/motion-static\"\n\nimport { Graph, GraphBody } from \"@/registry/default/graph-frame/graph-frame\"\nimport {\n  fadeUp,\n  intensityClass,\n  intensityGlyph,\n  intensityLevel,\n  resolveGlyphs,\n  staggerList,\n  type Glyphs,\n  type GraphPalette,\n} from \"@/registry/default/graph-motion/graph-motion\"\nimport { cn } from \"@/lib/utils\"\n\ntype HeatRow = {\n  label: string\n  values: number[]\n}\n\ntype GraphHeatmapProps = {\n  title: string\n  columns: string[]\n  rows: HeatRow[]\n  max?: number\n  legend?: boolean\n  caption?: string\n  glyphs?: Glyphs\n  palette?: GraphPalette\n  corner?: string\n  className?: string\n}\n\nfunction IntensityScale({\n  glyphs,\n  palette,\n}: {\n  glyphs: readonly string[]\n  palette?: GraphPalette\n}) {\n  return (\n    <p className=\"flex items-center gap-2 text-graph-muted\">\n      <span>Less</span>\n      <span aria-hidden=\"true\" className=\"flex select-none\">\n        {glyphs.map((glyph, index) => (\n          <span\n            className={cn(\n              \"w-[1ch] text-center\",\n              intensityClass(\n                Math.round((index / Math.max(glyphs.length - 1, 1)) * 4),\n                palette\n              )\n            )}\n            key={`${glyph}-${index}`}\n          >\n            {glyph}\n          </span>\n        ))}\n      </span>\n      <span>More</span>\n    </p>\n  )\n}\n\nfunction GraphHeatmap({\n  title,\n  columns,\n  rows,\n  max,\n  legend = true,\n  caption,\n  glyphs,\n  palette,\n  corner,\n  className,\n}: GraphHeatmapProps) {\n  const reduce = useReducedMotion()\n  const item = fadeUp(reduce)\n  const list = staggerList(reduce, 0.04)\n  const peak = max ?? Math.max(0, ...rows.flatMap((row) => row.values), 0)\n  const template = `7rem repeat(${Math.max(columns.length, 1)}, minmax(1.25ch, 1fr))`\n  const set = resolveGlyphs(glyphs)\n\n  return (\n    <Graph title={title} className={className} corner={corner}>\n      <GraphBody className=\"flex flex-col gap-4\">\n        <div className=\"flex w-full flex-col gap-2\">\n          <div\n            className=\"grid w-full items-end gap-x-1\"\n            style={{ gridTemplateColumns: template }}\n          >\n            <span />\n            {columns.map((column) => (\n              <span\n                className=\"truncate text-center text-graph-muted\"\n                key={column}\n              >\n                {column}\n              </span>\n            ))}\n          </div>\n          <motion.ul\n            className=\"flex flex-col gap-1\"\n            initial={reduce ? false : \"hidden\"}\n            role=\"list\"\n            variants={list}\n            viewport={{ once: true, amount: 0.4 }}\n            whileInView=\"show\"\n          >\n            {rows.map((row) => (\n              <motion.li\n                aria-label={`${row.label}: ${columns\n                  .map((column, index) => `${column} ${row.values[index] ?? 0}`)\n                  .join(\", \")}`}\n                className=\"grid items-center gap-x-1\"\n                key={row.label}\n                style={{ gridTemplateColumns: template }}\n                variants={item}\n              >\n                <span className=\"truncate text-foreground\">{row.label}</span>\n                {columns.map((column, index) => {\n                  const value = row.values[index] ?? 0\n                  const level = intensityLevel(value, peak)\n\n                  return (\n                    <span\n                      aria-hidden=\"true\"\n                      className={cn(\n                        \"text-center leading-none select-none\",\n                        intensityClass(level, palette)\n                      )}\n                      key={`${row.label}-${column}`}\n                    >\n                      {intensityGlyph(level, set)}\n                    </span>\n                  )\n                })}\n              </motion.li>\n            ))}\n          </motion.ul>\n        </div>\n        {legend || caption ? (\n          <div className=\"flex flex-wrap items-center justify-between gap-3\">\n            {caption ? <p className=\"text-graph-muted\">{caption}</p> : <span />}\n            {legend ? <IntensityScale glyphs={set} palette={palette} /> : null}\n          </div>\n        ) : null}\n      </GraphBody>\n    </Graph>\n  )\n}\n\nexport { GraphHeatmap }\nexport type { GraphHeatmapProps, HeatRow }\n",
      "type": "registry:component"
    },
    {
      "path": "registry/default/graph-invoice/graph-invoice.tsx",
      "content": "\"use client\"\n\nimport { motion, useReducedMotion } from \"@/registry/default/motion-static/motion-static\"\n\nimport {\n  Graph,\n  GraphBody,\n  GraphRule,\n} from \"@/registry/default/graph-frame/graph-frame\"\nimport {\n  fadeUp,\n  staggerList,\n} from \"@/registry/default/graph-motion/graph-motion\"\nimport { cn } from \"@/lib/utils\"\n\ntype InvoiceParty = {\n  name: string\n  lines?: string[]\n}\n\ntype InvoiceMeta = {\n  label: string\n  value: string\n}\n\ntype InvoiceItem = {\n  description: string\n  qty?: string\n  rate?: string\n  amount: string\n}\n\ntype InvoiceTotal = {\n  label: string\n  value: string\n  accent?: boolean\n}\n\ntype GraphInvoiceProps = {\n  title: string\n  from?: InvoiceParty\n  to?: InvoiceParty\n  meta?: InvoiceMeta[]\n  items: InvoiceItem[]\n  totals?: InvoiceTotal[]\n  note?: string\n  corner?: string\n  className?: string\n}\n\nfunction Party({ label, party }: { label: string; party: InvoiceParty }) {\n  return (\n    <div className=\"flex flex-col gap-1\">\n      <p className=\"font-mono tracking-wide text-graph-muted uppercase\">\n        {label}\n      </p>\n      <p className=\"text-foreground\">{party.name}</p>\n      {party.lines?.map((line) => (\n        <p className=\"text-graph-muted\" key={line}>\n          {line}\n        </p>\n      ))}\n    </div>\n  )\n}\n\nfunction GraphInvoice({\n  title,\n  from,\n  to,\n  meta,\n  items,\n  totals,\n  note,\n  corner,\n  className,\n}: GraphInvoiceProps) {\n  const reduce = useReducedMotion()\n  const item = fadeUp(reduce)\n  const list = staggerList(reduce, 0.04)\n  const showQty = items.some((row) => row.qty != null)\n  const showRate = items.some((row) => row.rate != null)\n  const columns = 1 + Number(showQty) + Number(showRate) + 1\n\n  return (\n    <Graph title={title} className={className} corner={corner}>\n      <GraphBody className=\"flex flex-col gap-8\">\n        {from || to ? (\n          <div className=\"grid gap-6 sm:grid-cols-2\">\n            {from ? <Party label=\"From\" party={from} /> : null}\n            {to ? <Party label=\"Bill to\" party={to} /> : null}\n          </div>\n        ) : null}\n\n        {meta && meta.length > 0 ? (\n          <dl className=\"flex flex-wrap gap-x-8 gap-y-3\">\n            {meta.map((entry) => (\n              <div className=\"flex flex-col gap-1\" key={entry.label}>\n                <dt className=\"font-mono tracking-wide text-graph-muted uppercase\">\n                  {entry.label}\n                </dt>\n                <dd className=\"text-foreground tabular-nums\">{entry.value}</dd>\n              </div>\n            ))}\n          </dl>\n        ) : null}\n\n        <div className=\"@container overflow-x-auto\">\n          <table className=\"w-full min-w-lg border-separate border-spacing-0\">\n            <thead>\n              <tr>\n                <th className=\"px-0 pb-3 text-left font-normal text-graph-muted\">\n                  Description\n                </th>\n                {showQty ? (\n                  <th className=\"px-3 pb-3 text-right font-normal text-graph-muted\">\n                    Qty\n                  </th>\n                ) : null}\n                {showRate ? (\n                  <th className=\"px-3 pb-3 text-right font-normal text-graph-muted\">\n                    Rate\n                  </th>\n                ) : null}\n                <th className=\"px-0 pb-3 text-right font-normal text-graph-muted\">\n                  Amount\n                </th>\n              </tr>\n              <tr>\n                <th colSpan={columns} className=\"p-0\">\n                  <GraphRule />\n                </th>\n              </tr>\n            </thead>\n            <motion.tbody\n              initial={reduce ? false : \"hidden\"}\n              variants={list}\n              viewport={{ once: true, amount: 0.4 }}\n              whileInView=\"show\"\n            >\n              {items.map((row) => (\n                <motion.tr key={row.description} variants={item}>\n                  <td className=\"px-0 py-2.5 text-left\">{row.description}</td>\n                  {showQty ? (\n                    <td className=\"px-3 py-2.5 text-right tabular-nums\">\n                      {row.qty ?? \"\"}\n                    </td>\n                  ) : null}\n                  {showRate ? (\n                    <td className=\"px-3 py-2.5 text-right tabular-nums\">\n                      {row.rate ?? \"\"}\n                    </td>\n                  ) : null}\n                  <td className=\"px-0 py-2.5 text-right tabular-nums\">\n                    {row.amount}\n                  </td>\n                </motion.tr>\n              ))}\n            </motion.tbody>\n          </table>\n        </div>\n\n        {totals && totals.length > 0 ? (\n          <div className=\"flex flex-col gap-3\">\n            <GraphRule />\n            <motion.dl\n              className=\"ml-auto flex w-full max-w-[22rem] flex-col gap-2\"\n              initial={reduce ? false : \"hidden\"}\n              variants={list}\n              viewport={{ once: true }}\n              whileInView=\"show\"\n            >\n              {totals.map((entry) => (\n                <motion.div\n                  className=\"grid grid-cols-[minmax(0,1fr)_8rem] items-baseline gap-x-4\"\n                  key={entry.label}\n                  variants={item}\n                >\n                  <dt\n                    className={cn(\n                      entry.accent ? \"text-foreground\" : \"text-graph-muted\"\n                    )}\n                  >\n                    {entry.label}\n                  </dt>\n                  <dd\n                    className={cn(\n                      \"text-right tabular-nums\",\n                      entry.accent ? \"text-graph-accent\" : \"text-foreground\"\n                    )}\n                  >\n                    {entry.value}\n                  </dd>\n                </motion.div>\n              ))}\n            </motion.dl>\n          </div>\n        ) : null}\n\n        {note ? (\n          <p className=\"max-w-[48ch] text-pretty text-graph-muted\">{note}</p>\n        ) : null}\n      </GraphBody>\n    </Graph>\n  )\n}\n\nexport { GraphInvoice }\nexport type {\n  GraphInvoiceProps,\n  InvoiceItem,\n  InvoiceMeta,\n  InvoiceParty,\n  InvoiceTotal,\n}\n",
      "type": "registry:component"
    },
    {
      "path": "registry/default/graph-kpi/graph-kpi.tsx",
      "content": "\"use client\"\n\nimport { motion, useReducedMotion } from \"@/registry/default/motion-static/motion-static\"\n\nimport {\n  Graph,\n  GraphBody,\n  GraphTick,\n  GraphTrack,\n} from \"@/registry/default/graph-frame/graph-frame\"\nimport {\n  DIM_OPACITY,\n  fadeUp,\n  fillDelay,\n  graphTransition,\n  isMonoPalette,\n  resolveGlyphs,\n  toneClass,\n  type Glyphs,\n  type GraphPalette,\n} from \"@/registry/default/graph-motion/graph-motion\"\nimport { cn } from \"@/lib/utils\"\n\nconst SPARK_DEFAULT = [\"▁\", \"▂\", \"▃\", \"▄\", \"▅\", \"▆\", \"▇\", \"█\"]\n\ntype GraphKpiProps = {\n  title: string\n  value: string\n  label: string\n  hint?: string\n  data: number[]\n  glyphs?: Glyphs\n  palette?: GraphPalette\n  corner?: string\n  className?: string\n}\n\nfunction GraphKpi({\n  title,\n  value,\n  label,\n  hint,\n  data,\n  glyphs,\n  palette,\n  corner,\n  className,\n}: GraphKpiProps) {\n  const reduce = useReducedMotion()\n  const enter = fadeUp(reduce)\n  const max = Math.max(...data, 1)\n  const last = data.length - 1\n  const set = glyphs == null ? SPARK_DEFAULT : resolveGlyphs(glyphs)\n  const points = data.map((entry) => {\n    const index = Math.round((entry / max) * (set.length - 1))\n    return set[index] ?? set[0] ?? \"▁\"\n  })\n\n  return (\n    <Graph title={title} className={className} corner={corner}>\n      <GraphBody className=\"flex flex-col gap-4\">\n        <motion.div\n          className=\"flex flex-col gap-2\"\n          initial={reduce ? false : \"hidden\"}\n          variants={enter}\n          viewport={{ once: true, amount: 0.5 }}\n          whileInView=\"show\"\n        >\n          <p\n            className={cn(\n              \"text-3xl tracking-tight tabular-nums sm:text-4xl\",\n              toneClass(palette, \"primary\")\n            )}\n          >\n            {value}\n          </p>\n          <div className=\"flex items-baseline gap-3\">\n            <p className=\"text-graph-muted\">{label}</p>\n            {hint ? (\n              <p className=\"text-graph-muted tabular-nums\">{hint}</p>\n            ) : null}\n          </div>\n        </motion.div>\n        {points.length > 0 ? (\n          <GraphTrack className=\"justify-start gap-0.5\">\n            {points.map((glyph, index) => {\n              const live = index === last\n\n              return (\n                <GraphTick className=\"flex-none\" key={`${glyph}-${index}`}>\n                  <motion.span\n                    className={cn(\n                      live\n                        ? toneClass(palette, \"primary\")\n                        : toneClass(palette, \"secondary\")\n                    )}\n                    initial={reduce ? false : { opacity: 0 }}\n                    transition={graphTransition(reduce, {\n                      delay: fillDelay(reduce, index),\n                    })}\n                    viewport={{ once: true }}\n                    whileInView={{\n                      opacity:\n                        live || !isMonoPalette(palette) ? 1 : DIM_OPACITY,\n                    }}\n                  >\n                    {glyph}\n                  </motion.span>\n                </GraphTick>\n              )\n            })}\n          </GraphTrack>\n        ) : null}\n        <span className=\"sr-only\">\n          {value} {label}\n          {hint ? `. ${hint}` : \"\"}\n        </span>\n      </GraphBody>\n    </Graph>\n  )\n}\n\nexport { GraphKpi }\nexport type { GraphKpiProps }\n",
      "type": "registry:component"
    },
    {
      "path": "registry/default/graph-meter/graph-meter.tsx",
      "content": "\"use client\"\n\nimport { motion, useReducedMotion } from \"@/registry/default/motion-static/motion-static\"\n\nimport {\n  Graph,\n  GraphBody,\n  GraphTick,\n  GraphTrack,\n} from \"@/registry/default/graph-frame/graph-frame\"\nimport {\n  fillDelay,\n  graphTransition,\n  toneClass,\n  trackMarks,\n  type Glyphs,\n  type GraphPalette,\n} from \"@/registry/default/graph-motion/graph-motion\"\nimport { cn } from \"@/lib/utils\"\n\ntype GraphMeterProps = {\n  title: string\n  value: number\n  ticks?: number\n  caption?: string\n  glyphs?: Glyphs\n  palette?: GraphPalette\n  corner?: string\n  className?: string\n}\n\nfunction GraphMeter({\n  title,\n  value,\n  ticks = 14,\n  caption,\n  glyphs,\n  palette,\n  corner,\n  className,\n}: GraphMeterProps) {\n  const reduce = useReducedMotion()\n  const clamped = Math.min(1, Math.max(0, value))\n  const filled = Math.round(clamped * ticks)\n  const marks = trackMarks(glyphs, {\n    empty: \"-\",\n    rest: \"=\",\n    fill: \"=\",\n  })\n\n  return (\n    <Graph title={title} className={className} corner={corner}>\n      <GraphBody className=\"flex flex-col gap-4\">\n        <p className=\"flex w-full items-center gap-3 tabular-nums\">\n          <span aria-hidden=\"true\" className=\"text-graph-frame select-none\">\n            [\n          </span>\n          <GraphTrack>\n            {Array.from({ length: ticks }, (_, index) => {\n              const isFilled = index < filled\n\n              return (\n                <GraphTick\n                  className={\n                    isFilled\n                      ? toneClass(palette, \"primary\")\n                      : \"text-graph-frame\"\n                  }\n                  key={index}\n                >\n                  <motion.span\n                    className=\"block w-full\"\n                    initial={reduce || !isFilled ? false : { opacity: 0 }}\n                    transition={graphTransition(reduce, {\n                      delay: fillDelay(reduce, index),\n                    })}\n                    viewport={{ once: true }}\n                    whileInView={{ opacity: 1 }}\n                  >\n                    {isFilled ? marks.fill : marks.empty}\n                  </motion.span>\n                </GraphTick>\n              )\n            })}\n          </GraphTrack>\n          <span aria-hidden=\"true\" className=\"text-graph-frame select-none\">\n            ]\n          </span>\n          <span\n            className={cn(\n              \"w-[4ch] shrink-0 text-right\",\n              toneClass(palette, \"primary\")\n            )}\n          >\n            {Math.round(clamped * 100)}%\n          </span>\n        </p>\n        {caption ? <p className=\"text-graph-muted\">{caption}</p> : null}\n        <span className=\"sr-only\">\n          {Math.round(clamped * 100)} percent\n          {caption ? ` ${caption}` : \"\"}\n        </span>\n      </GraphBody>\n    </Graph>\n  )\n}\n\nexport { GraphMeter }\nexport type { GraphMeterProps }\n",
      "type": "registry:component"
    },
    {
      "path": "registry/default/graph-motion/graph-motion.ts",
      "content": "import type { Transition, Variants } from \"@/registry/default/motion-static/motion-static\"\n\nexport const easeOutCubic = [0.215, 0.61, 0.355, 1] as const\n\n/**\n * Upstream 0.4. This site holds every piece of text to 4.5:1, and at 40%\n * opacity nothing clears it: the muted grey is only at 5.1:1 to begin with,\n * and even full-strength foreground text falls to about 2.8:1. So nothing is\n * dimmed here — the accent alone marks the row or column being pointed at,\n * which is the argument the section is making anyway. Colour marks; it does\n * not have to shout the rest down.\n */\nexport const DIM_OPACITY = 1\n\nexport function graphTransition(\n  reduce: boolean | null,\n  extras?: Transition\n): Transition {\n  if (reduce) {\n    return { duration: 0 }\n  }\n\n  return {\n    duration: 0.22,\n    ease: easeOutCubic,\n    ...extras,\n  }\n}\n\nexport function fadeUp(reduce: boolean | null): Variants {\n  if (reduce) {\n    return {\n      hidden: { opacity: 1, transform: \"translateY(0px)\" },\n      show: { opacity: 1, transform: \"translateY(0px)\" },\n    }\n  }\n\n  return {\n    hidden: { opacity: 0, transform: \"translateY(8px)\" },\n    show: {\n      opacity: 1,\n      transform: \"translateY(0px)\",\n      transition: graphTransition(false),\n    },\n  }\n}\n\nexport function staggerList(reduce: boolean | null, stagger = 0.04): Variants {\n  return {\n    hidden: {},\n    show: {\n      transition: reduce ? { duration: 0 } : { staggerChildren: stagger },\n    },\n  }\n}\n\nexport function fillDelay(reduce: boolean | null, index: number, step = 0.03) {\n  if (reduce) {\n    return 0\n  }\n\n  return Math.min(index * step, 0.28)\n}\n\nexport function clamp01(value: number) {\n  return Math.min(1, Math.max(0, value))\n}\n\nexport const GLYPH_SETS = {\n  shade: [\"·\", \"░\", \"▒\", \"▓\", \"█\"],\n  ascii: [\".\", \"-\", \"=\", \"#\", \"@\"],\n  hash: [\".\", \":\", \"+\", \"#\", \"█\"],\n  bar: [\"▁\", \"▂\", \"▃\", \"▅\", \"█\"],\n} as const\n\nexport type GlyphSetName = keyof typeof GLYPH_SETS\nexport type Glyphs = GlyphSetName | readonly string[]\n\nexport const INTENSITY_GLYPHS = GLYPH_SETS.shade\n\nexport function resolveGlyphs(glyphs?: Glyphs): readonly string[] {\n  if (glyphs == null) {\n    return GLYPH_SETS.shade\n  }\n\n  if (typeof glyphs === \"string\") {\n    return GLYPH_SETS[glyphs] ?? GLYPH_SETS.shade\n  }\n\n  return glyphs.length > 0 ? glyphs : GLYPH_SETS.shade\n}\n\nexport function trackMarks(\n  glyphs?: Glyphs,\n  fallback: { empty: string; rest: string; fill: string } = {\n    empty: \"-\",\n    rest: \"░\",\n    fill: \"█\",\n  }\n) {\n  if (glyphs == null) {\n    return fallback\n  }\n\n  const set = resolveGlyphs(glyphs)\n  const last = set.length - 1\n\n  return {\n    empty: set[0] ?? fallback.empty,\n    rest: set[Math.min(1, last)] ?? fallback.rest,\n    fill: set[last] ?? fallback.fill,\n  }\n}\n\nexport function intensityLevel(value: number, max: number) {\n  if (value <= 0 || max <= 0) {\n    return 0\n  }\n\n  return Math.max(1, Math.round(clamp01(value / max) * 4))\n}\n\nexport function intensityGlyph(\n  level: number,\n  glyphs: readonly string[] = INTENSITY_GLYPHS\n) {\n  if (glyphs.length === 0) {\n    return \"·\"\n  }\n\n  const clamped = Math.min(4, Math.max(0, Math.round(level)))\n  const index = Math.round((clamped / 4) * (glyphs.length - 1))\n  return glyphs[index] ?? glyphs[0] ?? \"·\"\n}\n\nexport function intensityClass(level: number, palette: GraphPalette = \"mono\") {\n  const index = Math.min(4, Math.max(0, Math.round(level)))\n\n  if (index <= 0) {\n    return \"text-graph-frame\"\n  }\n\n  if (palette === \"mono\") {\n    if (index <= 2) {\n      return \"text-graph-muted\"\n    }\n\n    if (index === 3) {\n      return \"text-foreground\"\n    }\n\n    return \"text-graph-accent\"\n  }\n\n  if (palette === \"multi\") {\n    if (index === 1) {\n      return \"text-graph-accent-2\"\n    }\n\n    if (index <= 3) {\n      return \"text-graph-accent-3\"\n    }\n\n    return \"text-graph-accent\"\n  }\n\n  if (index <= 2) {\n    return \"text-graph-accent-2\"\n  }\n\n  return \"text-graph-accent\"\n}\n\nexport type GraphPalette = \"mono\" | \"duo\" | \"multi\"\n\nconst SERIES_TONES = [\n  \"text-graph-accent\",\n  \"text-graph-accent-2\",\n  \"text-graph-accent-3\",\n] as const\n\nexport function isMonoPalette(palette?: GraphPalette) {\n  return palette == null || palette === \"mono\"\n}\n\nexport function seriesClass(palette: GraphPalette | undefined, index: number) {\n  if (isMonoPalette(palette)) {\n    return index === 0 ? \"text-graph-accent\" : \"text-foreground\"\n  }\n\n  const count = palette === \"duo\" ? 2 : 3\n  return SERIES_TONES[index % count]\n}\n\nexport function seriesDim(\n  palette: GraphPalette | undefined,\n  highlighted: boolean\n) {\n  if (!isMonoPalette(palette) || highlighted) {\n    return undefined\n  }\n\n  return { opacity: DIM_OPACITY }\n}\n\nexport function toneClass(\n  palette: GraphPalette | undefined,\n  role: \"primary\" | \"secondary\" | \"idle\" | \"empty\"\n) {\n  if (role === \"empty\") {\n    return \"text-graph-frame\"\n  }\n\n  if (role === \"idle\") {\n    return \"text-graph-muted\"\n  }\n\n  if (role === \"primary\") {\n    return \"text-graph-accent\"\n  }\n\n  return isMonoPalette(palette) ? \"text-graph-muted\" : \"text-graph-accent-2\"\n}\n",
      "type": "registry:lib"
    },
    {
      "path": "registry/default/graph-plot/graph-plot.tsx",
      "content": "\"use client\"\n\nimport { motion, useReducedMotion } from \"@/registry/default/motion-static/motion-static\"\n\nimport {\n  Graph,\n  GraphBody,\n  GraphRule,\n} from \"@/registry/default/graph-frame/graph-frame\"\nimport {\n  clamp01,\n  fillDelay,\n  graphTransition,\n  toneClass,\n  trackMarks,\n  type Glyphs,\n  type GraphPalette,\n} from \"@/registry/default/graph-motion/graph-motion\"\nimport { cn } from \"@/lib/utils\"\n\ntype GraphPlotProps = {\n  title: string\n  data: number[]\n  labels?: string[]\n  height?: number\n  variant?: \"line\" | \"area\"\n  progress?: number\n  glyphs?: Glyphs\n  palette?: GraphPalette\n  corner?: string\n  className?: string\n}\n\nfunction formatTick(value: number) {\n  if (Number.isInteger(value)) {\n    return String(value)\n  }\n\n  return value.toFixed(1)\n}\n\nfunction GraphPlot({\n  title,\n  data,\n  labels,\n  height = 7,\n  variant = \"area\",\n  progress = 1,\n  glyphs,\n  palette,\n  corner,\n  className,\n}: GraphPlotProps) {\n  const reduce = useReducedMotion()\n  const max = Math.max(...data, 0)\n  const min = Math.min(0, ...data)\n  const range = max - min || 1\n  const end = labels?.[labels.length - 1]\n  const start = labels?.[0]\n  const yLabel = formatTick(max)\n  const revealed = Math.round(clamp01(progress) * data.length)\n  const lastLive = Math.max(0, revealed - 1)\n  const marks = trackMarks(glyphs)\n\n  return (\n    <Graph title={title} className={className} corner={corner}>\n      <GraphBody className=\"flex flex-col gap-3\">\n        <div className=\"flex gap-3\">\n          <div\n            className=\"flex w-[4ch] shrink-0 flex-col justify-between py-px text-right text-graph-muted tabular-nums\"\n            style={{ height: `${height}em` }}\n          >\n            <span>{yLabel}</span>\n            <span>{formatTick(min)}</span>\n          </div>\n          <div\n            aria-hidden=\"true\"\n            className=\"flex min-w-0 flex-1 items-end select-none\"\n            style={{ height: `${height}em` }}\n          >\n            {data.map((value, column) => {\n              const level = Math.round(((value - min) / range) * (height - 1))\n              const live = column === lastLive && column < revealed\n              const shown = column < revealed\n\n              return (\n                <span\n                  className=\"flex h-full min-w-[1ch] flex-1 flex-col justify-end\"\n                  key={column}\n                >\n                  {Array.from({ length: height }, (_, row) => {\n                    const fromBottom = height - 1 - row\n                    const isCap = shown && fromBottom === level\n                    const isFill =\n                      shown && variant === \"area\" && fromBottom < level\n                    const glyph = isCap ? marks.fill : isFill ? marks.rest : \" \"\n                    const tone = isCap\n                      ? live\n                        ? toneClass(palette, \"primary\")\n                        : \"text-foreground\"\n                      : isFill\n                        ? toneClass(palette, \"secondary\")\n                        : \"text-transparent\"\n\n                    return (\n                      <motion.span\n                        className={cn(\"h-[1em] w-full text-center\", tone)}\n                        initial={\n                          reduce || !shown || glyph === \" \"\n                            ? false\n                            : { opacity: 0 }\n                        }\n                        key={row}\n                        transition={graphTransition(reduce, {\n                          delay: fillDelay(reduce, column),\n                        })}\n                        viewport={{ once: true }}\n                        whileInView={{ opacity: 1 }}\n                      >\n                        {glyph}\n                      </motion.span>\n                    )\n                  })}\n                </span>\n              )\n            })}\n          </div>\n        </div>\n        {start || end ? (\n          <>\n            <div className=\"flex gap-3\">\n              <span className=\"invisible w-[4ch] shrink-0 tabular-nums\">\n                {yLabel}\n              </span>\n              <GraphRule className=\"flex-1\" />\n            </div>\n            <div className=\"flex gap-3\">\n              <span className=\"invisible w-[4ch] shrink-0 tabular-nums\">\n                {yLabel}\n              </span>\n              <div className=\"flex flex-1 justify-between text-graph-muted\">\n                <span>{start}</span>\n                {end && end !== start ? <span>{end}</span> : null}\n              </div>\n            </div>\n          </>\n        ) : null}\n        <span className=\"sr-only\">\n          {variant} plot, {data.length} points, min {formatTick(min)}, max{\" \"}\n          {formatTick(max)}\n        </span>\n      </GraphBody>\n    </Graph>\n  )\n}\n\nexport { GraphPlot }\nexport type { GraphPlotProps }\n",
      "type": "registry:component"
    },
    {
      "path": "registry/default/graph-rank/graph-rank.tsx",
      "content": "\"use client\"\n\nimport { motion, useReducedMotion } from \"@/registry/default/motion-static/motion-static\"\n\nimport {\n  Graph,\n  GraphBody,\n  GraphTick,\n  GraphTrack,\n} from \"@/registry/default/graph-frame/graph-frame\"\nimport {\n  fadeUp,\n  staggerList,\n  toneClass,\n  trackMarks,\n  type Glyphs,\n  type GraphPalette,\n} from \"@/registry/default/graph-motion/graph-motion\"\n\ntype RankItem = {\n  label: string\n  value: number\n  display?: string\n}\n\ntype GraphRankProps = {\n  title: string\n  items: RankItem[]\n  max?: number\n  ticks?: number\n  glyphs?: Glyphs\n  palette?: GraphPalette\n  corner?: string\n  className?: string\n}\n\nfunction formatValue(item: RankItem) {\n  if (item.display) {\n    return item.display\n  }\n\n  return item.value.toLocaleString(\"en-US\", {\n    maximumFractionDigits: Number.isInteger(item.value) ? 0 : 1,\n  })\n}\n\nfunction GraphRank({\n  title,\n  items,\n  max,\n  ticks = 20,\n  glyphs,\n  palette,\n  corner,\n  className,\n}: GraphRankProps) {\n  const reduce = useReducedMotion()\n  const item = fadeUp(reduce)\n  const list = staggerList(reduce, 0.05)\n  const peak = max ?? Math.max(...items.map((entry) => entry.value), 1)\n  const marks = trackMarks(glyphs, {\n    empty: \"-\",\n    rest: \"=\",\n    fill: \"=\",\n  })\n\n  return (\n    <Graph title={title} className={className} corner={corner}>\n      <GraphBody className=\"flex flex-col gap-3\">\n        <motion.ol\n          className=\"flex w-full list-none flex-col gap-2\"\n          initial={reduce ? false : \"hidden\"}\n          variants={list}\n          viewport={{ once: true, amount: 0.4 }}\n          whileInView=\"show\"\n        >\n          {items.map((entry) => {\n            const filled = Math.min(\n              ticks,\n              Math.round((Math.max(entry.value, 0) / peak) * ticks)\n            )\n            const shown = formatValue(entry)\n\n            return (\n              <motion.li\n                aria-label={`${entry.label} ${shown}`}\n                className=\"grid grid-cols-[7rem_minmax(0,1fr)_7rem] items-center gap-x-4\"\n                key={entry.label}\n                variants={item}\n              >\n                <span className=\"truncate text-foreground\">{entry.label}</span>\n                <span className=\"flex min-w-0 items-center\">\n                  <span\n                    aria-hidden=\"true\"\n                    className=\"text-graph-frame select-none\"\n                  >\n                    [\n                  </span>\n                  <GraphTrack>\n                    {Array.from({ length: ticks }, (_, index) => {\n                      const on = index < filled\n\n                      return (\n                        <GraphTick\n                          className={\n                            on\n                              ? toneClass(palette, \"primary\")\n                              : \"text-graph-frame\"\n                          }\n                          key={index}\n                        >\n                          {on ? marks.fill : marks.empty}\n                        </GraphTick>\n                      )\n                    })}\n                  </GraphTrack>\n                  <span\n                    aria-hidden=\"true\"\n                    className=\"text-graph-frame select-none\"\n                  >\n                    ]\n                  </span>\n                </span>\n                <span className=\"text-right text-graph-muted tabular-nums\">\n                  {shown}\n                </span>\n              </motion.li>\n            )\n          })}\n        </motion.ol>\n      </GraphBody>\n    </Graph>\n  )\n}\n\nexport { GraphRank }\nexport type { GraphRankProps, RankItem }\n",
      "type": "registry:component"
    },
    {
      "path": "registry/default/graph-slope/graph-slope.tsx",
      "content": "\"use client\"\n\nimport { motion, useReducedMotion } from \"@/registry/default/motion-static/motion-static\"\n\nimport { Graph, GraphBody } from \"@/registry/default/graph-frame/graph-frame\"\nimport {\n  fadeUp,\n  staggerList,\n  toneClass,\n  type GraphPalette,\n} from \"@/registry/default/graph-motion/graph-motion\"\nimport { cn } from \"@/lib/utils\"\n\ntype SlopeItem = {\n  label: string\n  from: number\n  to: number\n}\n\ntype GraphSlopeProps = {\n  title: string\n  fromLabel: string\n  toLabel: string\n  items: SlopeItem[]\n  palette?: GraphPalette\n  corner?: string\n  className?: string\n}\n\nfunction format(value: number) {\n  return value.toLocaleString(\"en-US\", {\n    maximumFractionDigits: Number.isInteger(value) ? 0 : 1,\n  })\n}\n\nfunction GraphSlope({\n  title,\n  fromLabel,\n  toLabel,\n  items,\n  palette,\n  corner,\n  className,\n}: GraphSlopeProps) {\n  const reduce = useReducedMotion()\n  const item = fadeUp(reduce)\n  const list = staggerList(reduce, 0.05)\n\n  return (\n    <Graph title={title} className={className} corner={corner}>\n      <GraphBody className=\"flex flex-col gap-3\">\n        <div className=\"grid grid-cols-[minmax(0,1fr)_6.5rem_2rem_6.5rem] items-end gap-x-3\">\n          <span />\n          <span className=\"text-right text-graph-muted\">{fromLabel}</span>\n          <span />\n          <span className=\"text-right text-graph-muted\">{toLabel}</span>\n        </div>\n        <motion.ul\n          className=\"flex flex-col gap-2\"\n          initial={reduce ? false : \"hidden\"}\n          role=\"list\"\n          variants={list}\n          viewport={{ once: true, amount: 0.4 }}\n          whileInView=\"show\"\n        >\n          {items.map((row) => {\n            const up = row.to > row.from\n            const down = row.to < row.from\n\n            return (\n              <motion.li\n                aria-label={`${row.label} from ${format(row.from)} to ${format(row.to)}`}\n                className=\"grid grid-cols-[minmax(0,1fr)_6.5rem_2rem_6.5rem] items-baseline gap-x-3\"\n                key={row.label}\n                variants={item}\n              >\n                <span className=\"truncate text-foreground\">{row.label}</span>\n                <span className=\"text-right text-graph-muted tabular-nums\">\n                  {format(row.from)}\n                </span>\n                <span\n                  aria-hidden=\"true\"\n                  className={cn(\n                    \"text-center select-none\",\n                    up && toneClass(palette, \"primary\"),\n                    down && toneClass(palette, \"secondary\"),\n                    !up && !down && toneClass(palette, \"empty\")\n                  )}\n                >\n                  {up ? \"→\" : down ? \"→\" : \"–\"}\n                </span>\n                <span\n                  className={cn(\n                    \"text-right tabular-nums\",\n                    up && toneClass(palette, \"primary\"),\n                    down && toneClass(palette, \"secondary\"),\n                    !up && !down && \"text-foreground\"\n                  )}\n                >\n                  {format(row.to)}\n                </span>\n              </motion.li>\n            )\n          })}\n        </motion.ul>\n      </GraphBody>\n    </Graph>\n  )\n}\n\nexport { GraphSlope }\nexport type { GraphSlopeProps, SlopeItem }\n",
      "type": "registry:component"
    },
    {
      "path": "registry/default/graph-spark/graph-spark.tsx",
      "content": "\"use client\"\n\nimport { motion, useReducedMotion } from \"@/registry/default/motion-static/motion-static\"\n\nimport {\n  Graph,\n  GraphBody,\n  GraphTick,\n  GraphTrack,\n} from \"@/registry/default/graph-frame/graph-frame\"\nimport {\n  DIM_OPACITY,\n  fillDelay,\n  graphTransition,\n  isMonoPalette,\n  resolveGlyphs,\n  toneClass,\n  type Glyphs,\n  type GraphPalette,\n} from \"@/registry/default/graph-motion/graph-motion\"\nimport { cn } from \"@/lib/utils\"\n\nconst SPARK_DEFAULT = [\"▁\", \"▂\", \"▃\", \"▄\", \"▅\", \"▆\", \"▇\", \"█\"]\n\ntype GraphSparkProps = {\n  title: string\n  data: number[]\n  caption?: string\n  glyphs?: Glyphs\n  palette?: GraphPalette\n  corner?: string\n  className?: string\n}\n\nfunction GraphSpark({\n  title,\n  data,\n  caption,\n  glyphs,\n  palette,\n  corner,\n  className,\n}: GraphSparkProps) {\n  const reduce = useReducedMotion()\n  const max = Math.max(...data, 1)\n  const last = data.length - 1\n  const set = glyphs == null ? SPARK_DEFAULT : resolveGlyphs(glyphs)\n  const points = data.map((value) => {\n    const index = Math.round((value / max) * (set.length - 1))\n    return set[index] ?? set[0] ?? \"▁\"\n  })\n\n  return (\n    <Graph title={title} className={className} corner={corner}>\n      <GraphBody className=\"flex flex-col items-center gap-4\">\n        <GraphTrack className=\"justify-center gap-0.5\">\n          {points.map((glyph, index) => {\n            const live = index === last\n\n            return (\n              <GraphTick className=\"flex-none\" key={`${glyph}-${index}`}>\n                <motion.span\n                  className={cn(\n                    live\n                      ? toneClass(palette, \"primary\")\n                      : toneClass(palette, \"secondary\")\n                  )}\n                  initial={reduce ? false : { opacity: 0 }}\n                  transition={graphTransition(reduce, {\n                    delay: fillDelay(reduce, index),\n                  })}\n                  viewport={{ once: true }}\n                  whileInView={{\n                    opacity: live || !isMonoPalette(palette) ? 1 : DIM_OPACITY,\n                  }}\n                >\n                  {glyph}\n                </motion.span>\n              </GraphTick>\n            )\n          })}\n        </GraphTrack>\n        {caption ? <p className=\"text-graph-muted\">{caption}</p> : null}\n        <span className=\"sr-only\">\n          Sparkline with {data.length} points\n          {caption ? `. ${caption}` : \"\"}\n        </span>\n      </GraphBody>\n    </Graph>\n  )\n}\n\nexport { GraphSpark }\nexport type { GraphSparkProps }\n",
      "type": "registry:component"
    },
    {
      "path": "registry/default/graph-spec/graph-spec.tsx",
      "content": "\"use client\"\n\nimport { motion, useReducedMotion } from \"@/registry/default/motion-static/motion-static\"\n\nimport { Graph, GraphBody } from \"@/registry/default/graph-frame/graph-frame\"\nimport {\n  fadeUp,\n  staggerList,\n} from \"@/registry/default/graph-motion/graph-motion\"\nimport { cn } from \"@/lib/utils\"\n\ntype SpecRow = {\n  label: string\n  value: string\n  accent?: boolean\n}\n\ntype GraphSpecProps = {\n  title: string\n  rows: SpecRow[]\n  corner?: string\n  className?: string\n}\n\nfunction GraphSpec({ title, rows, corner, className }: GraphSpecProps) {\n  const reduce = useReducedMotion()\n  const item = fadeUp(reduce)\n  const list = staggerList(reduce, 0.04)\n\n  return (\n    <Graph title={title} className={className} corner={corner}>\n      <GraphBody>\n        <motion.dl\n          className=\"flex flex-col gap-3\"\n          initial={reduce ? false : \"hidden\"}\n          variants={list}\n          viewport={{ once: true, amount: 0.5 }}\n          whileInView=\"show\"\n        >\n          {rows.map((row) => (\n            <motion.div\n              className=\"grid grid-cols-[minmax(7rem,11rem)_minmax(0,1fr)] items-baseline gap-x-6\"\n              key={row.label}\n              variants={item}\n            >\n              <dt className=\"text-graph-muted\">{row.label}</dt>\n              <dd\n                className={cn(\n                  \"tabular-nums\",\n                  row.accent ? \"text-graph-accent\" : \"text-foreground\"\n                )}\n              >\n                {row.value}\n              </dd>\n            </motion.div>\n          ))}\n        </motion.dl>\n      </GraphBody>\n    </Graph>\n  )\n}\n\nexport { GraphSpec }\nexport type { GraphSpecProps, SpecRow }\n",
      "type": "registry:component"
    },
    {
      "path": "registry/default/graph-stack/graph-stack.tsx",
      "content": "\"use client\"\n\nimport { motion, useReducedMotion } from \"@/registry/default/motion-static/motion-static\"\n\nimport {\n  Graph,\n  GraphBody,\n  GraphTick,\n  GraphTrack,\n} from \"@/registry/default/graph-frame/graph-frame\"\nimport {\n  fadeUp,\n  isMonoPalette,\n  resolveGlyphs,\n  seriesClass,\n  seriesDim,\n  staggerList,\n  type Glyphs,\n  type GraphPalette,\n} from \"@/registry/default/graph-motion/graph-motion\"\n\nconst DEFAULT_GLYPHS = [\"█\", \"▓\", \"▒\", \"░\", \"#\", \"=\", \"+\", \"-\"]\n\ntype StackSegment = {\n  label: string\n  value: number\n}\n\ntype StackRow = {\n  label: string\n  segments: StackSegment[]\n}\n\ntype GraphStackProps = {\n  title: string\n  rows: StackRow[]\n  accent?: string\n  ticks?: number\n  glyphs?: Glyphs\n  palette?: GraphPalette\n  corner?: string\n  className?: string\n}\n\ntype Painted = {\n  label: string\n  glyph: string\n  count: number\n  accent: boolean\n}\n\nfunction paintRow(\n  segments: StackSegment[],\n  ticks: number,\n  glyphs: readonly string[],\n  accentLabel?: string\n): Painted[] {\n  const total = segments.reduce((sum, segment) => sum + segment.value, 0) || 1\n  let left = ticks\n\n  return segments.map((segment, index) => {\n    const raw = Math.round((segment.value / total) * ticks)\n    const count =\n      index === segments.length - 1\n        ? Math.max(0, left)\n        : Math.min(Math.max(0, raw), left)\n    left -= count\n    const highlighted = accentLabel\n      ? segment.label === accentLabel\n      : index === 0\n\n    return {\n      label: segment.label,\n      glyph: glyphs[index % glyphs.length] ?? \"█\",\n      count,\n      accent: highlighted,\n    }\n  })\n}\n\nfunction GraphStack({\n  title,\n  rows,\n  accent,\n  ticks = 24,\n  glyphs,\n  palette,\n  corner,\n  className,\n}: GraphStackProps) {\n  const reduce = useReducedMotion()\n  const item = fadeUp(reduce)\n  const list = staggerList(reduce, 0.05)\n  const set = glyphs == null ? DEFAULT_GLYPHS : resolveGlyphs(glyphs)\n  const legend: string[] = []\n\n  for (const row of rows) {\n    for (const segment of row.segments) {\n      if (!legend.includes(segment.label)) {\n        legend.push(segment.label)\n      }\n    }\n  }\n\n  return (\n    <Graph title={title} className={className} corner={corner}>\n      <GraphBody className=\"flex flex-col gap-6\">\n        <motion.ul\n          className=\"flex flex-col gap-3\"\n          initial={reduce ? false : \"hidden\"}\n          role=\"list\"\n          variants={list}\n          viewport={{ once: true, amount: 0.4 }}\n          whileInView=\"show\"\n        >\n          {rows.map((row) => {\n            const painted = paintRow(row.segments, ticks, set, accent)\n\n            return (\n              <motion.li\n                aria-label={`${row.label}: ${row.segments\n                  .map((segment) => `${segment.label} ${segment.value}`)\n                  .join(\", \")}`}\n                className=\"grid grid-cols-[7rem_minmax(0,1fr)] items-center gap-x-4\"\n                key={row.label}\n                variants={item}\n              >\n                <span className=\"truncate text-foreground\">{row.label}</span>\n                <GraphTrack>\n                  {painted.flatMap((piece) =>\n                    Array.from({ length: piece.count }, (_, index) => (\n                      <GraphTick\n                        className={seriesClass(\n                          palette,\n                          legend.indexOf(piece.label)\n                        )}\n                        key={`${piece.label}-${index}`}\n                        style={seriesDim(\n                          palette,\n                          isMonoPalette(palette) ? piece.accent : true\n                        )}\n                      >\n                        {piece.glyph}\n                      </GraphTick>\n                    ))\n                  )}\n                </GraphTrack>\n              </motion.li>\n            )\n          })}\n        </motion.ul>\n        <ul className=\"flex flex-wrap gap-x-4 gap-y-1\" role=\"list\">\n          {legend.map((label, index) => {\n            const glyph = set[index % set.length] ?? \"█\"\n            const highlighted = isMonoPalette(palette)\n              ? accent\n                ? label === accent\n                : index === 0\n              : true\n\n            return (\n              <li\n                className=\"flex items-center gap-2\"\n                key={label}\n                style={seriesDim(palette, highlighted)}\n              >\n                <span\n                  aria-hidden=\"true\"\n                  className={seriesClass(palette, index)}\n                >\n                  {glyph}\n                </span>\n                <span\n                  className={\n                    highlighted ? \"text-foreground\" : \"text-graph-muted\"\n                  }\n                >\n                  {label}\n                </span>\n              </li>\n            )\n          })}\n        </ul>\n      </GraphBody>\n    </Graph>\n  )\n}\n\nexport { GraphStack }\nexport type { GraphStackProps, StackRow, StackSegment }\n",
      "type": "registry:component"
    },
    {
      "path": "registry/default/graph-stat/graph-stat.tsx",
      "content": "\"use client\"\n\nimport { motion, useReducedMotion } from \"@/registry/default/motion-static/motion-static\"\n\nimport { Graph, GraphBody } from \"@/registry/default/graph-frame/graph-frame\"\nimport {\n  fadeUp,\n  staggerList,\n} from \"@/registry/default/graph-motion/graph-motion\"\nimport { cn } from \"@/lib/utils\"\n\nconst columnClass: Record<number, string> = {\n  1: \"sm:grid-cols-1\",\n  2: \"sm:grid-cols-2\",\n  3: \"sm:grid-cols-3\",\n  4: \"sm:grid-cols-4\",\n}\n\ntype StatItem = {\n  value: string\n  label: string\n  hint?: string\n  accent?: boolean\n}\n\ntype GraphStatProps = {\n  title: string\n  items: StatItem[]\n  corner?: string\n  className?: string\n}\n\nfunction GraphStat({ title, items, corner, className }: GraphStatProps) {\n  const reduce = useReducedMotion()\n  const item = fadeUp(reduce)\n  const list = staggerList(reduce, 0.06)\n  const columns = Math.min(items.length, 4)\n\n  return (\n    <Graph title={title} className={className} corner={corner}>\n      <GraphBody>\n        <motion.ul\n          className={cn(\"grid gap-8\", columnClass[columns])}\n          initial={reduce ? false : \"hidden\"}\n          role=\"list\"\n          variants={list}\n          viewport={{ once: true, amount: 0.5 }}\n          whileInView=\"show\"\n        >\n          {items.map((entry) => (\n            <motion.li\n              className=\"flex flex-col gap-2\"\n              key={entry.label}\n              variants={item}\n            >\n              <p\n                className={cn(\n                  \"text-3xl tracking-tight tabular-nums sm:text-4xl\",\n                  entry.accent ? \"text-graph-accent\" : \"text-foreground\"\n                )}\n              >\n                {entry.value}\n              </p>\n              <p className=\"text-graph-muted\">{entry.label}</p>\n              {entry.hint ? (\n                <p className=\"text-graph-muted\">{entry.hint}</p>\n              ) : null}\n            </motion.li>\n          ))}\n        </motion.ul>\n      </GraphBody>\n    </Graph>\n  )\n}\n\nexport { GraphStat }\nexport type { GraphStatProps, StatItem }\n",
      "type": "registry:component"
    },
    {
      "path": "registry/default/graph-table/graph-table.tsx",
      "content": "\"use client\"\n\nimport type { ReactNode } from \"react\"\n\nimport { motion, useReducedMotion } from \"@/registry/default/motion-static/motion-static\"\n\nimport {\n  Graph,\n  GraphBody,\n  GraphRule,\n} from \"@/registry/default/graph-frame/graph-frame\"\nimport {\n  fadeUp,\n  staggerList,\n} from \"@/registry/default/graph-motion/graph-motion\"\nimport { cn } from \"@/lib/utils\"\n\ntype GraphAlign = \"left\" | \"right\"\n\ntype GraphTableProps = {\n  title: string\n  headers: string[]\n  rows: ReactNode[][]\n  footer?: ReactNode[]\n  align?: GraphAlign[]\n  corner?: string\n  className?: string\n}\n\nfunction GraphTable({\n  title,\n  headers,\n  rows,\n  footer,\n  align,\n  corner,\n  className,\n}: GraphTableProps) {\n  const reduce = useReducedMotion()\n  const item = fadeUp(reduce)\n  const list = staggerList(reduce, 0.04)\n\n  return (\n    <Graph title={title} className={className} corner={corner}>\n      <GraphBody className=\"px-3 py-6 sm:px-6 sm:py-8\">\n        <div className=\"@container overflow-x-auto\">\n          <table className=\"w-full min-w-lg border-separate border-spacing-0\">\n            <thead>\n              <tr>\n                {headers.map((header, index) => (\n                  <th\n                    key={header}\n                    className={cn(\n                      \"px-3 pb-3 font-normal whitespace-nowrap text-foreground\",\n                      (align?.[index] ?? (index === 0 ? \"left\" : \"right\")) ===\n                        \"right\"\n                        ? \"text-right\"\n                        : \"text-left\"\n                    )}\n                  >\n                    {header}\n                  </th>\n                ))}\n              </tr>\n              <tr>\n                <th colSpan={headers.length} className=\"p-0\">\n                  <GraphRule />\n                </th>\n              </tr>\n            </thead>\n            <motion.tbody\n              initial={reduce ? false : \"hidden\"}\n              variants={list}\n              viewport={{ once: true, amount: 0.4 }}\n              whileInView=\"show\"\n            >\n              {rows.map((row, rowIndex) => (\n                <motion.tr key={rowIndex} variants={item}>\n                  {row.map((cell, cellIndex) => (\n                    <td\n                      key={cellIndex}\n                      className={cn(\n                        \"px-3 py-2.5 whitespace-nowrap\",\n                        (align?.[cellIndex] ??\n                          (cellIndex === 0 ? \"left\" : \"right\")) === \"right\"\n                          ? \"text-right tabular-nums\"\n                          : \"text-left\"\n                      )}\n                    >\n                      {cell}\n                    </td>\n                  ))}\n                </motion.tr>\n              ))}\n            </motion.tbody>\n            {footer ? (\n              <tfoot>\n                <tr>\n                  <td colSpan={headers.length} className=\"pt-2 pb-3\">\n                    <GraphRule />\n                  </td>\n                </tr>\n                <tr>\n                  {footer.map((cell, cellIndex) => (\n                    <td\n                      key={cellIndex}\n                      className={cn(\n                        \"px-3 pt-1 whitespace-nowrap\",\n                        (align?.[cellIndex] ??\n                          (cellIndex === 0 ? \"left\" : \"right\")) === \"right\"\n                          ? \"text-right tabular-nums\"\n                          : \"text-left\"\n                      )}\n                    >\n                      {cell}\n                    </td>\n                  ))}\n                </tr>\n              </tfoot>\n            ) : null}\n          </table>\n        </div>\n      </GraphBody>\n    </Graph>\n  )\n}\n\nexport { GraphTable }\nexport type { GraphTableProps }\n",
      "type": "registry:component"
    },
    {
      "path": "registry/default/graph-timeline/graph-timeline.tsx",
      "content": "\"use client\"\n\nimport { motion, useReducedMotion } from \"@/registry/default/motion-static/motion-static\"\n\nimport { Graph, GraphBody } from \"@/registry/default/graph-frame/graph-frame\"\nimport {\n  fadeUp,\n  staggerList,\n  toneClass,\n  type GraphPalette,\n} from \"@/registry/default/graph-motion/graph-motion\"\nimport { cn } from \"@/lib/utils\"\n\ntype TimelineState = \"done\" | \"now\" | \"next\"\n\ntype TimelineEvent = {\n  date: string\n  label: string\n  state?: TimelineState\n}\n\ntype GraphTimelineProps = {\n  title: string\n  events: TimelineEvent[]\n  palette?: GraphPalette\n  corner?: string\n  className?: string\n}\n\nconst mark: Record<TimelineState, string> = {\n  done: \"●\",\n  now: \"●\",\n  next: \"○\",\n}\n\nfunction GraphTimeline({\n  title,\n  events,\n  palette,\n  corner,\n  className,\n}: GraphTimelineProps) {\n  const reduce = useReducedMotion()\n  const item = fadeUp(reduce)\n  const list = staggerList(reduce, 0.05)\n\n  return (\n    <Graph title={title} className={className} corner={corner}>\n      <GraphBody>\n        <motion.ol\n          className=\"flex flex-col\"\n          initial={reduce ? false : \"hidden\"}\n          role=\"list\"\n          variants={list}\n          viewport={{ once: true, amount: 0.4 }}\n          whileInView=\"show\"\n        >\n          {events.map((event, index) => {\n            const state = event.state ?? \"done\"\n            const last = index === events.length - 1\n            const live = state === \"now\"\n\n            return (\n              <motion.li\n                key={`${event.date}-${event.label}`}\n                className=\"flex flex-col\"\n                variants={item}\n              >\n                <div className=\"grid grid-cols-[1.25rem_7rem_minmax(0,1fr)] items-baseline gap-x-4\">\n                  <span\n                    aria-hidden=\"true\"\n                    className={cn(\n                      \"text-center leading-none select-none\",\n                      live && toneClass(palette, \"primary\"),\n                      state === \"done\" && \"text-foreground\",\n                      state === \"next\" && toneClass(palette, \"secondary\")\n                    )}\n                  >\n                    {mark[state]}\n                  </span>\n                  <span\n                    className={cn(\n                      \"tabular-nums\",\n                      state === \"next\"\n                        ? toneClass(palette, \"secondary\")\n                        : \"text-foreground\"\n                    )}\n                  >\n                    {event.date}\n                  </span>\n                  <span\n                    className={cn(\n                      live && toneClass(palette, \"primary\"),\n                      state === \"done\" && \"text-foreground\",\n                      state === \"next\" && toneClass(palette, \"secondary\")\n                    )}\n                  >\n                    {event.label}\n                  </span>\n                </div>\n                {last ? null : (\n                  <div\n                    aria-hidden=\"true\"\n                    className=\"grid grid-cols-[1.25rem_7rem_minmax(0,1fr)] gap-x-4 py-1 select-none\"\n                  >\n                    <span className=\"text-center text-graph-frame\">│</span>\n                  </div>\n                )}\n              </motion.li>\n            )\n          })}\n        </motion.ol>\n      </GraphBody>\n    </Graph>\n  )\n}\n\nexport { GraphTimeline }\nexport type { GraphTimelineProps, TimelineEvent, TimelineState }\n",
      "type": "registry:component"
    },
    {
      "path": "registry/default/graph-timer/graph-timer.tsx",
      "content": "\"use client\"\n\nimport { motion, useReducedMotion } from \"@/registry/default/motion-static/motion-static\"\n\nimport { Graph, GraphBody } from \"@/registry/default/graph-frame/graph-frame\"\nimport {\n  formatAgo,\n  formatClock,\n  formatHms,\n  parseInstant,\n  useGraphNow,\n} from \"@/registry/default/graph-clock/graph-clock\"\nimport {\n  fadeUp,\n  toneClass,\n  type GraphPalette,\n} from \"@/registry/default/graph-motion/graph-motion\"\nimport { cn } from \"@/lib/utils\"\n\ntype TimerKind = \"elapsed\" | \"ago\" | \"clock\"\n\ntype GraphTimerProps = {\n  title: string\n  kind?: TimerKind\n  at?: Date | number | string\n  caption?: string\n  palette?: GraphPalette\n  corner?: string\n  className?: string\n}\n\nfunction GraphTimer({\n  title,\n  kind = \"elapsed\",\n  at,\n  caption,\n  palette,\n  corner,\n  className,\n}: GraphTimerProps) {\n  const reduce = useReducedMotion()\n  const enter = fadeUp(reduce)\n  const now = useGraphNow()\n  const origin = at == null ? Number.NaN : parseInstant(at)\n  let value = kind === \"ago\" ? \"0s ago\" : \"00:00:00\"\n  let spoken = \"timer\"\n\n  if (now != null) {\n    if (kind === \"clock\") {\n      value = formatClock(now)\n      spoken = `local time ${value}`\n    } else if (Number.isFinite(origin)) {\n      const elapsed = Math.max(0, now - origin)\n      if (kind === \"ago\") {\n        value = formatAgo(elapsed)\n        spoken = value\n      } else {\n        value = formatHms(elapsed)\n        spoken = `elapsed ${value}`\n      }\n    }\n  }\n\n  return (\n    <Graph title={title} className={className} corner={corner}>\n      <GraphBody>\n        <motion.div\n          className=\"flex flex-col gap-2\"\n          initial={reduce ? false : \"hidden\"}\n          variants={enter}\n          viewport={{ once: true, amount: 0.5 }}\n          whileInView=\"show\"\n        >\n          <p\n            className={cn(\n              \"text-3xl tracking-tight tabular-nums sm:text-4xl\",\n              toneClass(palette, \"primary\")\n            )}\n          >\n            {value}\n          </p>\n          {caption ? <p className=\"text-graph-muted\">{caption}</p> : null}\n        </motion.div>\n        <span className=\"sr-only\">{spoken}</span>\n      </GraphBody>\n    </Graph>\n  )\n}\n\nexport { GraphTimer }\nexport type { GraphTimerProps, TimerKind }\n",
      "type": "registry:component"
    },
    {
      "path": "registry/default/graph-tree/graph-tree.tsx",
      "content": "\"use client\"\n\nimport { motion, useReducedMotion } from \"@/registry/default/motion-static/motion-static\"\n\nimport { Graph, GraphBody } from \"@/registry/default/graph-frame/graph-frame\"\nimport {\n  DIM_OPACITY,\n  fadeUp,\n  staggerList,\n} from \"@/registry/default/graph-motion/graph-motion\"\nimport { cn } from \"@/lib/utils\"\n\ntype TreeNode = {\n  label: string\n  meta?: string\n  accent?: boolean\n  children?: TreeNode[]\n}\n\ntype GraphTreeProps = {\n  title: string\n  nodes: TreeNode[]\n  corner?: string\n  className?: string\n}\n\ntype FlatRow = {\n  key: string\n  branch: string\n  label: string\n  meta?: string\n  accent?: boolean\n}\n\nfunction flatten(\n  nodes: TreeNode[],\n  prefix = \"\",\n  trail = \"root\",\n  isRoot = true\n): FlatRow[] {\n  const singleRoot = isRoot && nodes.length === 1\n\n  return nodes.flatMap((node, index) => {\n    const last = index === nodes.length - 1\n    const branch = singleRoot ? \"\" : prefix + (last ? \"└─ \" : \"├─ \")\n    const key = `${trail}/${node.label}-${index}`\n    const childPrefix = singleRoot ? \"\" : prefix + (last ? \"   \" : \"│  \")\n    const row: FlatRow = {\n      key,\n      branch,\n      label: node.label,\n      meta: node.meta,\n      accent: node.accent,\n    }\n    const kids = node.children\n      ? flatten(node.children, childPrefix, key, false)\n      : []\n    return [row, ...kids]\n  })\n}\n\nfunction GraphTree({ title, nodes, corner, className }: GraphTreeProps) {\n  const reduce = useReducedMotion()\n  const item = fadeUp(reduce)\n  const list = staggerList(reduce, 0.03)\n  const rows = flatten(nodes)\n  const hasAccent = rows.some((row) => row.accent)\n\n  return (\n    <Graph title={title} className={className} corner={corner}>\n      <GraphBody className=\"overflow-x-auto\">\n        <motion.ul\n          role=\"list\"\n          className=\"flex min-w-max flex-col gap-1\"\n          initial={reduce ? false : \"hidden\"}\n          variants={list}\n          viewport={{ once: true, amount: 0.4 }}\n          whileInView=\"show\"\n        >\n          {rows.map((row) => {\n            const dim = hasAccent && !row.accent\n\n            return (\n              <motion.li\n                key={row.key}\n                className=\"grid grid-cols-[minmax(0,1fr)_auto] items-baseline gap-x-6\"\n                style={dim ? { opacity: DIM_OPACITY } : undefined}\n                variants={item}\n              >\n                <span className=\"whitespace-nowrap\">\n                  <span\n                    aria-hidden=\"true\"\n                    className=\"text-graph-frame select-none\"\n                  >\n                    {row.branch}\n                  </span>\n                  <span\n                    className={cn(\n                      row.accent ? \"text-graph-accent\" : \"text-foreground\"\n                    )}\n                  >\n                    {row.label}\n                  </span>\n                </span>\n                {row.meta ? (\n                  <span className=\"text-graph-muted tabular-nums\">\n                    {row.meta}\n                  </span>\n                ) : (\n                  <span />\n                )}\n              </motion.li>\n            )\n          })}\n        </motion.ul>\n        <span className=\"sr-only\">Tree with {rows.length} nodes</span>\n      </GraphBody>\n    </Graph>\n  )\n}\n\nexport { GraphTree }\nexport type { GraphTreeProps, TreeNode }\n",
      "type": "registry:component"
    },
    {
      "path": "registry/default/graph-uptime/graph-uptime.tsx",
      "content": "\"use client\"\n\nimport { motion, useReducedMotion } from \"@/registry/default/motion-static/motion-static\"\n\nimport {\n  Graph,\n  GraphBody,\n  GraphTick,\n  GraphTrack,\n} from \"@/registry/default/graph-frame/graph-frame\"\nimport {\n  fadeUp,\n  resolveGlyphs,\n  staggerList,\n  toneClass,\n  type Glyphs,\n  type GraphPalette,\n} from \"@/registry/default/graph-motion/graph-motion\"\nimport { cn } from \"@/lib/utils\"\n\ntype UptimeStatus = \"ok\" | \"degraded\" | \"down\" | \"empty\"\n\ntype GraphUptimeProps = {\n  title: string\n  days: UptimeStatus[]\n  from?: string\n  to?: string\n  columns?: number\n  glyphs?: Glyphs\n  palette?: GraphPalette\n  corner?: string\n  className?: string\n}\n\nfunction statusTone(\n  palette: GraphPalette | undefined\n): Record<UptimeStatus, string> {\n  return {\n    ok: toneClass(palette, \"primary\"),\n    degraded: toneClass(palette, \"secondary\"),\n    down: toneClass(palette, \"empty\"),\n    empty: toneClass(palette, \"empty\"),\n  }\n}\n\nfunction GraphUptime({\n  title,\n  days,\n  from,\n  to,\n  columns = 30,\n  glyphs,\n  palette,\n  corner,\n  className,\n}: GraphUptimeProps) {\n  const reduce = useReducedMotion()\n  const item = fadeUp(reduce)\n  const list = staggerList(reduce, 0.05)\n  const known = days.filter((day) => day !== \"empty\")\n  const ok = known.filter((day) => day === \"ok\").length\n  const percent = known.length === 0 ? 0 : Math.round((ok / known.length) * 100)\n  const cols = Math.max(1, columns)\n  const rows: UptimeStatus[][] = []\n  const set = resolveGlyphs(glyphs)\n  const last = set.length - 1\n  const mark: Record<UptimeStatus, string> = {\n    ok: set[last] ?? \"█\",\n    degraded: set[Math.min(2, last)] ?? \"▒\",\n    down: set[0] ?? \"·\",\n    empty: \"-\",\n  }\n  const tone = statusTone(palette)\n\n  for (let index = 0; index < days.length; index += cols) {\n    rows.push(days.slice(index, index + cols))\n  }\n\n  return (\n    <Graph title={title} className={className} corner={corner}>\n      <GraphBody className=\"flex flex-col items-center gap-4\">\n        <div className=\"flex w-fit max-w-full flex-col gap-4\">\n          <motion.div\n            aria-hidden=\"true\"\n            className=\"flex flex-col gap-1 select-none\"\n            initial={reduce ? false : \"hidden\"}\n            variants={list}\n            viewport={{ once: true, amount: 0.4 }}\n            whileInView=\"show\"\n          >\n            {rows.map((row, rowIndex) => (\n              <motion.div key={rowIndex} variants={item}>\n                <GraphTrack className=\"w-auto justify-start gap-0.5\">\n                  {row.map((day, index) => (\n                    <GraphTick\n                      className={cn(\"flex-none\", tone[day])}\n                      key={`${rowIndex}-${index}`}\n                    >\n                      {mark[day]}\n                    </GraphTick>\n                  ))}\n                </GraphTrack>\n              </motion.div>\n            ))}\n          </motion.div>\n          <div className=\"flex flex-wrap items-baseline justify-between gap-3\">\n            <p className={cn(\"tabular-nums\", tone.ok)}>{percent}%</p>\n            {from || to ? (\n              <p className=\"flex gap-3 text-graph-muted\">\n                {from ? <span>{from}</span> : null}\n                {to ? <span>{to}</span> : null}\n              </p>\n            ) : null}\n          </div>\n        </div>\n        <p className=\"flex flex-wrap justify-center gap-x-4 gap-y-1 text-graph-muted\">\n          <span>\n            <span className={tone.ok}>{mark.ok}</span> up\n          </span>\n          <span>\n            <span className={tone.degraded}>{mark.degraded}</span> slow\n          </span>\n          <span>\n            <span className={tone.down}>{mark.down}</span> down\n          </span>\n        </p>\n        <span className=\"sr-only\">\n          {percent} percent uptime over {known.length} days\n          {from && to ? `, ${from} to ${to}` : \"\"}\n        </span>\n      </GraphBody>\n    </Graph>\n  )\n}\n\nexport { GraphUptime }\nexport type { GraphUptimeProps, UptimeStatus }\n",
      "type": "registry:component"
    },
    {
      "path": "registry/default/graph-waffle/graph-waffle.tsx",
      "content": "\"use client\"\n\nimport { motion, useReducedMotion } from \"@/registry/default/motion-static/motion-static\"\n\nimport { Graph, GraphBody } from \"@/registry/default/graph-frame/graph-frame\"\nimport {\n  fillDelay,\n  graphTransition,\n  toneClass,\n  trackMarks,\n  type Glyphs,\n  type GraphPalette,\n} from \"@/registry/default/graph-motion/graph-motion\"\nimport { cn } from \"@/lib/utils\"\n\ntype GraphWaffleProps = {\n  title: string\n  value: number\n  cells?: number\n  columns?: number\n  caption?: string\n  glyphs?: Glyphs\n  palette?: GraphPalette\n  corner?: string\n  className?: string\n}\n\nfunction GraphWaffle({\n  title,\n  value,\n  cells = 100,\n  columns = 10,\n  caption,\n  glyphs,\n  palette,\n  corner,\n  className,\n}: GraphWaffleProps) {\n  const reduce = useReducedMotion()\n  const clamped = Math.min(1, Math.max(0, value))\n  const filled = Math.round(clamped * cells)\n  const rows = Math.ceil(cells / columns)\n  const marks = trackMarks(glyphs, {\n    empty: \"░\",\n    rest: \"░\",\n    fill: \"█\",\n  })\n\n  return (\n    <Graph title={title} className={className} corner={corner}>\n      <GraphBody className=\"flex flex-col gap-4\">\n        <div\n          aria-hidden=\"true\"\n          className=\"flex w-full flex-col gap-1 select-none\"\n        >\n          {Array.from({ length: rows }, (_, row) => (\n            <div className=\"flex w-full\" key={row}>\n              {Array.from({ length: columns }, (_, column) => {\n                const index = row * columns + column\n                if (index >= cells) {\n                  return <span className=\"min-w-[1ch] flex-1\" key={column} />\n                }\n                const isFilled = index < filled\n\n                return (\n                  <motion.span\n                    className={cn(\n                      \"min-w-[1ch] flex-1 text-center\",\n                      isFilled\n                        ? toneClass(palette, \"primary\")\n                        : \"text-graph-frame\"\n                    )}\n                    initial={reduce || !isFilled ? false : { opacity: 0 }}\n                    key={column}\n                    transition={graphTransition(reduce, {\n                      delay: fillDelay(reduce, index, 0.006),\n                    })}\n                    viewport={{ once: true }}\n                    whileInView={{ opacity: 1 }}\n                  >\n                    {isFilled ? marks.fill : marks.empty}\n                  </motion.span>\n                )\n              })}\n            </div>\n          ))}\n        </div>\n        <p className={cn(\"tabular-nums\", toneClass(palette, \"primary\"))}>\n          {Math.round(clamped * 100)}%\n        </p>\n        {caption ? <p className=\"text-graph-muted\">{caption}</p> : null}\n        <span className=\"sr-only\">\n          {Math.round(clamped * 100)} percent\n          {caption ? `. ${caption}` : \"\"}\n        </span>\n      </GraphBody>\n    </Graph>\n  )\n}\n\nexport { GraphWaffle }\nexport type { GraphWaffleProps }\n",
      "type": "registry:component"
    },
    {
      "path": "registry/default/graph-waterfall/graph-waterfall.tsx",
      "content": "\"use client\"\n\nimport { motion, useReducedMotion } from \"@/registry/default/motion-static/motion-static\"\n\nimport {\n  Graph,\n  GraphBody,\n  GraphRule,\n  GraphTick,\n  GraphTrack,\n} from \"@/registry/default/graph-frame/graph-frame\"\nimport {\n  fadeUp,\n  staggerList,\n  toneClass,\n  trackMarks,\n  type Glyphs,\n  type GraphPalette,\n} from \"@/registry/default/graph-motion/graph-motion\"\nimport { cn } from \"@/lib/utils\"\n\ntype WaterfallKind = \"start\" | \"in\" | \"out\" | \"end\"\n\ntype WaterfallItem = {\n  label: string\n  value: number\n  display?: string\n  kind?: WaterfallKind\n}\n\ntype GraphWaterfallProps = {\n  title: string\n  items: WaterfallItem[]\n  ticks?: number\n  glyphs?: Glyphs\n  palette?: GraphPalette\n  corner?: string\n  className?: string\n}\n\nfunction resolveKind(\n  item: WaterfallItem,\n  index: number,\n  length: number\n): WaterfallKind {\n  if (item.kind) {\n    return item.kind\n  }\n\n  if (index === 0) {\n    return \"start\"\n  }\n\n  if (index === length - 1) {\n    return \"end\"\n  }\n\n  return item.value >= 0 ? \"in\" : \"out\"\n}\n\nfunction formatValue(item: WaterfallItem, kind: WaterfallKind) {\n  if (item.display) {\n    return item.display\n  }\n\n  const absolute = Math.abs(item.value)\n\n  if (kind === \"in\") {\n    return `+${absolute.toLocaleString(\"en-US\")}`\n  }\n\n  if (kind === \"out\") {\n    return `−${absolute.toLocaleString(\"en-US\")}`\n  }\n\n  return item.value.toLocaleString(\"en-US\")\n}\n\nfunction GraphWaterfall({\n  title,\n  items,\n  ticks = 24,\n  glyphs,\n  palette,\n  corner,\n  className,\n}: GraphWaterfallProps) {\n  const reduce = useReducedMotion()\n  const item = fadeUp(reduce)\n  const list = staggerList(reduce, 0.05)\n  const marks = trackMarks(glyphs)\n  let run = 0\n  const segments = items.map((entry, index) => {\n    const kind = resolveKind(entry, index, items.length)\n    const magnitude = Math.abs(entry.value)\n\n    if (kind === \"start\") {\n      const from = 0\n      const to = entry.value\n      run = entry.value\n      return { ...entry, kind, from, to }\n    }\n\n    if (kind === \"in\") {\n      const from = run\n      const to = run + magnitude\n      run = to\n      return { ...entry, kind, from, to }\n    }\n\n    if (kind === \"out\") {\n      const to = run\n      const from = run - magnitude\n      run = from\n      return { ...entry, kind, from, to }\n    }\n\n    const total = entry.value\n    run = total\n    return { ...entry, kind, from: 0, to: total }\n  })\n  const lows = segments.map((segment) => Math.min(segment.from, segment.to))\n  const highs = segments.map((segment) => Math.max(segment.from, segment.to))\n  const low = Math.min(0, ...lows)\n  const high = Math.max(1, ...highs)\n  const span = high - low || 1\n\n  function column(value: number) {\n    return Math.round(((value - low) / span) * ticks)\n  }\n\n  return (\n    <Graph title={title} className={className} corner={corner}>\n      <GraphBody className=\"flex flex-col gap-3\">\n        <motion.ul\n          className=\"flex w-full flex-col gap-2\"\n          initial={reduce ? false : \"hidden\"}\n          role=\"list\"\n          variants={list}\n          viewport={{ once: true, amount: 0.4 }}\n          whileInView=\"show\"\n        >\n          {segments.map((segment, index) => {\n            const start = Math.min(column(segment.from), column(segment.to))\n            const end = Math.max(\n              column(segment.from),\n              column(segment.to),\n              start + 1\n            )\n            const isEnd = segment.kind === \"end\"\n            const showRule = isEnd && index > 0\n\n            return (\n              <li className=\"flex flex-col gap-2\" key={segment.label}>\n                {showRule ? <GraphRule /> : null}\n                <motion.div\n                  className=\"grid grid-cols-[7rem_minmax(0,1fr)_5.5rem] items-center gap-x-4\"\n                  variants={item}\n                >\n                  <span className=\"truncate text-foreground\">\n                    {segment.label}\n                  </span>\n                  <GraphTrack>\n                    {Array.from({ length: ticks }, (_, cell) => {\n                      const filled = cell >= start && cell < end\n                      const tone = !filled\n                        ? toneClass(palette, \"empty\")\n                        : segment.kind === \"out\"\n                          ? toneClass(palette, \"secondary\")\n                          : segment.kind === \"start\"\n                            ? \"text-foreground\"\n                            : toneClass(palette, \"primary\")\n\n                      return (\n                        <GraphTick className={tone} key={cell}>\n                          {filled ? marks.fill : marks.empty}\n                        </GraphTick>\n                      )\n                    })}\n                  </GraphTrack>\n                  <span\n                    className={cn(\n                      \"text-right tabular-nums\",\n                      segment.kind === \"out\" && toneClass(palette, \"secondary\"),\n                      segment.kind === \"end\" && toneClass(palette, \"primary\"),\n                      (segment.kind === \"start\" || segment.kind === \"in\") &&\n                        \"text-foreground\"\n                    )}\n                  >\n                    {formatValue(segment, segment.kind)}\n                  </span>\n                </motion.div>\n              </li>\n            )\n          })}\n        </motion.ul>\n        <span className=\"sr-only\">\n          {segments\n            .map(\n              (segment) =>\n                `${segment.label} ${formatValue(segment, segment.kind)}`\n            )\n            .join(\", \")}\n        </span>\n      </GraphBody>\n    </Graph>\n  )\n}\n\nexport { GraphWaterfall }\nexport type { GraphWaterfallProps, WaterfallItem, WaterfallKind }\n",
      "type": "registry:component"
    },
    {
      "path": "registry/default/motion-static/motion-static.ts",
      "content": "/**\n * A static stand-in for `motion/react`, so the vendored mdx-graphs components\n * render as characters and nothing else.\n *\n * Upstream every graph animates: rows stagger in on `whileInView`, glyphs fade\n * up from `initial={{ opacity: 0 }}`. That is a runtime behaviour, and these\n * graphs have no runtime — they are rendered at build time through the React\n * integration with no client directive, so no hydration ever arrives to raise\n * the opacity motion wrote into the markup. Shipping the real library would\n * mean shipping the animation runtime with it, on a page whose whole argument\n * is that a chart can be text.\n *\n * So the graphs take the path the library already has for a reader who does not\n * want motion. `useReducedMotion()` answers true, and every component's own\n * reduced-motion branch resolves its variants to the finished state, skips the\n * `initial` frame, and sets the transitions to zero. `motion.<tag>` is then just\n * `<tag>` with the animation props dropped — `style` and `className` pass\n * through, because two of the components carry real dimming in `style`.\n *\n * Keeping the shim here rather than editing the components means a re-vendor\n * from the registry is a copy plus two import rewrites, not a re-application of\n * hand edits.\n */\n\nimport * as React from \"react\";\n\n/** Structural stubs for the two types graph-motion.ts imports for its helpers. */\nexport type Transition = Record<string, unknown>;\nexport type Variants = Record<string, Record<string, unknown>>;\n\n/**\n * Props that only mean something to the animation runtime. Everything else —\n * className, style, role, aria-*, key, children — is forwarded to the DOM.\n */\nconst MOTION_PROPS = new Set([\n  \"animate\",\n  \"custom\",\n  \"drag\",\n  \"exit\",\n  \"initial\",\n  \"layout\",\n  \"layoutId\",\n  \"onAnimationComplete\",\n  \"onAnimationStart\",\n  \"transition\",\n  \"variants\",\n  \"viewport\",\n  \"whileDrag\",\n  \"whileFocus\",\n  \"whileHover\",\n  \"whileInView\",\n  \"whileTap\",\n]);\n\nfunction strip(props: Record<string, unknown>) {\n  const out: Record<string, unknown> = {};\n  for (const key in props) {\n    if (!MOTION_PROPS.has(key)) out[key] = props[key];\n  }\n  return out;\n}\n\ntype MotionTags = {\n  [K in keyof React.JSX.IntrinsicElements]: React.FC<\n    React.JSX.IntrinsicElements[K] & Record<string, unknown>\n  >;\n};\n\n/**\n * `motion.div`, `motion.li`, … resolved on demand. A Proxy rather than a fixed\n * map so a component vendored later cannot reach for a tag the shim forgot.\n */\nexport const motion = new Proxy({} as MotionTags, {\n  get(cache: Record<string, unknown>, tag: string) {\n    if (!cache[tag]) {\n      const Component = (props: Record<string, unknown>) =>\n        React.createElement(tag, strip(props));\n      Component.displayName = `motion.${tag}`;\n      cache[tag] = Component;\n    }\n    return cache[tag];\n  },\n}) as MotionTags;\n\n/**\n * Always true. Not a claim about the reader's `prefers-reduced-motion` — it is\n * the honest answer for a page that ships no animation runtime at all.\n */\nexport function useReducedMotion(): boolean {\n  return true;\n}\n",
      "type": "registry:lib"
    }
  ],
  "cssVars": {
    "theme": {
      "color-graph-accent": "var(--graph-accent)",
      "color-graph-accent-2": "var(--graph-accent-2)",
      "color-graph-accent-3": "var(--graph-accent-3)",
      "color-graph-frame": "var(--graph-frame)",
      "color-graph-muted": "var(--graph-muted)",
      "color-graph-faint": "var(--graph-faint)",
      "color-contrast-14": "var(--contrast-14)",
      "color-contrast-23": "var(--contrast-23)",
      "color-contrast-45": "var(--contrast-45)",
      "color-contrast-70": "var(--contrast-70)"
    },
    "light": {
      "graph-accent": "oklch(0.5 0.18 255)",
      "graph-accent-2": "oklch(0.58 0.14 70)",
      "graph-accent-3": "oklch(0.5 0.12 165)",
      "graph-frame": "oklch(0.205 0 0 / 0.28)",
      "graph-muted": "oklch(0.52 0 0)",
      "graph-faint": "oklch(0.82 0 0)",
      "contrast-14": "oklch(0.88 0 0)",
      "contrast-23": "oklch(0.76 0 0)",
      "contrast-45": "oklch(0.48 0 0)",
      "contrast-70": "oklch(0.28 0 0)"
    },
    "dark": {
      "graph-accent": "oklch(0.7 0.12 255)",
      "graph-accent-2": "oklch(0.78 0.12 70)",
      "graph-accent-3": "oklch(0.78 0.1 165)",
      "graph-frame": "oklch(0.48 0 0)",
      "graph-muted": "oklch(0.52 0 0)",
      "graph-faint": "oklch(0.28 0 0)",
      "contrast-14": "oklch(0.22 0 0)",
      "contrast-23": "oklch(0.34 0 0)",
      "contrast-45": "oklch(0.62 0 0)",
      "contrast-70": "oklch(0.84 0 0)"
    }
  },
  "css": {
    "@utility graph-frame": {
      "background-image": "repeating-linear-gradient(to right, var(--graph-frame) 0 2px, transparent 2px 7px), repeating-linear-gradient(to bottom, var(--graph-frame) 0 2px, transparent 2px 7px), repeating-linear-gradient(to right, var(--graph-frame) 0 2px, transparent 2px 7px), repeating-linear-gradient(to bottom, var(--graph-frame) 0 2px, transparent 2px 7px)",
      "background-repeat": "repeat-x, repeat-y, repeat-x, repeat-y",
      "background-position": "0 0, 100% 0, 0 100%, 0 0",
      "background-size": "100% 1px, 1px 100%, 100% 1px, 1px 100%"
    },
    "@utility graph-rule": {
      "height": "1px",
      "background-image": "repeating-linear-gradient(to right, var(--graph-frame) 0 2px, transparent 2px 7px)"
    },
    "@utility graph-rule-y": {
      "width": "1px",
      "background-image": "repeating-linear-gradient(to bottom, var(--graph-frame) 0 2px, transparent 2px 7px)"
    }
  },
  "type": "registry:component"
}
