{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "deadline-countdown",
  "title": "Deadline Countdown",
  "description": "Days-to-deadline band with segmented progress and CountUp.",
  "files": [
    {
      "path": "registry/default/blocks/deadline-countdown.tsx",
      "content": "\"use client\"\n\nimport * as React from \"react\"\n\nconst TOTAL_SEGMENTS = 24\nconst DAY_MS = 24 * 60 * 60 * 1000\n\n/** Edit dates and labels after install. */\nconst CONTENT = {\n  title: \"Deadline\",\n  targetDate: \"2026-12-31\",\n  startDate: \"2026-01-01\",\n  unitLabel: \"days\",\n  progressLabel: \"to deadline\",\n}\n\nfunction parseIso(iso: string) {\n  return new Date(iso.length <= 10 ? `${iso}T00:00:00Z` : iso)\n}\n\nfunction daysBetween(fromIso: string, toIso: string) {\n  return Math.round(\n    (parseIso(toIso).getTime() - parseIso(fromIso).getTime()) / DAY_MS\n  )\n}\n\nfunction daysFromNow(iso: string) {\n  const now = new Date()\n  const target = parseIso(iso)\n  return Math.max(0, Math.ceil((target.getTime() - now.getTime()) / DAY_MS))\n}\n\nfunction formatFullDate(iso: string) {\n  return new Intl.DateTimeFormat(\"en-US\", {\n    year: \"numeric\",\n    month: \"long\",\n    day: \"numeric\",\n    timeZone: \"UTC\",\n  }).format(parseIso(iso))\n}\n\n/** Inlined CountUp helper — self-contained registry block. */\nfunction CountUp({\n  value,\n  duration = 1200,\n  className,\n  ariaLabel,\n}: {\n  value: number\n  duration?: number\n  className?: string\n  ariaLabel?: string\n}) {\n  const ref = React.useRef<HTMLSpanElement | null>(null)\n  const [display, setDisplay] = React.useState(0)\n  const startedRef = React.useRef(false)\n\n  React.useEffect(() => {\n    const node = ref.current\n    if (!node) return\n\n    const reduced =\n      window.matchMedia?.(\"(prefers-reduced-motion: reduce)\").matches\n    if (reduced) {\n      setDisplay(value)\n      return\n    }\n\n    let raf = 0\n    const start = () => {\n      if (startedRef.current) return\n      startedRef.current = true\n      const t0 = performance.now()\n      const from = 0\n      const to = value\n      const ease = (t: number) => 1 - Math.pow(1 - t, 4)\n\n      const step = (now: number) => {\n        const t = Math.min(1, (now - t0) / duration)\n        setDisplay(Math.round(from + (to - from) * ease(t)))\n        if (t < 1) raf = requestAnimationFrame(step)\n      }\n      raf = requestAnimationFrame(step)\n    }\n\n    if (typeof IntersectionObserver === \"undefined\") {\n      start()\n      return () => cancelAnimationFrame(raf)\n    }\n\n    const io = new IntersectionObserver(\n      (entries) => {\n        if (entries[0]?.isIntersecting) {\n          start()\n          io.disconnect()\n        }\n      },\n      { threshold: 0.3 }\n    )\n    io.observe(node)\n    return () => {\n      io.disconnect()\n      cancelAnimationFrame(raf)\n    }\n  }, [value, duration])\n\n  return (\n    <span\n      ref={ref}\n      className={className}\n      aria-label={ariaLabel ?? String(value)}\n    >\n      {display}\n    </span>\n  )\n}\n\nexport function DeadlineCountdown({\n  title = CONTENT.title,\n  targetDate = CONTENT.targetDate,\n  startDate = CONTENT.startDate,\n  unitLabel = CONTENT.unitLabel,\n  progressLabel = CONTENT.progressLabel,\n  className,\n}: {\n  title?: string\n  targetDate?: string\n  startDate?: string\n  unitLabel?: string\n  progressLabel?: string\n  className?: string\n} = {}) {\n  const daysRemaining = daysFromNow(targetDate)\n  const totalDays = Math.max(1, daysBetween(startDate, targetDate))\n  const elapsed = Math.max(0, totalDays - daysRemaining)\n  const percent = Math.min(100, Math.round((elapsed / totalDays) * 100))\n  const filledSegments = Math.min(\n    TOTAL_SEGMENTS,\n    Math.round((elapsed / totalDays) * TOTAL_SEGMENTS)\n  )\n\n  return (\n    <section className={className ?? \"mx-auto max-w-[640px]\"}>\n      <div className=\"relative overflow-hidden rounded-[10px] border border-border-subtle bg-muted/40 p-6 sm:p-8\">\n        <div className=\"flex flex-col gap-6 sm:flex-row sm:items-end sm:justify-between\">\n          <div className=\"flex items-baseline gap-3\">\n            <CountUp\n              value={daysRemaining}\n              className=\"text-5xl font-medium tracking-tight tabular-nums text-[var(--color-brand,#0b7bff)] sm:text-6xl\"\n            />\n            <div className=\"pb-1 sm:pb-2\">\n              <div className=\"text-[13px] font-medium text-foreground\">\n                {unitLabel}\n              </div>\n              <div className=\"text-[12px] text-muted-foreground\">remaining</div>\n            </div>\n          </div>\n\n          <div className=\"sm:text-right\">\n            <div className=\"font-mono text-[10.5px] tracking-[0.12em] text-muted-foreground uppercase\">\n              {title}\n            </div>\n            <div className=\"mt-1.5 text-[15px] font-medium tabular-nums text-foreground\">\n              {formatFullDate(targetDate)}\n            </div>\n          </div>\n        </div>\n\n        <div className=\"mt-6\">\n          <div\n            className=\"flex items-center gap-[3px]\"\n            role=\"progressbar\"\n            aria-valuemin={0}\n            aria-valuemax={100}\n            aria-valuenow={percent}\n            aria-label={`${title} progress`}\n          >\n            {Array.from({ length: TOTAL_SEGMENTS }).map((_, i) => {\n              const filled = i < filledSegments\n              return (\n                <span\n                  key={i}\n                  className={\n                    \"h-[6px] flex-1 rounded-[1px] transition-colors duration-300 \" +\n                    (filled\n                      ? \"bg-[var(--color-brand,#0b7bff)]\"\n                      : \"bg-border-subtle\")\n                  }\n                />\n              )\n            })}\n          </div>\n          <div className=\"mt-2.5 flex items-center justify-between font-mono text-[11px] text-muted-foreground\">\n            <span>\n              {elapsed} / {totalDays} days\n            </span>\n            <span>\n              {percent}% {progressLabel}\n            </span>\n          </div>\n        </div>\n      </div>\n    </section>\n  )\n}\n",
      "type": "registry:component",
      "target": "components/blocks/deadline-countdown.tsx"
    }
  ],
  "type": "registry:block"
}