{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "schedule-builder",
  "type": "registry:component",
  "title": "Schedule Builder",
  "description": "A recurrence rule as a live English sentence over real occurrences, with month-end and DST traps.",
  "dependencies": [
    "motion"
  ],
  "registryDependencies": [
    "https://lab.moumen.dev/r/lab-theme.json"
  ],
  "files": [
    {
      "path": "registry/lab/schedule-builder/schedule-builder.tsx",
      "type": "registry:component",
      "target": "@components/lab/schedule-builder.tsx",
      "content": "\"use client\";\n\nimport { useEffect, useMemo, useRef, useState } from \"react\";\nimport { MotionConfig, motion } from \"motion/react\";\n\n// Schedule builder - a recurrence rule assembled as a live English sentence,\n// with the next N REAL occurrences underneath.\n//\n// The domain is the hard part: recurrence looks like dropdowns but is full of\n// calendar traps, and this build refuses to fake any of them:\n//\n//   · Month boundaries. \"Every month on day 31\" cannot run in September.\n//     RRULE semantics SKIP the month (and the list shows a ghost row saying\n//     so); the `clamp` prop switches to the other real-world policy, where\n//     day 31 becomes Sep 30.\n//   · DST. Runs are built from local wall-clock components (year, month,\n//     day, hour), so \"9:00 AM\" stays 9:00 AM across a daylight-saving jump -\n//     the UTC offset is printed on every row and flagged when it differs\n//     from the first run's.\n//   · Nth-weekday math. \"The 2nd Tuesday\" and \"the last Friday\" are computed\n//     from the month's first/last day, never by scanning.\n//\n// The sentence morphs word-by-word: words are keyed by text + occurrence and\n// carry motion's `layout` - surviving words glide to their new positions while\n// new words blur in. Change \"week\" to \"month\" and \"at 9:00 AM\" slides left\n// instead of re-rendering; the sentence reads as one object being edited, not\n// a string being replaced.\n//\n// Read the rule out through `onRuleChange` (it is the component's value).\n// Animation via motion/react; honours prefers-reduced-motion. Requires the\n// lab-theme tokens. Fully Tailwind, no CSS files.\n\nconst EASE = [0.22, 1, 0.36, 1] as const;\n\nconst WEEKDAYS = [\"Sunday\", \"Monday\", \"Tuesday\", \"Wednesday\", \"Thursday\", \"Friday\", \"Saturday\"];\nconst ORDINALS: { value: number | \"last\"; label: string }[] = [\n  { value: 1, label: \"1st\" },\n  { value: 2, label: \"2nd\" },\n  { value: 3, label: \"3rd\" },\n  { value: 4, label: \"4th\" },\n  { value: \"last\", label: \"last\" },\n];\n\nexport interface ScheduleRule {\n  freq: \"daily\" | \"weekly\" | \"monthly\";\n  interval: number;\n  weekdays: number[];\n  monthMode: \"date\" | \"nth\";\n  monthDay: number;\n  ordinal: number | \"last\";\n  weekday: number;\n  hour: number;\n  minute: number;\n}\n\nexport interface ScheduleBuilderState {\n  sentence: string;\n  next: string | null;\n  skips: number;\n  dstChanges: number;\n  freq: ScheduleRule[\"freq\"];\n}\n\ntype RunEntry =\n  | { kind: \"run\"; date: Date; clamped?: boolean }\n  | { kind: \"skip\"; key: string; label: string; month: number };\n\nconst DEFAULT_RULE: ScheduleRule = {\n  freq: \"weekly\",\n  interval: 1,\n  weekdays: [2, 4], // Tue + Thu\n  monthMode: \"date\",\n  monthDay: 31, // deliberately the gnarly default - skips appear immediately\n  ordinal: 2,\n  weekday: 2,\n  hour: 9,\n  minute: 0,\n};\n\nconst monthName = (date: Date) => date.toLocaleString(\"en-US\", { month: \"long\" });\n\n\nfunction offsetLabel(date: Date) {\n  const mins = -date.getTimezoneOffset();\n  const sign = mins >= 0 ? \"+\" : \"-\";\n  const abs = Math.abs(mins);\n  const h = Math.floor(abs / 60);\n  const m = abs % 60;\n  return `GMT${sign}${h}${m ? `:${String(m).padStart(2, \"0\")}` : \"\"}`;\n}\n\nfunction timeLabel(hour: number, minute: number) {\n  const h12 = hour % 12 === 0 ? 12 : hour % 12;\n  return `${h12}:${String(minute).padStart(2, \"0\")}`;\n}\n\n// \"2nd Tuesday of month m\" - computed from the month's first day; \"last\"\n// walks back from the month's last day. A 1st-4th always exists.\nfunction nthWeekdayOf(year: number, month: number, ordinal: number | \"last\", weekday: number, hour: number, minute: number) {\n  if (ordinal === \"last\") {\n    const last = new Date(year, month + 1, 0);\n    const back = (last.getDay() - weekday + 7) % 7;\n    return new Date(year, month, last.getDate() - back, hour, minute);\n  }\n  const first = new Date(year, month, 1);\n  const forward = (weekday - first.getDay() + 7) % 7;\n  return new Date(year, month, 1 + forward + (ordinal - 1) * 7, hour, minute);\n}\n\nconst startOfWeek = (d: Date) => new Date(d.getFullYear(), d.getMonth(), d.getDate() - d.getDay());\nconst WEEK_MS = 7 * 86400000;\n\n// The next `count` occurrences, plus ghost entries for months a day-of-month\n// rule has to skip. Everything is built from LOCAL date components, so DST is\n// handled by the platform, not re-derived.\nfunction computeRuns(rule: ScheduleRule, now: Date, count: number, clamp: boolean): RunEntry[] {\n  const { freq, interval, weekdays, monthMode, monthDay, ordinal, weekday, hour, minute } = rule;\n  const out: RunEntry[] = [];\n  let runs = 0;\n\n  if (freq === \"daily\") {\n    const c = new Date(now.getFullYear(), now.getMonth(), now.getDate(), hour, minute);\n    if (c <= now) c.setDate(c.getDate() + interval);\n    while (runs < count) {\n      out.push({ kind: \"run\", date: new Date(c) });\n      runs += 1;\n      c.setDate(c.getDate() + interval); // setDate keeps local wall-clock across DST\n    }\n  } else if (freq === \"weekly\") {\n    const anchor = startOfWeek(now); // this week starts the interval cycle\n    for (let i = 0; i < 800 && runs < count; i += 1) {\n      const cand = new Date(now.getFullYear(), now.getMonth(), now.getDate() + i, hour, minute);\n      if (!weekdays.includes(cand.getDay())) continue;\n      const weeksAway = Math.round((startOfWeek(cand).getTime() - anchor.getTime()) / WEEK_MS); // round() absorbs the DST hour\n      if (weeksAway % interval !== 0) continue;\n      if (cand <= now) continue;\n      out.push({ kind: \"run\", date: cand });\n      runs += 1;\n    }\n  } else {\n    for (let i = 0; i < 36 && runs < count; i += 1) {\n      const year = now.getFullYear();\n      const month = now.getMonth() + i;\n      if (monthMode === \"date\") {\n        const daysInMonth = new Date(year, month + 1, 0).getDate();\n        if (monthDay > daysInMonth) {\n          if (clamp) {\n            const cand = new Date(year, month, daysInMonth, hour, minute);\n            if (cand > now) {\n              out.push({ kind: \"run\", date: cand, clamped: true });\n              runs += 1;\n            }\n          } else if (new Date(year, month + 1, 0, 23, 59) > now) {\n            // RRULE semantics: the month simply has no day 31 - say so.\n            out.push({\n              kind: \"skip\",\n              key: `skip-${year}-${month}`,\n              label: `${monthName(new Date(year, month, 1))} has only ${daysInMonth} days`,\n              month,\n            });\n          }\n          continue;\n        }\n        const cand = new Date(year, month, monthDay, hour, minute);\n        if (cand > now) {\n          out.push({ kind: \"run\", date: cand });\n          runs += 1;\n        }\n      } else {\n        const cand = nthWeekdayOf(year, month, ordinal, weekday, hour, minute);\n        if (cand > now) {\n          out.push({ kind: \"run\", date: cand });\n          runs += 1;\n        }\n      }\n    }\n  }\n  return out;\n}\n\n// The sentence as a word list. Punctuation rides on its word - keys are\n// text + occurrence, so a surviving \"at\" keeps its identity and glides\n// instead of re-entering.\nfunction sentenceWords(rule: ScheduleRule) {\n  const { freq, interval, weekdays, monthMode, monthDay, ordinal, weekday, hour, minute } = rule;\n  const words = [\"Every\"];\n  if (freq === \"daily\") {\n    if (interval === 1) words.push(\"day\");\n    else words.push(String(interval), \"days\");\n  } else if (freq === \"weekly\") {\n    if (interval === 1) words.push(\"week\");\n    else words.push(String(interval), \"weeks\");\n    words.push(\"on\");\n    const names = [...weekdays].sort((a, b) => a - b).map((d) => WEEKDAYS[d]);\n    names.forEach((name, index) => {\n      if (index === names.length - 1 && names.length > 1) words.push(\"and\");\n      words.push(index < names.length - 2 ? `${name},` : name);\n    });\n  } else {\n    words.push(\"month\", \"on\");\n    if (monthMode === \"date\") words.push(\"day\", String(monthDay));\n    else words.push(\"the\", ORDINALS.find((o) => o.value === ordinal)!.label, WEEKDAYS[weekday]);\n  }\n  words.push(\"at\", timeLabel(hour, minute), hour < 12 ? \"AM\" : \"PM\");\n  const seen: Record<string, number> = {};\n  return words.map((word) => ({ word, key: `${word}·${(seen[word] = (seen[word] ?? 0) + 1)}` }));\n}\n\nconst SEG_BTN =\n  \"h-7 px-2.5 rounded-md bg-transparent text-muted-foreground text-xs font-medium cursor-pointer transition-[background-color,color,scale] duration-150 aria-pressed:bg-primary aria-pressed:text-primary-foreground active:scale-[0.96] focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring\";\nconst STEP_BTN =\n  \"w-7 h-7 rounded-lg bg-transparent text-muted-foreground text-sm cursor-pointer transition-[background-color,color,scale] duration-150 hover:enabled:bg-accent hover:enabled:text-foreground active:enabled:scale-[0.96] disabled:opacity-35 disabled:cursor-default focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring\";\nconst SELECT =\n  \"h-7 px-1.5 rounded-lg bg-background shadow-border text-foreground text-xs font-medium cursor-pointer outline-none transition-shadow duration-150 hover:shadow-border-hover focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring\";\nconst ROW_LABEL = \"w-14 flex-none text-[0.6875rem] font-semibold tracking-[0.06em] uppercase text-muted-foreground/70\";\n\nexport default function ScheduleBuilder({\n  defaultRule,\n  onRuleChange,\n  occurrences = 5,\n  morph = true,\n  clamp = false, // month-end policy: false = RRULE skip · true = clamp to last day\n  inspect = false,\n  onStateChange,\n}: {\n  /** Seed the builder with a partial rule; the rest falls back to the default. */\n  defaultRule?: Partial<ScheduleRule>;\n  /** The component's value: fires with the full rule on every edit. */\n  onRuleChange?: (rule: ScheduleRule) => void;\n  /** How many upcoming runs to prove the rule with. */\n  occurrences?: number;\n  morph?: boolean;\n  clamp?: boolean;\n  inspect?: boolean;\n  onStateChange?: (state: ScheduleBuilderState) => void;\n}) {\n  const [rule, setRule] = useState<ScheduleRule>({ ...DEFAULT_RULE, ...defaultRule });\n  // Entrances are gated behind the first paint - on mount the sentence just is.\n  const mountedRef = useRef(false);\n  useEffect(() => {\n    mountedRef.current = true;\n  }, []);\n\n  const words = useMemo(() => sentenceWords(rule), [rule]);\n  const sentenceText = words.map((w) => w.word).join(\" \");\n  // `now` is pinned per rule-change so the list doesn't jitter between renders.\n  const runs = useMemo(() => computeRuns(rule, new Date(), occurrences, clamp), [rule, clamp, occurrences]);\n  const firstRun = runs.find((entry): entry is Extract<RunEntry, { kind: \"run\" }> => entry.kind === \"run\");\n  const baseOffset = firstRun ? offsetLabel(firstRun.date) : null;\n  const dstChanges = runs.filter((entry) => entry.kind === \"run\" && offsetLabel(entry.date) !== baseOffset).length;\n  const skips = runs.filter((entry) => entry.kind === \"skip\").length;\n\n  const set = (patch: Partial<ScheduleRule>) => setRule((prev) => ({ ...prev, ...patch }));\n\n  function toggleWeekday(day: number) {\n    setRule((prev) => {\n      if (prev.weekdays.includes(day)) {\n        if (prev.weekdays.length === 1) return prev; // a weekly rule needs a day\n        return { ...prev, weekdays: prev.weekdays.filter((d) => d !== day) };\n      }\n      return { ...prev, weekdays: [...prev.weekdays, day] };\n    });\n  }\n\n  useEffect(() => {\n    onRuleChange?.(rule);\n  }, [rule, onRuleChange]);\n\n  useEffect(() => {\n    onStateChange?.({\n      sentence: sentenceText,\n      next: firstRun\n        ? `${firstRun.date.toLocaleDateString(\"en-US\", { weekday: \"short\", month: \"short\", day: \"numeric\" })} · ${timeLabel(firstRun.date.getHours(), firstRun.date.getMinutes())} ${firstRun.date.getHours() < 12 ? \"AM\" : \"PM\"}`\n        : null,\n      skips,\n      dstChanges,\n      freq: rule.freq,\n    });\n    // eslint-disable-next-line react-hooks/exhaustive-deps\n  }, [sentenceText, firstRun?.date?.getTime(), skips, dstChanges, rule.freq, onStateChange]);\n\n  const runFmt = (date: Date) =>\n    date.toLocaleDateString(\"en-US\", { weekday: \"short\", month: \"short\", day: \"numeric\", year: \"numeric\" });\n\n  return (\n    <MotionConfig reducedMotion=\"user\">\n      <div className=\"relative w-full max-w-[22rem] flex flex-col gap-3.5\">\n        {/* The sentence - words are the animated unit, not the string. Real\n            spaces between the spans, so selection, copy and screen readers get\n            \"Every week…\", not \"Everyweek…\". Surviving keys glide via layout;\n            new keys blur in. */}\n        <p\n          className=\"m-0 min-h-[3.2em] text-lg leading-[1.5] font-medium tracking-[-0.01em] text-foreground\"\n          aria-live=\"polite\"\n        >\n          {words.map(({ word, key }, index) => (\n            <span key={key}>\n              {index > 0 && \" \"}\n              <motion.span\n                layout={morph ? \"position\" : false}\n                initial={mountedRef.current && morph ? { opacity: 0, filter: \"blur(2px)\", y: \"0.3em\" } : false}\n                animate={{ opacity: 1, filter: \"blur(0px)\", y: 0 }}\n                transition={{ layout: { duration: 0.3, ease: EASE }, duration: 0.24, ease: EASE }}\n                className={`inline-block${inspect ? \" outline-1 outline-dashed outline-[#93c5fd] outline-offset-1 rounded-[2px]\" : \"\"}`}\n              >\n                {word}\n              </motion.span>\n            </span>\n          ))}\n        </p>\n\n        {/* ── Controls ── */}\n        <div className=\"flex flex-col gap-2\">\n          <div className=\"flex items-center flex-wrap gap-2 min-h-8\">\n            <span className={ROW_LABEL}>Repeats</span>\n            <div className=\"inline-flex gap-[2px] p-[2px] rounded-lg bg-muted\" role=\"group\" aria-label=\"Frequency\">\n              {([\"daily\", \"weekly\", \"monthly\"] as const).map((freq) => (\n                <button key={freq} type=\"button\" className={SEG_BTN} aria-pressed={rule.freq === freq} onClick={() => set({ freq })}>\n                  {freq[0].toUpperCase() + freq.slice(1)}\n                </button>\n              ))}\n            </div>\n          </div>\n\n          {rule.freq !== \"monthly\" && (\n            <div className=\"flex items-center flex-wrap gap-2 min-h-8\">\n              <span className={ROW_LABEL}>Every</span>\n              <div className=\"inline-flex items-center rounded-lg bg-background shadow-border\" role=\"group\" aria-label=\"Interval\">\n                <button type=\"button\" className={STEP_BTN} aria-label=\"Less often\" disabled={rule.interval <= 1} onClick={() => set({ interval: rule.interval - 1 })}>\n                  −\n                </button>\n                <span className=\"min-w-6 text-center text-[0.8125rem] font-medium text-foreground tabular-nums\">{rule.interval}</span>\n                <button type=\"button\" className={STEP_BTN} aria-label=\"More often\" disabled={rule.interval >= 6} onClick={() => set({ interval: rule.interval + 1 })}>\n                  +\n                </button>\n              </div>\n              <span className=\"text-xs font-medium text-muted-foreground/70\">\n                {rule.freq === \"daily\" ? (rule.interval === 1 ? \"day\" : \"days\") : rule.interval === 1 ? \"week\" : \"weeks\"}\n              </span>\n            </div>\n          )}\n\n          {rule.freq === \"weekly\" && (\n            <div className=\"flex items-center flex-wrap gap-2 min-h-8\">\n              <span className={ROW_LABEL}>On</span>\n              <div className=\"inline-flex gap-1\" role=\"group\" aria-label=\"Weekdays\">\n                {WEEKDAYS.map((name, day) => (\n                  <button\n                    key={name}\n                    type=\"button\"\n                    className=\"w-7 h-7 rounded-full bg-muted text-muted-foreground text-[0.6875rem] font-semibold cursor-pointer transition-[background-color,color,scale] duration-150 aria-pressed:bg-primary aria-pressed:text-primary-foreground active:scale-[0.96] focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring\"\n                    aria-pressed={rule.weekdays.includes(day)}\n                    aria-label={name}\n                    onClick={() => toggleWeekday(day)}\n                  >\n                    {name[0]}\n                  </button>\n                ))}\n              </div>\n            </div>\n          )}\n\n          {rule.freq === \"monthly\" && (\n            <div className=\"flex items-center flex-wrap gap-2 min-h-8\">\n              <span className={ROW_LABEL}>On</span>\n              <div className=\"inline-flex gap-[2px] p-[2px] rounded-lg bg-muted\" role=\"group\" aria-label=\"Monthly mode\">\n                <button type=\"button\" className={SEG_BTN} aria-pressed={rule.monthMode === \"date\"} onClick={() => set({ monthMode: \"date\" })}>\n                  A date\n                </button>\n                <button type=\"button\" className={SEG_BTN} aria-pressed={rule.monthMode === \"nth\"} onClick={() => set({ monthMode: \"nth\" })}>\n                  A weekday\n                </button>\n              </div>\n              {rule.monthMode === \"date\" ? (\n                <div className=\"inline-flex items-center rounded-lg bg-background shadow-border\" role=\"group\" aria-label=\"Day of month\">\n                  <button type=\"button\" className={STEP_BTN} aria-label=\"Earlier day\" disabled={rule.monthDay <= 1} onClick={() => set({ monthDay: rule.monthDay - 1 })}>\n                    −\n                  </button>\n                  <span className=\"min-w-6 text-center text-[0.8125rem] font-medium text-foreground tabular-nums\">{rule.monthDay}</span>\n                  <button type=\"button\" className={STEP_BTN} aria-label=\"Later day\" disabled={rule.monthDay >= 31} onClick={() => set({ monthDay: rule.monthDay + 1 })}>\n                    +\n                  </button>\n                </div>\n              ) : (\n                <>\n                  <select\n                    className={SELECT}\n                    value={String(rule.ordinal)}\n                    aria-label=\"Which one\"\n                    onChange={(e) => set({ ordinal: e.target.value === \"last\" ? \"last\" : Number(e.target.value) })}\n                  >\n                    {ORDINALS.map((o) => (\n                      <option key={o.label} value={String(o.value)}>\n                        {o.label}\n                      </option>\n                    ))}\n                  </select>\n                  <select className={SELECT} value={rule.weekday} aria-label=\"Weekday\" onChange={(e) => set({ weekday: Number(e.target.value) })}>\n                    {WEEKDAYS.map((name, day) => (\n                      <option key={name} value={day}>\n                        {name}\n                      </option>\n                    ))}\n                  </select>\n                </>\n              )}\n            </div>\n          )}\n\n          <div className=\"flex items-center flex-wrap gap-2 min-h-8\">\n            <span className={ROW_LABEL}>At</span>\n            <select\n              className={SELECT}\n              value={rule.hour % 12 === 0 ? 12 : rule.hour % 12}\n              aria-label=\"Hour\"\n              onChange={(e) => {\n                const h12 = Number(e.target.value) % 12;\n                set({ hour: rule.hour < 12 ? h12 : h12 + 12 });\n              }}\n            >\n              {Array.from({ length: 12 }, (_, i) => i + 1).map((h) => (\n                <option key={h} value={h}>\n                  {h}\n                </option>\n              ))}\n            </select>\n            <select className={SELECT} value={rule.minute} aria-label=\"Minutes\" onChange={(e) => set({ minute: Number(e.target.value) })}>\n              {[0, 15, 30, 45].map((m) => (\n                <option key={m} value={m}>\n                  :{String(m).padStart(2, \"0\")}\n                </option>\n              ))}\n            </select>\n            <div className=\"inline-flex gap-[2px] p-[2px] rounded-lg bg-muted\" role=\"group\" aria-label=\"AM or PM\">\n              <button type=\"button\" className={SEG_BTN} aria-pressed={rule.hour < 12} onClick={() => set({ hour: rule.hour % 12 })}>\n                AM\n              </button>\n              <button type=\"button\" className={SEG_BTN} aria-pressed={rule.hour >= 12} onClick={() => set({ hour: (rule.hour % 12) + 12 })}>\n                PM\n              </button>\n            </div>\n          </div>\n        </div>\n\n        {/* ── The proof: real occurrences, ghosts for skipped months ── */}\n        <div className=\"border-t border-border pt-2.5\">\n          <p className=\"m-0 mb-1.5 text-[0.625rem] font-semibold tracking-[0.06em] uppercase text-muted-foreground/70\">\n            Next {runs.filter((r) => r.kind === \"run\").length} runs\n          </p>\n          <ol className=\"flex flex-col gap-0.5 m-0 p-0 list-none\">\n            {runs.map((entry, index) =>\n              entry.kind === \"skip\" ? (\n                <motion.li\n                  key={entry.key}\n                  initial={{ opacity: 0, y: \"0.25rem\", filter: \"blur(1px)\" }}\n                  animate={{ opacity: 1, y: 0, filter: \"blur(0px)\" }}\n                  transition={{ duration: 0.24, ease: EASE, delay: index * 0.03 }}\n                  className=\"flex items-center justify-between gap-3 px-1.5 py-[0.3125rem] rounded-lg text-xs text-muted-foreground/70 border border-dashed border-foreground/10\"\n                >\n                  <span>{entry.label}</span>\n                  <span className=\"text-[0.625rem] font-semibold tracking-[0.04em] uppercase\">skipped</span>\n                </motion.li>\n              ) : (\n                <motion.li\n                  key={entry.date.getTime()}\n                  initial={{ opacity: 0, y: \"0.25rem\", filter: \"blur(1px)\" }}\n                  animate={{ opacity: 1, y: 0, filter: \"blur(0px)\" }}\n                  transition={{ duration: 0.24, ease: EASE, delay: index * 0.03 }}\n                  className=\"flex items-center justify-between gap-3 px-1.5 py-[0.3125rem] rounded-lg text-[0.8125rem] text-foreground\"\n                >\n                  <span className=\"min-w-0 overflow-hidden text-ellipsis whitespace-nowrap\">\n                    {runFmt(entry.date)}\n                    {entry.clamped && (\n                      <span className=\"ml-1.5 text-[0.625rem] font-semibold tracking-[0.04em] uppercase text-[#d97706]\">clamped</span>\n                    )}\n                  </span>\n                  <span className=\"inline-flex items-baseline gap-1.5 flex-none text-muted-foreground tabular-nums\">\n                    {timeLabel(entry.date.getHours(), entry.date.getMinutes())} {entry.date.getHours() < 12 ? \"AM\" : \"PM\"}\n                    <span\n                      className={\n                        offsetLabel(entry.date) !== baseOffset\n                          ? \"text-[0.6875rem] text-[#d97706] font-semibold\"\n                          : \"text-[0.6875rem] text-muted-foreground/70\"\n                      }\n                    >\n                      {offsetLabel(entry.date)}\n                    </span>\n                  </span>\n                </motion.li>\n              ),\n            )}\n          </ol>\n        </div>\n\n        {/* Blueprint annotations (blue = the word glide, red = the calendar math). */}\n        {inspect && (\n          <>\n            <span className=\"absolute bottom-[calc(100%+0.4rem)] left-0 z-[6] whitespace-nowrap rounded-[0.25rem] border border-[#bfdbfe] bg-white px-[0.3125rem] py-[0.0625rem] text-[0.625rem] font-medium leading-normal tracking-[0.01em] text-[#2563eb] shadow-[0_1px_2px_rgba(0,0,0,0.08)] pointer-events-none tabular-nums\">\n              words keyed text+occurrence · layout glide 300ms\n            </span>\n            <span className=\"absolute top-[calc(100%+0.4rem)] left-0 z-[6] whitespace-nowrap rounded-[0.25rem] border border-[#fecaca] bg-white px-[0.3125rem] py-[0.0625rem] text-[0.625rem] font-medium leading-normal tracking-[0.01em] text-[#dc2626] shadow-[0_1px_2px_rgba(0,0,0,0.08)] pointer-events-none tabular-nums\">\n              occurrences computed, never added · offsets straight from Date\n            </span>\n          </>\n        )}\n      </div>\n    </MotionConfig>\n  );\n}\n"
    }
  ]
}
