{
  "$schema": "https://ui.shadcn.com/schema/registry.json",
  "name": "quill",
  "homepage": "https://www.quilldesignsystem.com",
  "items": [
    {
      "name": "quill",
      "type": "registry:base",
      "title": "Quill Design System",
      "description": "Warm neutral grounds, moss accents, Fraunces display type, and ink-toned type. A low-contrast editorial theme for digital products.",
      "author": "Craftwell (https://www.quilldesignsystem.com)",
      "files": [
        {
          "path": "registry/themes/quill.css",
          "type": "registry:base",
          "target": "app/quill-theme.css"
        }
      ],
      "cssVars": {
        "theme": {
          "font-sans": "\"Raleway\", -apple-system, BlinkMacSystemFont, sans-serif",
          "font-display": "\"Fraunces\", Georgia, serif",
          "font-heading": "\"Fraunces\", Georgia, serif",
          "font-mono": "ui-monospace, \"SF Mono\", Menlo, monospace",
          "font-ui": "\"Inter\", -apple-system, BlinkMacSystemFont, sans-serif",
          "font-data": "\"JetBrains Mono\", \"SF Mono\", ui-monospace, monospace",
          "color-background": "var(--background)",
          "color-foreground": "var(--foreground)",
          "color-card": "var(--card)",
          "color-card-foreground": "var(--card-foreground)",
          "color-popover": "var(--popover)",
          "color-popover-foreground": "var(--popover-foreground)",
          "color-primary": "var(--primary)",
          "color-primary-foreground": "var(--primary-foreground)",
          "color-secondary": "var(--secondary)",
          "color-secondary-foreground": "var(--secondary-foreground)",
          "color-muted": "var(--muted)",
          "color-muted-foreground": "var(--muted-foreground)",
          "color-accent": "var(--accent)",
          "color-accent-foreground": "var(--accent-foreground)",
          "color-destructive": "var(--destructive)",
          "color-border": "var(--border)",
          "color-input": "var(--input)",
          "color-ring": "var(--ring)",
          "color-chart-1": "var(--chart-1)",
          "color-chart-2": "var(--chart-2)",
          "color-chart-3": "var(--chart-3)",
          "color-chart-4": "var(--chart-4)",
          "color-chart-5": "var(--chart-5)",
          "color-sidebar": "var(--sidebar)",
          "color-sidebar-foreground": "var(--sidebar-foreground)",
          "color-sidebar-primary": "var(--sidebar-primary)",
          "color-sidebar-primary-foreground": "var(--sidebar-primary-foreground)",
          "color-sidebar-accent": "var(--sidebar-accent)",
          "color-sidebar-accent-foreground": "var(--sidebar-accent-foreground)",
          "color-sidebar-border": "var(--sidebar-border)",
          "color-sidebar-ring": "var(--sidebar-ring)",
          "color-link": "var(--link)",
          "color-success": "var(--success)",
          "color-warning": "var(--warning)",
          "color-info": "var(--info)",
          "color-working": "var(--working)",
          "color-queued": "var(--queued)",
          "color-paper": "var(--paper)",
          "color-paper-warm": "var(--paper-warm)",
          "color-paper-deep": "var(--paper-deep)",
          "color-ink": "var(--ink)",
          "color-ink-soft": "var(--ink-soft)",
          "color-ink-muted": "var(--ink-muted)",
          "color-terracotta": "var(--terracotta)",
          "color-terracotta-deep": "var(--terracotta-deep)",
          "color-moss": "var(--moss)",
          "color-moss-deep": "var(--moss-deep)",
          "color-indigo": "var(--indigo)",
          "color-indigo-deep": "var(--indigo-deep)",
          "color-gold": "var(--gold)",
          "color-gold-deep": "var(--gold-deep)",
          "color-gold-text": "var(--gold-text)",
          "color-teal": "var(--teal)",
          "color-teal-deep": "var(--teal-deep)",
          "color-accent-pigment-text": "var(--accent-pigment-text)",
          "radius-xs": "0.125rem",
          "radius-sm": "0.25rem",
          "radius-md": "0.375rem",
          "radius-lg": "0.5rem",
          "radius-xl": "1rem",
          "radius-2xl": "1.5rem",
          "radius-3xl": "2rem",
          "radius-4xl": "2.5rem",
          "text-2xs": "0.7rem",
          "text-xs": "0.75rem",
          "text-xs--line-height": "calc(1 / 0.75)",
          "text-sm": "0.85rem",
          "text-sm--line-height": "calc(1.25 / 0.875)",
          "text-base": "0.95rem",
          "text-base--line-height": "calc(1.5 / 1)",
          "text-lg": "1.15rem",
          "text-lg--line-height": "calc(1.75 / 1.125)",
          "text-xl": "1.5rem",
          "text-xl--line-height": "calc(1.75 / 1.25)",
          "text-2xl": "2rem",
          "text-2xl--line-height": "calc(2 / 1.5)",
          "text-3xl": "3rem",
          "text-3xl--line-height": "calc(2.25 / 1.875)",
          "text-4xl": "4rem",
          "text-4xl--line-height": "calc(2.5 / 2.25)",
          "text-5xl": "5.5rem",
          "text-5xl--line-height": "1",
          "leading-display": "1.05",
          "leading-heading": "1.2",
          "leading-ui": "1.5",
          "leading-reading": "1.7",
          "tracking-display": "-0.03em",
          "tracking-label": "0.1em",
          "tracking-eyebrow": "0.15em",
          "shadow-2xs": "var(--shadow-xs)",
          "shadow-xs": "var(--shadow-xs)",
          "shadow-sm": "var(--shadow-sm)",
          "shadow-md": "var(--shadow)",
          "shadow-lg": "var(--shadow-lg)",
          "shadow-xl": "var(--shadow-pop)",
          "shadow-2xl": "var(--shadow-pop)"
        },
        "light": {
          "radius": "0.5rem",
          "background": "var(--paper)",
          "foreground": "var(--ink)",
          "card": "var(--paper-warm)",
          "card-foreground": "var(--ink)",
          "popover": "var(--paper-warm)",
          "popover-foreground": "var(--ink)",
          "primary": "var(--ink)",
          "primary-foreground": "var(--paper)",
          "secondary": "var(--paper-deep)",
          "secondary-foreground": "var(--ink)",
          "muted": "var(--paper-deep)",
          "muted-foreground": "var(--ink-muted)",
          "accent": "var(--paper-deep)",
          "accent-foreground": "var(--ink)",
          "destructive": "var(--terracotta-deep)",
          "border": "var(--line-soft)",
          "input": "var(--line-control)",
          "ring": "var(--accent-pigment-text)",
          "chart-1": "var(--chart-series-1)",
          "chart-2": "var(--chart-series-2)",
          "chart-3": "var(--chart-series-3)",
          "chart-4": "var(--chart-series-4)",
          "chart-5": "var(--chart-series-5)",
          "sidebar": "var(--paper-warm)",
          "sidebar-foreground": "var(--ink)",
          "sidebar-primary": "var(--ink)",
          "sidebar-primary-foreground": "var(--paper)",
          "sidebar-accent": "var(--paper-deep)",
          "sidebar-accent-foreground": "var(--ink)",
          "sidebar-border": "var(--line-faint)",
          "sidebar-ring": "var(--accent-pigment-text)"
        }
      },
      "css": {
        "@custom-variant dark (&:is(.dark *, [data-theme=\"dark\"] *, [data-theme=\"classic-dark\"] *, [data-theme=\"intelligent\"] *))": {},
        ":root": {
          "--paper": "#F5EDDD",
          "--paper-warm": "#EFE4CE",
          "--paper-deep": "#E8DCC0",
          "--ink": "#2A2622",
          "--ink-soft": "#5C524A",
          "--ink-muted": "#675F58",
          "--terracotta": "#C4684B",
          "--terracotta-deep": "#8A4530",
          "--moss": "#7A8C5C",
          "--moss-deep": "#4C5936",
          "--indigo": "#5B6B8A",
          "--indigo-deep": "#44516D",
          "--gold": "#B89968",
          "--gold-deep": "#9A7D4E",
          "--gold-text": "#68522D",
          "--teal": "#4E938B",
          "--teal-deep": "#2F6B64",
          "--chart-series-1": "#732510",
          "--chart-series-2": "#345799",
          "--chart-series-3": "#9D7614",
          "--chart-series-4": "#79376C",
          "--chart-series-5": "#4F6D1A",
          "--chart-seq-1": "#C7D8B5",
          "--chart-seq-2": "#A1B787",
          "--chart-seq-3": "#7C975A",
          "--chart-seq-4": "#567428",
          "--chart-seq-5": "#375101",
          "--chart-div-1": "#903F2B",
          "--chart-div-2": "#BB8273",
          "--chart-div-3": "#CFC9C5",
          "--chart-div-4": "#7993C1",
          "--chart-div-5": "#36589B",
          "--line-faint": "rgba(42, 38, 34, 0.08)",
          "--line-soft": "rgba(42, 38, 34, 0.12)",
          "--line": "rgba(42, 38, 34, 0.15)",
          "--line-strong": "rgba(42, 38, 34, 0.20)",
          "--line-control": "#8A7F6E",
          "--ai-from": "#C49544",
          "--ai-via": "#DE501B",
          "--ai-to": "#536A99",
          "--ai-text-from": "#714F07",
          "--ai-text-via": "#9D3209",
          "--ai-text-to": "#3D507A",
          "--shadow-xs": "0 1px 2px -1px rgba(42, 38, 34, 0.12), 0 0 0 1px rgba(42, 38, 34, 0.05)",
          "--shadow-sm": "0 2px 4px -1px rgba(42, 38, 34, 0.14), 0 1px 2px -1px rgba(42, 38, 34, 0.08)",
          "--shadow": "0 4px 8px -2px rgba(42, 38, 34, 0.16), 0 2px 4px -2px rgba(42, 38, 34, 0.10)",
          "--shadow-lg": "0 12px 20px -4px rgba(42, 38, 34, 0.18), 0 4px 8px -4px rgba(42, 38, 34, 0.10)",
          "--shadow-pop": "0 20px 32px -6px rgba(42, 38, 34, 0.22), 0 8px 12px -6px rgba(42, 38, 34, 0.12)",
          "--ease-out": "cubic-bezier(0.4, 0, 0.2, 1)",
          "--ease-soft": "cubic-bezier(0.22, 1, 0.36, 1)",
          "--dur-fast": "0.2s",
          "--dur": "0.3s",
          "--dur-slow": "0.5s",
          "--lift": "translateY(-4px)",
          "--lift-sm": "translateY(-2px)",
          "--fraunces-display": "\"opsz\" 144, \"SOFT\" 50, \"WONK\" 0",
          "--fraunces-accent": "\"opsz\" 144, \"SOFT\" 100, \"WONK\" 1",
          "--fraunces-text": "\"SOFT\" 50, \"WONK\" 0",
          "--fraunces-caption": "\"opsz\" 14, \"SOFT\" 100, \"WONK\" 0",
          "--accent-pigment": "var(--moss)",
          "--accent-pigment-text": "var(--moss-deep)",
          "--text-accent-color": "var(--accent-pigment-text)",
          "--link": "var(--accent-pigment-text)",
          "--success": "var(--moss-deep)",
          "--warning": "var(--gold-text)",
          "--info": "var(--indigo-deep)",
          "--working": "var(--teal-deep)",
          "--queued": "var(--ink-muted)",
          "--space-1": "0.25rem",
          "--space-2": "0.5rem",
          "--space-3": "0.75rem",
          "--space-4": "1rem",
          "--space-5": "1.25rem",
          "--space-6": "1.5rem",
          "--space-7": "1.75rem",
          "--space-8": "2rem",
          "--space-9": "2.25rem",
          "--space-10": "2.5rem",
          "--space-12": "3rem",
          "--space-16": "4rem",
          "--space-20": "5rem",
          "--space-24": "6rem",
          "--space-0_5": "0.125rem",
          "--space-1_5": "0.375rem",
          "--space-2_5": "0.625rem",
          "--border-width-0": "0px",
          "--border-width-1": "1px",
          "--border-width-2": "2px",
          "--border-width-3": "3px",
          "--border-width-4": "4px",
          "--leading-display": "1.05",
          "--leading-heading": "1.2",
          "--leading-ui": "1.5",
          "--leading-reading": "1.7",
          "--tracking-display": "-0.03em",
          "--tracking-label": "0.1em",
          "--tracking-eyebrow": "0.15em",
          "--dk-paper": "#20180E",
          "--cl-paper": "#FFFFFF",
          "--cd-paper": "#000000",
          "--int-paper": "#0E100D",
          "--dk-paper-warm": "#2A2014",
          "--cl-paper-warm": "#F7F7F7",
          "--cd-paper-warm": "#111111",
          "--int-paper-warm": "#171A14",
          "--dk-paper-deep": "#352A1A",
          "--cl-paper-deep": "#EFEFEF",
          "--cd-paper-deep": "#1C1C1C",
          "--int-paper-deep": "#1D2117",
          "--dk-ink": "#F1E7D3",
          "--cl-ink": "#171717",
          "--cd-ink": "#F5F5F5",
          "--int-ink": "#E9E5D6",
          "--dk-ink-soft": "#C8B9A0",
          "--cl-ink-soft": "#454545",
          "--cd-ink-soft": "#C9C9C9",
          "--int-ink-soft": "#A9A791",
          "--dk-ink-muted": "#AFA08A",
          "--cl-ink-muted": "#5E5E5E",
          "--cd-ink-muted": "#A0A0A0",
          "--int-ink-muted": "#A09F8C",
          "--dk-terracotta": "#DB8568",
          "--cl-terracotta": "#DE501B",
          "--cd-terracotta": "#F57345",
          "--int-terracotta": "#C96F4C",
          "--dk-terracotta-deep": "#E89A80",
          "--cl-terracotta-deep": "#9D3209",
          "--cd-terracotta-deep": "#FE8D67",
          "--int-terracotta-deep": "#E08A66",
          "--dk-moss": "#A2B57E",
          "--cl-moss": "#758F43",
          "--cd-moss": "#9DB962",
          "--int-moss": "#7FAE5A",
          "--dk-moss-deep": "#B6C896",
          "--cl-moss-deep": "#516526",
          "--cd-moss-deep": "#B1CC7E",
          "--int-moss-deep": "#9BC47D",
          "--dk-indigo": "#92A2C2",
          "--cl-indigo": "#536A99",
          "--cd-indigo": "#8AA2D2",
          "--int-indigo": "#8B8FD8",
          "--dk-indigo-deep": "#AAB8D4",
          "--cl-indigo-deep": "#3D507A",
          "--cd-indigo-deep": "#A3B8E2",
          "--int-indigo-deep": "#A6AAE3",
          "--dk-gold": "#D6BA86",
          "--cl-gold": "#C49544",
          "--cd-gold": "#E2B764",
          "--int-gold": "#E0A340",
          "--dk-gold-deep": "#E2CA9E",
          "--cl-gold-deep": "#A57928",
          "--cd-gold-deep": "#ECC883",
          "--int-gold-deep": "#E8BC72",
          "--dk-gold-text": "#E2CA9E",
          "--cl-gold-text": "#7C5814",
          "--cd-gold-text": "#ECC883",
          "--int-gold-text": "#E8BC72",
          "--dk-teal": "#4AA9A0",
          "--cl-teal": "#178F84",
          "--cd-teal": "#3DBDB1",
          "--int-teal": "#4AA9A0",
          "--dk-teal-deep": "#63BCB2",
          "--cl-teal-deep": "#0E6B61",
          "--cd-teal-deep": "#5FD3C7",
          "--int-teal-deep": "#63BCB2",
          "--dk-chart-series-1": "#CA725C",
          "--cl-chart-series-1": "#7C1C01",
          "--cd-chart-series-1": "#C75E45",
          "--int-chart-series-1": "#C66F59",
          "--dk-chart-series-2": "#5175BA",
          "--cl-chart-series-2": "#194AAC",
          "--cd-chart-series-2": "#3966B9",
          "--int-chart-series-2": "#466AAE",
          "--dk-chart-series-3": "#A17A1B",
          "--cl-chart-series-3": "#AD8214",
          "--cd-chart-series-3": "#BA8B01",
          "--int-chart-series-3": "#BF973F",
          "--dk-chart-series-4": "#CC83BB",
          "--cl-chart-series-4": "#8D297E",
          "--cd-chart-series-4": "#F086DA",
          "--int-chart-series-4": "#EEA3DD",
          "--dk-chart-series-5": "#9ABE6D",
          "--cl-chart-series-5": "#577A16",
          "--cd-chart-series-5": "#8CB258",
          "--int-chart-series-5": "#A0C473",
          "--dk-chart-seq-1": "#303D20",
          "--cl-chart-seq-1": "#CCE0B6",
          "--cd-chart-seq-1": "#2A3815",
          "--int-chart-seq-1": "#303D20",
          "--dk-chart-seq-2": "#475A2E",
          "--cl-chart-seq-2": "#A0BC7E",
          "--cd-chart-seq-2": "#41591D",
          "--int-chart-seq-2": "#475A2E",
          "--dk-chart-seq-3": "#5F793D",
          "--cl-chart-seq-3": "#779A45",
          "--cd-chart-seq-3": "#5A7B25",
          "--int-chart-seq-3": "#5F793D",
          "--dk-chart-seq-4": "#79994D",
          "--cl-chart-seq-4": "#527602",
          "--cd-chart-seq-4": "#749F2B",
          "--int-chart-seq-4": "#79994D",
          "--dk-chart-seq-5": "#97B86B",
          "--cl-chart-seq-5": "#375101",
          "--cd-chart-seq-5": "#95C352",
          "--int-chart-seq-5": "#97B86B",
          "--dk-chart-div-1": "#DC836D",
          "--cl-chart-div-1": "#A22801",
          "--cd-chart-div-1": "#FA7959",
          "--int-chart-div-1": "#DC836D",
          "--dk-chart-div-2": "#986153",
          "--cl-chart-div-2": "#C77B68",
          "--cd-chart-div-2": "#A75D4B",
          "--int-chart-div-2": "#986153",
          "--dk-chart-div-3": "#403C39",
          "--cl-chart-div-3": "#D4D0CD",
          "--cd-chart-div-3": "#3A3735",
          "--int-chart-div-3": "#403C39",
          "--dk-chart-div-4": "#59729E",
          "--cl-chart-div-4": "#7092D0",
          "--cd-chart-div-4": "#5474AF",
          "--int-chart-div-4": "#59729E",
          "--dk-chart-div-5": "#779EE6",
          "--cl-chart-div-5": "#2253B5",
          "--cd-chart-div-5": "#71A3FF",
          "--int-chart-div-5": "#779EE6",
          "--dk-line-faint": "rgba(241, 231, 211, 0.07)",
          "--cl-line-faint": "rgba(0, 0, 0, 0.07)",
          "--cd-line-faint": "rgba(255, 255, 255, 0.08)",
          "--int-line-faint": "rgba(233, 229, 214, 0.07)",
          "--dk-line-soft": "rgba(241, 231, 211, 0.11)",
          "--cl-line-soft": "rgba(0, 0, 0, 0.11)",
          "--cd-line-soft": "rgba(255, 255, 255, 0.12)",
          "--int-line-soft": "rgba(233, 229, 214, 0.11)",
          "--dk-line": "rgba(241, 231, 211, 0.15)",
          "--cl-line": "rgba(0, 0, 0, 0.14)",
          "--cd-line": "rgba(255, 255, 255, 0.16)",
          "--int-line": "rgba(233, 229, 214, 0.15)",
          "--dk-line-strong": "rgba(241, 231, 211, 0.22)",
          "--cl-line-strong": "rgba(0, 0, 0, 0.20)",
          "--cd-line-strong": "rgba(255, 255, 255, 0.24)",
          "--int-line-strong": "rgba(233, 229, 214, 0.22)",
          "--dk-line-control": "#746B5D",
          "--cl-line-control": "#858585",
          "--cd-line-control": "#757575",
          "--int-line-control": "#767663",
          "--dk-ai-from": "#E2B764",
          "--cl-ai-from": "#C49544",
          "--cd-ai-from": "#E2B764",
          "--int-ai-from": "#E0A340",
          "--dk-ai-via": "#F57345",
          "--cl-ai-via": "#DE501B",
          "--cd-ai-via": "#F57345",
          "--int-ai-via": "#C96F4C",
          "--dk-ai-to": "#8AA2D2",
          "--cl-ai-to": "#536A99",
          "--cd-ai-to": "#8AA2D2",
          "--int-ai-to": "#8B8FD8",
          "--dk-ai-text-from": "#ECC883",
          "--cl-ai-text-from": "#7C5814",
          "--cd-ai-text-from": "#ECC883",
          "--int-ai-text-from": "#E8BC72",
          "--dk-ai-text-via": "#FF8B64",
          "--cl-ai-text-via": "#9D3209",
          "--cd-ai-text-via": "#FE8D67",
          "--int-ai-text-via": "#E08A66",
          "--dk-ai-text-to": "#A3B8E2",
          "--cl-ai-text-to": "#3D507A",
          "--cd-ai-text-to": "#A3B8E2",
          "--int-ai-text-to": "#A6AAE3",
          "--dk-shadow-xs": "0 1px 2px -1px rgba(8, 5, 3, 0.40), 0 0 0 1px rgba(8, 5, 3, 0.18)",
          "--cl-shadow-xs": "0 1px 2px -1px rgba(0, 0, 0, 0.12), 0 0 0 1px rgba(0, 0, 0, 0.05)",
          "--cd-shadow-xs": "0 1px 2px -1px rgba(0, 0, 0, 0.50), 0 0 0 1px rgba(255, 255, 255, 0.06)",
          "--int-shadow-xs": "0 1px 2px -1px rgba(8, 5, 3, 0.40), 0 0 0 1px rgba(8, 5, 3, 0.18)",
          "--dk-shadow-sm": "0 2px 4px -1px rgba(8, 5, 3, 0.48), 0 1px 2px -1px rgba(8, 5, 3, 0.30)",
          "--cl-shadow-sm": "0 2px 4px -1px rgba(0, 0, 0, 0.14), 0 1px 2px -1px rgba(0, 0, 0, 0.08)",
          "--cd-shadow-sm": "0 2px 4px -1px rgba(0, 0, 0, 0.55), 0 1px 2px -1px rgba(0, 0, 0, 0.35)",
          "--int-shadow-sm": "0 2px 4px -1px rgba(8, 5, 3, 0.48), 0 1px 2px -1px rgba(8, 5, 3, 0.30)",
          "--dk-shadow": "0 4px 8px -2px rgba(8, 5, 3, 0.54), 0 2px 4px -2px rgba(8, 5, 3, 0.36)",
          "--cl-shadow": "0 4px 8px -2px rgba(0, 0, 0, 0.16), 0 2px 4px -2px rgba(0, 0, 0, 0.10)",
          "--cd-shadow": "0 4px 8px -2px rgba(0, 0, 0, 0.60), 0 2px 4px -2px rgba(0, 0, 0, 0.40)",
          "--int-shadow": "0 4px 8px -2px rgba(8, 5, 3, 0.54), 0 2px 4px -2px rgba(8, 5, 3, 0.36)",
          "--dk-shadow-lg": "0 12px 20px -4px rgba(8, 5, 3, 0.62), 0 4px 8px -4px rgba(8, 5, 3, 0.40)",
          "--cl-shadow-lg": "0 12px 20px -4px rgba(0, 0, 0, 0.18), 0 4px 8px -4px rgba(0, 0, 0, 0.10)",
          "--cd-shadow-lg": "0 12px 20px -4px rgba(0, 0, 0, 0.68), 0 4px 8px -4px rgba(0, 0, 0, 0.44)",
          "--int-shadow-lg": "0 12px 20px -4px rgba(8, 5, 3, 0.62), 0 4px 8px -4px rgba(8, 5, 3, 0.40)",
          "--dk-shadow-pop": "0 20px 32px -6px rgba(8, 5, 3, 0.72), 0 8px 12px -6px rgba(8, 5, 3, 0.48)",
          "--cl-shadow-pop": "0 20px 32px -6px rgba(0, 0, 0, 0.22), 0 8px 12px -6px rgba(0, 0, 0, 0.12)",
          "--cd-shadow-pop": "0 20px 32px -6px rgba(0, 0, 0, 0.78), 0 8px 12px -6px rgba(0, 0, 0, 0.52)",
          "--int-shadow-pop": "0 20px 32px -6px rgba(8, 5, 3, 0.72), 0 8px 12px -6px rgba(8, 5, 3, 0.48)"
        },
        "[data-theme=\"dark\"]": {
          "--paper": "var(--dk-paper)",
          "--paper-warm": "var(--dk-paper-warm)",
          "--paper-deep": "var(--dk-paper-deep)",
          "--ink": "var(--dk-ink)",
          "--ink-soft": "var(--dk-ink-soft)",
          "--ink-muted": "var(--dk-ink-muted)",
          "--terracotta": "var(--dk-terracotta)",
          "--terracotta-deep": "var(--dk-terracotta-deep)",
          "--moss": "var(--dk-moss)",
          "--moss-deep": "var(--dk-moss-deep)",
          "--indigo": "var(--dk-indigo)",
          "--indigo-deep": "var(--dk-indigo-deep)",
          "--gold": "var(--dk-gold)",
          "--gold-deep": "var(--dk-gold-deep)",
          "--gold-text": "var(--dk-gold-text)",
          "--teal": "var(--dk-teal)",
          "--teal-deep": "var(--dk-teal-deep)",
          "--chart-series-1": "var(--dk-chart-series-1)",
          "--chart-series-2": "var(--dk-chart-series-2)",
          "--chart-series-3": "var(--dk-chart-series-3)",
          "--chart-series-4": "var(--dk-chart-series-4)",
          "--chart-series-5": "var(--dk-chart-series-5)",
          "--chart-seq-1": "var(--dk-chart-seq-1)",
          "--chart-seq-2": "var(--dk-chart-seq-2)",
          "--chart-seq-3": "var(--dk-chart-seq-3)",
          "--chart-seq-4": "var(--dk-chart-seq-4)",
          "--chart-seq-5": "var(--dk-chart-seq-5)",
          "--chart-div-1": "var(--dk-chart-div-1)",
          "--chart-div-2": "var(--dk-chart-div-2)",
          "--chart-div-3": "var(--dk-chart-div-3)",
          "--chart-div-4": "var(--dk-chart-div-4)",
          "--chart-div-5": "var(--dk-chart-div-5)",
          "--line-faint": "var(--dk-line-faint)",
          "--line-soft": "var(--dk-line-soft)",
          "--line": "var(--dk-line)",
          "--line-strong": "var(--dk-line-strong)",
          "--line-control": "var(--dk-line-control)",
          "--ai-from": "var(--dk-ai-from)",
          "--ai-via": "var(--dk-ai-via)",
          "--ai-to": "var(--dk-ai-to)",
          "--ai-text-from": "var(--dk-ai-text-from)",
          "--ai-text-via": "var(--dk-ai-text-via)",
          "--ai-text-to": "var(--dk-ai-text-to)",
          "--shadow-xs": "var(--dk-shadow-xs)",
          "--shadow-sm": "var(--dk-shadow-sm)",
          "--shadow": "var(--dk-shadow)",
          "--shadow-lg": "var(--dk-shadow-lg)",
          "--shadow-pop": "var(--dk-shadow-pop)",
          "--accent-pigment": "var(--moss)",
          "--accent-pigment-text": "var(--moss-deep)",
          "--text-accent-color": "var(--accent-pigment-text)",
          "--link": "var(--accent-pigment-text)",
          "--success": "var(--moss-deep)",
          "--warning": "var(--gold-text)",
          "--info": "var(--indigo-deep)",
          "--working": "var(--teal-deep)",
          "--queued": "var(--ink-muted)",
          "--background": "var(--paper)",
          "--foreground": "var(--ink)",
          "--card": "var(--paper-warm)",
          "--card-foreground": "var(--ink)",
          "--popover": "var(--paper-warm)",
          "--popover-foreground": "var(--ink)",
          "--primary": "var(--ink)",
          "--primary-foreground": "var(--paper)",
          "--secondary": "var(--paper-deep)",
          "--secondary-foreground": "var(--ink)",
          "--muted": "var(--paper-deep)",
          "--muted-foreground": "var(--ink-muted)",
          "--accent": "var(--paper-deep)",
          "--accent-foreground": "var(--ink)",
          "--destructive": "var(--terracotta-deep)",
          "--border": "var(--line-soft)",
          "--input": "var(--line-control)",
          "--ring": "var(--accent-pigment-text)",
          "--chart-1": "var(--chart-series-1)",
          "--chart-2": "var(--chart-series-2)",
          "--chart-3": "var(--chart-series-3)",
          "--chart-4": "var(--chart-series-4)",
          "--chart-5": "var(--chart-series-5)",
          "--sidebar": "var(--paper-warm)",
          "--sidebar-foreground": "var(--ink)",
          "--sidebar-primary": "var(--ink)",
          "--sidebar-primary-foreground": "var(--paper)",
          "--sidebar-accent": "var(--paper-deep)",
          "--sidebar-accent-foreground": "var(--ink)",
          "--sidebar-border": "var(--line-faint)",
          "--sidebar-ring": "var(--accent-pigment-text)"
        },
        "[data-theme=\"classic-light\"]": {
          "--paper": "var(--cl-paper)",
          "--paper-warm": "var(--cl-paper-warm)",
          "--paper-deep": "var(--cl-paper-deep)",
          "--ink": "var(--cl-ink)",
          "--ink-soft": "var(--cl-ink-soft)",
          "--ink-muted": "var(--cl-ink-muted)",
          "--terracotta": "var(--cl-terracotta)",
          "--terracotta-deep": "var(--cl-terracotta-deep)",
          "--moss": "var(--cl-moss)",
          "--moss-deep": "var(--cl-moss-deep)",
          "--indigo": "var(--cl-indigo)",
          "--indigo-deep": "var(--cl-indigo-deep)",
          "--gold": "var(--cl-gold)",
          "--gold-deep": "var(--cl-gold-deep)",
          "--gold-text": "var(--cl-gold-text)",
          "--teal": "var(--cl-teal)",
          "--teal-deep": "var(--cl-teal-deep)",
          "--chart-series-1": "var(--cl-chart-series-1)",
          "--chart-series-2": "var(--cl-chart-series-2)",
          "--chart-series-3": "var(--cl-chart-series-3)",
          "--chart-series-4": "var(--cl-chart-series-4)",
          "--chart-series-5": "var(--cl-chart-series-5)",
          "--chart-seq-1": "var(--cl-chart-seq-1)",
          "--chart-seq-2": "var(--cl-chart-seq-2)",
          "--chart-seq-3": "var(--cl-chart-seq-3)",
          "--chart-seq-4": "var(--cl-chart-seq-4)",
          "--chart-seq-5": "var(--cl-chart-seq-5)",
          "--chart-div-1": "var(--cl-chart-div-1)",
          "--chart-div-2": "var(--cl-chart-div-2)",
          "--chart-div-3": "var(--cl-chart-div-3)",
          "--chart-div-4": "var(--cl-chart-div-4)",
          "--chart-div-5": "var(--cl-chart-div-5)",
          "--line-faint": "var(--cl-line-faint)",
          "--line-soft": "var(--cl-line-soft)",
          "--line": "var(--cl-line)",
          "--line-strong": "var(--cl-line-strong)",
          "--line-control": "var(--cl-line-control)",
          "--ai-from": "var(--cl-ai-from)",
          "--ai-via": "var(--cl-ai-via)",
          "--ai-to": "var(--cl-ai-to)",
          "--ai-text-from": "var(--cl-ai-text-from)",
          "--ai-text-via": "var(--cl-ai-text-via)",
          "--ai-text-to": "var(--cl-ai-text-to)",
          "--shadow-xs": "var(--cl-shadow-xs)",
          "--shadow-sm": "var(--cl-shadow-sm)",
          "--shadow": "var(--cl-shadow)",
          "--shadow-lg": "var(--cl-shadow-lg)",
          "--shadow-pop": "var(--cl-shadow-pop)",
          "--accent-pigment": "var(--moss)",
          "--accent-pigment-text": "var(--moss-deep)",
          "--text-accent-color": "var(--accent-pigment-text)",
          "--link": "var(--accent-pigment-text)",
          "--success": "var(--moss-deep)",
          "--warning": "var(--gold-text)",
          "--info": "var(--indigo-deep)",
          "--working": "var(--teal-deep)",
          "--queued": "var(--ink-muted)",
          "--background": "var(--paper)",
          "--foreground": "var(--ink)",
          "--card": "var(--paper-warm)",
          "--card-foreground": "var(--ink)",
          "--popover": "var(--paper-warm)",
          "--popover-foreground": "var(--ink)",
          "--primary": "var(--ink)",
          "--primary-foreground": "var(--paper)",
          "--secondary": "var(--paper-deep)",
          "--secondary-foreground": "var(--ink)",
          "--muted": "var(--paper-deep)",
          "--muted-foreground": "var(--ink-muted)",
          "--accent": "var(--paper-deep)",
          "--accent-foreground": "var(--ink)",
          "--destructive": "var(--terracotta-deep)",
          "--border": "var(--line-soft)",
          "--input": "var(--line-control)",
          "--ring": "var(--accent-pigment-text)",
          "--chart-1": "var(--chart-series-1)",
          "--chart-2": "var(--chart-series-2)",
          "--chart-3": "var(--chart-series-3)",
          "--chart-4": "var(--chart-series-4)",
          "--chart-5": "var(--chart-series-5)",
          "--sidebar": "var(--paper-warm)",
          "--sidebar-foreground": "var(--ink)",
          "--sidebar-primary": "var(--ink)",
          "--sidebar-primary-foreground": "var(--paper)",
          "--sidebar-accent": "var(--paper-deep)",
          "--sidebar-accent-foreground": "var(--ink)",
          "--sidebar-border": "var(--line-faint)",
          "--sidebar-ring": "var(--accent-pigment-text)"
        },
        "[data-theme=\"classic-dark\"]": {
          "--paper": "var(--cd-paper)",
          "--paper-warm": "var(--cd-paper-warm)",
          "--paper-deep": "var(--cd-paper-deep)",
          "--ink": "var(--cd-ink)",
          "--ink-soft": "var(--cd-ink-soft)",
          "--ink-muted": "var(--cd-ink-muted)",
          "--terracotta": "var(--cd-terracotta)",
          "--terracotta-deep": "var(--cd-terracotta-deep)",
          "--moss": "var(--cd-moss)",
          "--moss-deep": "var(--cd-moss-deep)",
          "--indigo": "var(--cd-indigo)",
          "--indigo-deep": "var(--cd-indigo-deep)",
          "--gold": "var(--cd-gold)",
          "--gold-deep": "var(--cd-gold-deep)",
          "--gold-text": "var(--cd-gold-text)",
          "--teal": "var(--cd-teal)",
          "--teal-deep": "var(--cd-teal-deep)",
          "--chart-series-1": "var(--cd-chart-series-1)",
          "--chart-series-2": "var(--cd-chart-series-2)",
          "--chart-series-3": "var(--cd-chart-series-3)",
          "--chart-series-4": "var(--cd-chart-series-4)",
          "--chart-series-5": "var(--cd-chart-series-5)",
          "--chart-seq-1": "var(--cd-chart-seq-1)",
          "--chart-seq-2": "var(--cd-chart-seq-2)",
          "--chart-seq-3": "var(--cd-chart-seq-3)",
          "--chart-seq-4": "var(--cd-chart-seq-4)",
          "--chart-seq-5": "var(--cd-chart-seq-5)",
          "--chart-div-1": "var(--cd-chart-div-1)",
          "--chart-div-2": "var(--cd-chart-div-2)",
          "--chart-div-3": "var(--cd-chart-div-3)",
          "--chart-div-4": "var(--cd-chart-div-4)",
          "--chart-div-5": "var(--cd-chart-div-5)",
          "--line-faint": "var(--cd-line-faint)",
          "--line-soft": "var(--cd-line-soft)",
          "--line": "var(--cd-line)",
          "--line-strong": "var(--cd-line-strong)",
          "--line-control": "var(--cd-line-control)",
          "--ai-from": "var(--cd-ai-from)",
          "--ai-via": "var(--cd-ai-via)",
          "--ai-to": "var(--cd-ai-to)",
          "--ai-text-from": "var(--cd-ai-text-from)",
          "--ai-text-via": "var(--cd-ai-text-via)",
          "--ai-text-to": "var(--cd-ai-text-to)",
          "--shadow-xs": "var(--cd-shadow-xs)",
          "--shadow-sm": "var(--cd-shadow-sm)",
          "--shadow": "var(--cd-shadow)",
          "--shadow-lg": "var(--cd-shadow-lg)",
          "--shadow-pop": "var(--cd-shadow-pop)",
          "--accent-pigment": "var(--moss)",
          "--accent-pigment-text": "var(--moss-deep)",
          "--text-accent-color": "var(--accent-pigment-text)",
          "--link": "var(--accent-pigment-text)",
          "--success": "var(--moss-deep)",
          "--warning": "var(--gold-text)",
          "--info": "var(--indigo-deep)",
          "--working": "var(--teal-deep)",
          "--queued": "var(--ink-muted)",
          "--background": "var(--paper)",
          "--foreground": "var(--ink)",
          "--card": "var(--paper-warm)",
          "--card-foreground": "var(--ink)",
          "--popover": "var(--paper-warm)",
          "--popover-foreground": "var(--ink)",
          "--primary": "var(--ink)",
          "--primary-foreground": "var(--paper)",
          "--secondary": "var(--paper-deep)",
          "--secondary-foreground": "var(--ink)",
          "--muted": "var(--paper-deep)",
          "--muted-foreground": "var(--ink-muted)",
          "--accent": "var(--paper-deep)",
          "--accent-foreground": "var(--ink)",
          "--destructive": "var(--terracotta-deep)",
          "--border": "var(--line-soft)",
          "--input": "var(--line-control)",
          "--ring": "var(--accent-pigment-text)",
          "--chart-1": "var(--chart-series-1)",
          "--chart-2": "var(--chart-series-2)",
          "--chart-3": "var(--chart-series-3)",
          "--chart-4": "var(--chart-series-4)",
          "--chart-5": "var(--chart-series-5)",
          "--sidebar": "var(--paper-warm)",
          "--sidebar-foreground": "var(--ink)",
          "--sidebar-primary": "var(--ink)",
          "--sidebar-primary-foreground": "var(--paper)",
          "--sidebar-accent": "var(--paper-deep)",
          "--sidebar-accent-foreground": "var(--ink)",
          "--sidebar-border": "var(--line-faint)",
          "--sidebar-ring": "var(--accent-pigment-text)"
        },
        "[data-theme=\"intelligent\"]": {
          "--paper": "var(--int-paper)",
          "--paper-warm": "var(--int-paper-warm)",
          "--paper-deep": "var(--int-paper-deep)",
          "--ink": "var(--int-ink)",
          "--ink-soft": "var(--int-ink-soft)",
          "--ink-muted": "var(--int-ink-muted)",
          "--terracotta": "var(--int-terracotta)",
          "--terracotta-deep": "var(--int-terracotta-deep)",
          "--moss": "var(--int-moss)",
          "--moss-deep": "var(--int-moss-deep)",
          "--indigo": "var(--int-indigo)",
          "--indigo-deep": "var(--int-indigo-deep)",
          "--gold": "var(--int-gold)",
          "--gold-deep": "var(--int-gold-deep)",
          "--gold-text": "var(--int-gold-text)",
          "--teal": "var(--int-teal)",
          "--teal-deep": "var(--int-teal-deep)",
          "--chart-series-1": "var(--int-chart-series-1)",
          "--chart-series-2": "var(--int-chart-series-2)",
          "--chart-series-3": "var(--int-chart-series-3)",
          "--chart-series-4": "var(--int-chart-series-4)",
          "--chart-series-5": "var(--int-chart-series-5)",
          "--chart-seq-1": "var(--int-chart-seq-1)",
          "--chart-seq-2": "var(--int-chart-seq-2)",
          "--chart-seq-3": "var(--int-chart-seq-3)",
          "--chart-seq-4": "var(--int-chart-seq-4)",
          "--chart-seq-5": "var(--int-chart-seq-5)",
          "--chart-div-1": "var(--int-chart-div-1)",
          "--chart-div-2": "var(--int-chart-div-2)",
          "--chart-div-3": "var(--int-chart-div-3)",
          "--chart-div-4": "var(--int-chart-div-4)",
          "--chart-div-5": "var(--int-chart-div-5)",
          "--line-faint": "var(--int-line-faint)",
          "--line-soft": "var(--int-line-soft)",
          "--line": "var(--int-line)",
          "--line-strong": "var(--int-line-strong)",
          "--line-control": "var(--int-line-control)",
          "--ai-from": "var(--int-ai-from)",
          "--ai-via": "var(--int-ai-via)",
          "--ai-to": "var(--int-ai-to)",
          "--ai-text-from": "var(--int-ai-text-from)",
          "--ai-text-via": "var(--int-ai-text-via)",
          "--ai-text-to": "var(--int-ai-text-to)",
          "--shadow-xs": "var(--int-shadow-xs)",
          "--shadow-sm": "var(--int-shadow-sm)",
          "--shadow": "var(--int-shadow)",
          "--shadow-lg": "var(--int-shadow-lg)",
          "--shadow-pop": "var(--int-shadow-pop)",
          "--accent-pigment": "var(--moss)",
          "--accent-pigment-text": "var(--moss-deep)",
          "--text-accent-color": "var(--accent-pigment-text)",
          "--link": "var(--accent-pigment-text)",
          "--success": "var(--moss-deep)",
          "--warning": "var(--gold-text)",
          "--info": "var(--indigo-deep)",
          "--working": "var(--teal-deep)",
          "--queued": "var(--ink-muted)",
          "--background": "var(--paper)",
          "--foreground": "var(--ink)",
          "--card": "var(--paper-warm)",
          "--card-foreground": "var(--ink)",
          "--popover": "var(--paper-warm)",
          "--popover-foreground": "var(--ink)",
          "--primary": "var(--ink)",
          "--primary-foreground": "var(--paper)",
          "--secondary": "var(--paper-deep)",
          "--secondary-foreground": "var(--ink)",
          "--muted": "var(--paper-deep)",
          "--muted-foreground": "var(--ink-muted)",
          "--accent": "var(--paper-deep)",
          "--accent-foreground": "var(--ink)",
          "--destructive": "var(--terracotta-deep)",
          "--border": "var(--line-soft)",
          "--input": "var(--line-control)",
          "--ring": "var(--accent-pigment-text)",
          "--chart-1": "var(--chart-series-1)",
          "--chart-2": "var(--chart-series-2)",
          "--chart-3": "var(--chart-series-3)",
          "--chart-4": "var(--chart-series-4)",
          "--chart-5": "var(--chart-series-5)",
          "--sidebar": "var(--paper-warm)",
          "--sidebar-foreground": "var(--ink)",
          "--sidebar-primary": "var(--ink)",
          "--sidebar-primary-foreground": "var(--paper)",
          "--sidebar-accent": "var(--paper-deep)",
          "--sidebar-accent-foreground": "var(--ink)",
          "--sidebar-border": "var(--line-faint)",
          "--sidebar-ring": "var(--accent-pigment-text)"
        },
        "[data-accent=\"terracotta\"]": {
          "--accent-pigment": "var(--terracotta)",
          "--accent-pigment-text": "var(--terracotta-deep)"
        },
        "[data-accent=\"moss\"]": {
          "--accent-pigment": "var(--moss)",
          "--accent-pigment-text": "var(--moss-deep)"
        },
        "[data-accent=\"indigo\"]": {
          "--accent-pigment": "var(--indigo)",
          "--accent-pigment-text": "var(--indigo-deep)"
        },
        "[data-accent=\"gold\"]": {
          "--accent-pigment": "var(--gold-deep)",
          "--accent-pigment-text": "var(--gold-text)"
        },
        "@utility ai-text": {
          "background-image": "linear-gradient(115deg, var(--ai-text-from), var(--ai-text-via) 50%, var(--ai-text-to))",
          "-webkit-background-clip": "text",
          "background-clip": "text",
          "color": "transparent"
        },
        "@utility ai-edge": {
          "border": "1.5px solid transparent",
          "background": "linear-gradient(var(--background), var(--background)) padding-box, linear-gradient(115deg, color-mix(in oklab, color-mix(in oklab, var(--ai-from) 55%, var(--ai-text-from)) 45%, var(--line-control)), color-mix(in oklab, var(--ai-via) 45%, var(--line-control)) 50%, color-mix(in oklab, var(--ai-to) 45%, var(--line-control))) border-box",
          "&:focus-within, &[data-lit]": {
            "background": "linear-gradient(var(--background), var(--background)) padding-box, linear-gradient(115deg, color-mix(in oklab, var(--ai-from) 55%, var(--ai-text-from)), var(--ai-via) 50%, var(--ai-to)) border-box"
          }
        },
        "@utility ai-edge-working": {
          "border": "1.5px solid transparent",
          "background": "linear-gradient(var(--background), var(--background)) padding-box, linear-gradient(90deg, color-mix(in oklab, var(--ai-from) 55%, var(--ai-text-from)), var(--ai-via), var(--ai-to), var(--ai-via), color-mix(in oklab, var(--ai-from) 55%, var(--ai-text-from))) border-box",
          "background-size": "100% 100%, 300% 100%",
          "animation": "ai-sweep 2.4s linear infinite",
          "@media (prefers-reduced-motion: reduce)": {
            "animation": "none",
            "background-size": "100% 100%, 100% 100%"
          }
        },
        "@utility ai-wash": {
          "background-image": "linear-gradient(180deg, color-mix(in oklab, var(--ai-from) 16%, transparent) 0%, color-mix(in oklab, var(--ai-via) 8%, transparent) 45%, transparent 100%)"
        },
        "@utility ai-glow": {
          "background-image": "radial-gradient(60% 70% at 30% 40%, color-mix(in oklab, var(--ai-from) 18%, transparent), transparent 70%), radial-gradient(55% 65% at 75% 60%, color-mix(in oklab, var(--ai-to) 18%, transparent), transparent 70%)"
        },
        "@utility ai-line": {
          "height": "2px",
          "border-radius": "2px",
          "background-image": "linear-gradient(90deg, var(--ai-from), var(--ai-via), var(--ai-to), var(--ai-via), var(--ai-from))",
          "background-size": "300% 100%",
          "animation": "ai-line 1.6s linear infinite",
          "@media (prefers-reduced-motion: reduce)": {
            "animation": "none",
            "background-size": "100% 100%"
          }
        },
        "@utility ai-shimmer": {
          "background-image": "linear-gradient(90deg, var(--muted-foreground), var(--ai-text-via), var(--muted-foreground))",
          "background-size": "200% 100%",
          "-webkit-background-clip": "text",
          "background-clip": "text",
          "color": "transparent",
          "animation": "ai-shimmer 2.2s linear infinite",
          "@media (prefers-reduced-motion: reduce)": {
            "animation": "none",
            "color": "var(--muted-foreground)",
            "background-image": "none"
          }
        },
        "@keyframes ai-sweep": {
          "to": {
            "background-position": "0 0, -300% 0"
          }
        },
        "@keyframes ai-line": {
          "to": {
            "background-position": "-300% 0"
          }
        },
        "@keyframes ai-shimmer": {
          "to": {
            "background-position": "-200% 0"
          }
        }
      },
      "docs": "Themes — set data-theme on <html>: unset (or data-theme=\"light\") → Dawn (default) · data-theme=\"dark\" → Dusk · data-theme=\"classic-light\" → Classic Light · data-theme=\"classic-dark\" → Classic Dark · data-theme=\"intelligent\" → Intelligent. 5 themes in total. Accents — set data-accent on <html>, independently of the theme: terracotta · moss (default) · indigo · gold. The accent drives links, eyebrows, focus rings and accent italics. The two axes are independent. Runtime contract — the theme-selector block owns both attributes: after hydration it reads localStorage (\"quill-theme\", \"quill-accent\") and stamps <html>. Prerendered markup is always Dawn + moss, so first paint matches the server. Charts — use the chart tokens (--chart-series-1..5, the sequential and diverging ramps), never raw pigments. Assign series colours in that fixed order and never reorder or cycle survivors when a filter drops one: the order keeps the palette distinguishable under all three dichromacies. Fonts — Raleway (body) and Fraunces (display) load through the theme file's @import; no next/font. Never load them again under another name: the theme matches literal names. Wiring — the CLI install merges the theme into your Tailwind stylesheet. A theme FILE must be imported from inside that stylesheet — `@import \"./quill-theme.css\"` after `@import \"tailwindcss\"` and below any `@custom-variant dark` line shadcn wrote (the last wins) — never from layout.tsx, where every Quill utility is dead. dark: utilities — stock primitives' dark: tweaks follow Quill's dark themes (and the .dark class) once the theme is wired; nothing to add by hand. Self-check — after changing UI, run `node scripts/quill-check.mjs` (install once: `npx shadcn@latest add @quill/check`) and clear every finding: stock colours, raw colours, bracket values where a token exists, retired names, dead classes. An exception: `// quill-check: allow <rule> — <why>` on the line above. Updating — re-run with --overwrite, not --yes: on a file you have changed, --yes prompts in a terminal and silently skips when non-interactive. Full machine-readable reference for agents: https://www.quilldesignsystem.com/llms.txt. Per-component usage guides at /usage/<name>.md."
    },
    {
      "name": "icon",
      "type": "registry:ui",
      "title": "Icon (Material Symbols)",
      "description": "The Quill icon component — Material Symbols Outlined at weight 400, shipped as a self-contained core set of 93 names covering every icon the Quill blocks use.",
      "files": [
        {
          "path": "registry/lib/icon.tsx",
          "type": "registry:ui",
          "target": "components/ui/icon.tsx"
        },
        {
          "path": "src/components/ui/icons.core.mjs",
          "type": "registry:ui",
          "target": "components/ui/icons.core.mjs"
        },
        {
          "path": "registry/lib/icons.core.d.mts",
          "type": "registry:ui",
          "target": "components/ui/icons.core.d.mts"
        }
      ],
      "docs": "The Quill icon component — Material Symbols Outlined at weight 400, shipped as a self-contained core set of 93 names covering every icon the Quill blocks use. Do: Pick a name from the core set the `icon` item ships (93 names): account_balance, add, add_circle, archive, arrow_back, arrow_downward, arrow_forward, arrow_upward, attach_file, attach_money, calendar_today, cancel, chat_bubble, check, check_box, check_box_outline_blank, check_circle, chevron_left, chevron_right, close, cloud_upload, content_copy, credit_card, dangerous, dark_mode, dashboard, delete, description, dock_to_left, download, draft, edit, error, favorite, filter_list, folder_open, format_align_center, format_align_left, format_align_right, format_bold, format_italic, format_underlined, forward, group, help, home, info, ink_pen, keyboard_arrow_down, keyboard_arrow_left, keyboard_arrow_right, keyboard_arrow_up, keyboard_command_key, language, light_mode, link, lock, login, logout, mail, menu, menu_book, mic, more_horiz, more_vert, notifications, open_in_new, palette, person, person_add, photo_library, progress_activity, radio_button_checked, radio_button_unchecked, refresh, remove, reply, save, schedule, search, send, settings, share, sort, space_dashboard, star, star_shine, stop, upload, visibility, visibility_off, wallet, warning. Don't: Use any other Material Symbol name in an app. The consumer `<Icon>` bundles only the core set, so an unknown name renders as an empty, size-reserved box (plus a console warning in development); the design-system site lazy-loads the whole library, so a name can look fine on quilldesignsystem.com and be blank in your app. Do: Size through the `size` prop — a pixel number, or leave the `1em` default so the glyph follows the surrounding text. Don't: Scale an icon with a `transform` or a width/height class — the reserved box stops matching the glyph and the layout shifts. Do: Leave an icon decorative (the default renders `aria-hidden`) when the text next to it already carries the meaning. Don't: Add an `aria-label` to an icon that sits beside its own label — screen readers then announce the meaning twice. Use button when the glyph is the whole control — use Button with an icon size (`icon`, `icon-sm`) and an `aria-label`; Icon on its own is never interactive. Use spinner when the glyph means \"loading\" — Spinner carries the motion and the status semantics an icon does not."
    },
    {
      "name": "tone-badge",
      "type": "registry:ui",
      "title": "Tone badge",
      "description": "Quill's uppercase tag pill for status, tiers, and labels — wraps Badge with the pigment vocabulary (moss/gold/terracotta/indigo/neutral/muted) baked in so tone never drifts per call site.",
      "registryDependencies": [
        "badge"
      ],
      "files": [
        {
          "path": "registry/lib/tone-badge.tsx",
          "target": "components/ui/tone-badge.tsx",
          "type": "registry:ui"
        }
      ],
      "docs": "Quill's uppercase tag pill for status, tiers, and labels — wraps Badge with the pigment vocabulary (moss/gold/terracotta/indigo/neutral/muted) baked in so tone never drifts per call site. Do: Leave `solid` false (the tinted default) for regular status/tier labels — it is the visually quieter option and still hits AA contrast per tone. Don't: Set `solid` on every ToneBadge in a view — solid is reserved for the one strong cue (a \"current\" marker, a live state) and loses its signal once everything is solid. Do: Render every uppercase tag pill through ToneBadge, even one-off labels. Don't: Hand-roll a `rounded-full … uppercase` span with ad hoc tone colors — it drifts from the AA-checked tint/solid pairs and the two-size scale. Do: Use ToneBadge's own size scale — `md` (20px) or `sm` (16px, the count-pill scale). Don't: Shrink a pill by hand-tightening its tracking or padding instead of passing `size=\"sm\"` — type stays `--text-2xs` at 0.1em tracking in both sizes. Use badge when the label is a generic chip outside Quill's tag-pill vocabulary — use Badge directly instead of forcing it through a tone."
    },
    {
      "name": "ai-badge",
      "type": "registry:ui",
      "title": "AI badge",
      "description": "A small outline pill with the AI sparkle that marks content an AI made or suggested — \"AI draft\", \"Suggested\".",
      "registryDependencies": [
        "badge",
        "https://www.quilldesignsystem.com/r/ai-mark.json"
      ],
      "files": [
        {
          "path": "registry/lib/ai-badge.tsx",
          "target": "components/ui/ai-badge.tsx",
          "type": "registry:ui"
        }
      ],
      "docs": "A small outline pill with the AI sparkle that marks content an AI made or suggested — \"AI draft\", \"Suggested\". Do: Use the AI badge to say who made the content: \"AI draft\", \"Suggested\", \"Generated\". Don't: Use it as a status (\"Active\", \"New\") — status belongs to ToneBadge. Use tone-badge when the label is a status, tier or category rather than \"made by AI\". Use ai-mark when there is no room for words and the mark alone is enough."
    },
    {
      "name": "ai-button",
      "type": "registry:ui",
      "title": "AI button",
      "description": "A stock Quill button that runs an AI action, marked with the AI sparkle; the label stays plain ink.",
      "registryDependencies": [
        "button",
        "https://www.quilldesignsystem.com/r/ai-mark.json"
      ],
      "files": [
        {
          "path": "registry/lib/ai-button.tsx",
          "target": "components/ui/ai-button.tsx",
          "type": "registry:ui"
        }
      ],
      "docs": "A stock Quill button that runs an AI action, marked with the AI sparkle; the label stays plain ink. Do: Let the sparkle carry the gradient and keep the label in the button's normal text colour. Don't: Fill the button or its label with the AI gradient — the gradient belongs on the mark, and a gradient fill competes with the page. Do: Use a plain Button for Accept, Replace and Use this, even inside an AI popover. Don't: Make the button that applies an AI suggestion an AiButton — acting on AI output is an ordinary decision. Use button when the action does not involve AI. Use prompt-composer when the person needs to type what they want rather than press one action."
    },
    {
      "name": "ai-mark",
      "type": "registry:ui",
      "title": "AI mark",
      "description": "Quill's AI sparkle — the one icon that means AI, drawn in the AI gradient with a one-star cut for 16px and under.",
      "files": [
        {
          "path": "registry/lib/ai-mark.tsx",
          "target": "components/ui/ai-mark.tsx",
          "type": "registry:ui"
        }
      ],
      "docs": "Quill's AI sparkle — the one icon that means AI, drawn in the AI gradient with a one-star cut for 16px and under. Do: Use the AI mark only where the thing it sits on calls an AI or was made by one. Don't: Use the sparkle as decoration, a \"new\" marker or a rating star — once it appears on non-AI things it stops meaning AI. Do: Let the mark draw its own gradient at every size; pass `size`, never a colour. Don't: Recolour the mark with a text colour or a single pigment — the gradient is what makes it read as AI. Do: Pass `label` when the mark is the only thing that says \"AI\" (an icon-only button or avatar). Don't: Leave a standalone mark unlabelled — screen readers hear nothing. Use ai-badge when you are labelling a piece of content as AI-made; the badge carries the mark and the words. Use icon when the icon means anything other than AI — every other icon comes from the Material Symbols set."
    },
    {
      "name": "prompt-composer",
      "type": "registry:ui",
      "title": "Prompt composer",
      "description": "The box people type to an AI in — grows with the text, sends on Enter, turns Send into Stop while the AI works, with slots for tools, files and a model picker.",
      "registryDependencies": [
        "button",
        "textarea",
        "command",
        "https://www.quilldesignsystem.com/r/icon.json",
        "https://www.quilldesignsystem.com/r/ai-mark.json"
      ],
      "files": [
        {
          "path": "registry/lib/prompt-composer.tsx",
          "target": "components/ui/prompt-composer.tsx",
          "type": "registry:ui"
        }
      ],
      "docs": "The box people type to an AI in — grows with the text, sends on Enter, turns Send into Stop while the AI works, with slots for tools, files and a model picker. Do: Let the composer draw its own AI edge: muted at rest, full on focus, sweeping while working. Don't: Wrap it in a thick glowing gradient ring or a second border — one thin line marks AI. Do: Keep Send and Stop solid ink in the same spot. Don't: Fill the Send button with the AI gradient — it competes with the edge and breaks the never-on-Send rule. Do: Use `lg` on an AI home page and `sm` in threads, side panels and inline bars. Don't: Put the large composer inside a narrow panel — use `sm`. Do: When you pass `value`, clear it yourself in `onSubmit` (set it to an empty string). Don't: Pass `value` and expect the composer to empty itself after sending — it only clears its own state when uncontrolled. Do: Show active AI tools (Analyze data, Web search) as chips with the mark, and attached files as neutral file chips. Don't: Put the AI mark on attached files — the files are the person's, not the AI's. Do: Mark AI commands in the / menu with the AI sparkle and leave ordinary app commands unmarked. Don't: Mark every command — the mark is how people tell which actions call the AI. Do: Set `status=\"working\"` while the AI answers and pass `onStop`. Don't: Disable the whole composer while the AI works — people should be able to stop it. Do: Use `variant=\"notebook\"` where the prompt is a piece of writing — a brief, a spec, a long instruction. Don't: Use the notebook for quick questions or a help widget — its ruled page reads as \"write at length\". Do: Give each mode its own icon (`icon`) — the AI mode uses `ai: true` for the mark — and use `showModes={false}` to hide the tabs where a page has only one mode. Don't: Remove the `modes` list just to hide the tabs; that also drops each mode's placeholder. Use ai-home when you need the whole AI start page around the composer, not just the box. Use chat when two people are messaging each other and no AI is involved. Use textarea when it is an ordinary form field whose text is saved, not sent to an AI."
    },
    {
      "name": "example-app-page",
      "type": "registry:component",
      "title": "Example: app page",
      "description": "An example showing how to compose an app page: the sidebar-nav shell wrapping a page-header, then stat-cards, then a data-table — the page leads with what it is about, and the numbers sit inside it.",
      "files": [
        {
          "path": "registry/examples/example-app-page.tsx",
          "type": "registry:component",
          "target": "components/examples/example-app-page.tsx"
        }
      ],
      "registryDependencies": [
        "https://www.quilldesignsystem.com/r/sidebar-nav.json",
        "https://www.quilldesignsystem.com/r/page-header.json",
        "https://www.quilldesignsystem.com/r/stat-cards.json",
        "https://www.quilldesignsystem.com/r/data-table.json"
      ],
      "docs": "Composition, top to bottom: sidebar-nav → page-header → stat-cards → data-table. Install it, then replace the blocks' sample content with your own; keep the order and the spacing.\n\nA **4px base step** (`--space-1` = 0.25rem). Editorial rhythm — sections breathe.\n\n`--space-1` 4px · `--space-2` 8px · `--space-3` 12px · `--space-4` 16px · `--space-5` 20px · `--space-6` 24px · `--space-7` 28px · `--space-8` 32px · `--space-9` 36px · `--space-10` 40px · `--space-12` 48px · `--space-16` 64px · `--space-20` 80px · `--space-24` 96px\n\nComponents sit on `--space-4` / `--space-6`; sections breathe with `--space-24`. In a component write the class (`p-4`, `gap-6`): it is the same step, and no shipped component reads the variable. The variables are for hand-written CSS.\n\n### Layout\nNo layout tokens ship; use the values the site uses. Marketing max-width **1400px** (`max-w-[1400px]`), reading column **800px**, side padding **48px** on desktop (`px-12`) and **24px** on mobile (`px-6`), vertical section rhythm **96px** (`py-24`; `py-14` on mobile).\n\n### Composition\n- Recurring section header: eyebrow → headline (one accent word) → right-aligned italic caption.\n- One idea per section: a heading plus one composition (a grid of cards, a table, a form), never a stack of unrelated widgets.\n- No hero-metric row above an identical card grid — that is the generic dashboard Quill exists to avoid. Lead with the thing the page is about; let numbers sit inside it."
    },
    {
      "name": "example-marketing-page",
      "type": "registry:component",
      "title": "Example: marketing page",
      "description": "An example showing how to compose a marketing page: navbar, hero, feature-section, pricing, testimonial and footer — one idea per section, breathing at the 96px rhythm.",
      "files": [
        {
          "path": "registry/examples/example-marketing-page.tsx",
          "type": "registry:component",
          "target": "components/examples/example-marketing-page.tsx"
        }
      ],
      "registryDependencies": [
        "https://www.quilldesignsystem.com/r/navbar.json",
        "https://www.quilldesignsystem.com/r/hero.json",
        "https://www.quilldesignsystem.com/r/feature-section.json",
        "https://www.quilldesignsystem.com/r/pricing.json",
        "https://www.quilldesignsystem.com/r/testimonial.json",
        "https://www.quilldesignsystem.com/r/footer.json"
      ],
      "docs": "Composition, top to bottom: navbar → hero → feature-section → pricing → testimonial → footer. Install it, then replace the blocks' sample content with your own; keep the order and the spacing.\n\nA **4px base step** (`--space-1` = 0.25rem). Editorial rhythm — sections breathe.\n\n`--space-1` 4px · `--space-2` 8px · `--space-3` 12px · `--space-4` 16px · `--space-5` 20px · `--space-6` 24px · `--space-7` 28px · `--space-8` 32px · `--space-9` 36px · `--space-10` 40px · `--space-12` 48px · `--space-16` 64px · `--space-20` 80px · `--space-24` 96px\n\nComponents sit on `--space-4` / `--space-6`; sections breathe with `--space-24`. In a component write the class (`p-4`, `gap-6`): it is the same step, and no shipped component reads the variable. The variables are for hand-written CSS.\n\n### Layout\nNo layout tokens ship; use the values the site uses. Marketing max-width **1400px** (`max-w-[1400px]`), reading column **800px**, side padding **48px** on desktop (`px-12`) and **24px** on mobile (`px-6`), vertical section rhythm **96px** (`py-24`; `py-14` on mobile).\n\n### Composition\n- Recurring section header: eyebrow → headline (one accent word) → right-aligned italic caption.\n- One idea per section: a heading plus one composition (a grid of cards, a table, a form), never a stack of unrelated widgets.\n- No hero-metric row above an identical card grid — that is the generic dashboard Quill exists to avoid. Lead with the thing the page is about; let numbers sit inside it."
    },
    {
      "name": "example-auth-page",
      "type": "registry:component",
      "title": "Example: auth page",
      "description": "An example showing how to compose an auth page: login-split-panel alone at full viewport — one task, nothing competing with it.",
      "files": [
        {
          "path": "registry/examples/example-auth-page.tsx",
          "type": "registry:component",
          "target": "components/examples/example-auth-page.tsx"
        }
      ],
      "registryDependencies": [
        "https://www.quilldesignsystem.com/r/login-split-panel.json"
      ],
      "docs": "Composition, top to bottom: login-split-panel. Install it, then replace the blocks' sample content with your own; keep the order and the spacing.\n\nA **4px base step** (`--space-1` = 0.25rem). Editorial rhythm — sections breathe.\n\n`--space-1` 4px · `--space-2` 8px · `--space-3` 12px · `--space-4` 16px · `--space-5` 20px · `--space-6` 24px · `--space-7` 28px · `--space-8` 32px · `--space-9` 36px · `--space-10` 40px · `--space-12` 48px · `--space-16` 64px · `--space-20` 80px · `--space-24` 96px\n\nComponents sit on `--space-4` / `--space-6`; sections breathe with `--space-24`. In a component write the class (`p-4`, `gap-6`): it is the same step, and no shipped component reads the variable. The variables are for hand-written CSS.\n\n### Layout\nNo layout tokens ship; use the values the site uses. Marketing max-width **1400px** (`max-w-[1400px]`), reading column **800px**, side padding **48px** on desktop (`px-12`) and **24px** on mobile (`px-6`), vertical section rhythm **96px** (`py-24`; `py-14` on mobile).\n\n### Composition\n- Recurring section header: eyebrow → headline (one accent word) → right-aligned italic caption.\n- One idea per section: a heading plus one composition (a grid of cards, a table, a form), never a stack of unrelated widgets.\n- No hero-metric row above an identical card grid — that is the generic dashboard Quill exists to avoid. Lead with the thing the page is about; let numbers sit inside it."
    },
    {
      "name": "agent-rules",
      "type": "registry:file",
      "title": "Quill agent rules",
      "description": "Claude Code project rules and a component-choosing skill so AI agents build on-brand with Quill — the theming contract, foundations, principles, icon names and the block index, plus when to use each block and primitive and what to reach for instead, generated from the design system.",
      "docs": "Installs .claude/rules/quill.md at the project root, which Claude Code loads every session, and the quill-components skill in .claude/skills/quill-components/, which loads when an agent is choosing UI. Re-run `npx shadcn@latest add @quill/agent-rules --overwrite` after each Quill release to update it; the library-sync bot does this for apps that carry the rules file, including the skill.",
      "files": [
        {
          "path": "registry/agent-rules/quill.md",
          "type": "registry:file",
          "target": "~/.claude/rules/quill.md"
        },
        {
          "path": "registry/agent-rules/skills/quill-components/SKILL.md",
          "type": "registry:file",
          "target": "~/.claude/skills/quill-components/SKILL.md"
        },
        {
          "path": "registry/agent-rules/skills/quill-components/reference/accordion.md",
          "type": "registry:file",
          "target": "~/.claude/skills/quill-components/reference/accordion.md"
        },
        {
          "path": "registry/agent-rules/skills/quill-components/reference/activity-feed.md",
          "type": "registry:file",
          "target": "~/.claude/skills/quill-components/reference/activity-feed.md"
        },
        {
          "path": "registry/agent-rules/skills/quill-components/reference/ai-badge.md",
          "type": "registry:file",
          "target": "~/.claude/skills/quill-components/reference/ai-badge.md"
        },
        {
          "path": "registry/agent-rules/skills/quill-components/reference/ai-button.md",
          "type": "registry:file",
          "target": "~/.claude/skills/quill-components/reference/ai-button.md"
        },
        {
          "path": "registry/agent-rules/skills/quill-components/reference/ai-mark.md",
          "type": "registry:file",
          "target": "~/.claude/skills/quill-components/reference/ai-mark.md"
        },
        {
          "path": "registry/agent-rules/skills/quill-components/reference/alert.md",
          "type": "registry:file",
          "target": "~/.claude/skills/quill-components/reference/alert.md"
        },
        {
          "path": "registry/agent-rules/skills/quill-components/reference/alert-dialog.md",
          "type": "registry:file",
          "target": "~/.claude/skills/quill-components/reference/alert-dialog.md"
        },
        {
          "path": "registry/agent-rules/skills/quill-components/reference/alerts.md",
          "type": "registry:file",
          "target": "~/.claude/skills/quill-components/reference/alerts.md"
        },
        {
          "path": "registry/agent-rules/skills/quill-components/reference/analytics-charts.md",
          "type": "registry:file",
          "target": "~/.claude/skills/quill-components/reference/analytics-charts.md"
        },
        {
          "path": "registry/agent-rules/skills/quill-components/reference/announcement-banner.md",
          "type": "registry:file",
          "target": "~/.claude/skills/quill-components/reference/announcement-banner.md"
        },
        {
          "path": "registry/agent-rules/skills/quill-components/reference/aspect-ratio.md",
          "type": "registry:file",
          "target": "~/.claude/skills/quill-components/reference/aspect-ratio.md"
        },
        {
          "path": "registry/agent-rules/skills/quill-components/reference/avatar.md",
          "type": "registry:file",
          "target": "~/.claude/skills/quill-components/reference/avatar.md"
        },
        {
          "path": "registry/agent-rules/skills/quill-components/reference/badge.md",
          "type": "registry:file",
          "target": "~/.claude/skills/quill-components/reference/badge.md"
        },
        {
          "path": "registry/agent-rules/skills/quill-components/reference/badge-on-card.md",
          "type": "registry:file",
          "target": "~/.claude/skills/quill-components/reference/badge-on-card.md"
        },
        {
          "path": "registry/agent-rules/skills/quill-components/reference/breadcrumb.md",
          "type": "registry:file",
          "target": "~/.claude/skills/quill-components/reference/breadcrumb.md"
        },
        {
          "path": "registry/agent-rules/skills/quill-components/reference/button.md",
          "type": "registry:file",
          "target": "~/.claude/skills/quill-components/reference/button.md"
        },
        {
          "path": "registry/agent-rules/skills/quill-components/reference/button-group.md",
          "type": "registry:file",
          "target": "~/.claude/skills/quill-components/reference/button-group.md"
        },
        {
          "path": "registry/agent-rules/skills/quill-components/reference/calendar.md",
          "type": "registry:file",
          "target": "~/.claude/skills/quill-components/reference/calendar.md"
        },
        {
          "path": "registry/agent-rules/skills/quill-components/reference/calendar-page.md",
          "type": "registry:file",
          "target": "~/.claude/skills/quill-components/reference/calendar-page.md"
        },
        {
          "path": "registry/agent-rules/skills/quill-components/reference/calendar-range.md",
          "type": "registry:file",
          "target": "~/.claude/skills/quill-components/reference/calendar-range.md"
        },
        {
          "path": "registry/agent-rules/skills/quill-components/reference/card.md",
          "type": "registry:file",
          "target": "~/.claude/skills/quill-components/reference/card.md"
        },
        {
          "path": "registry/agent-rules/skills/quill-components/reference/carousel.md",
          "type": "registry:file",
          "target": "~/.claude/skills/quill-components/reference/carousel.md"
        },
        {
          "path": "registry/agent-rules/skills/quill-components/reference/chart.md",
          "type": "registry:file",
          "target": "~/.claude/skills/quill-components/reference/chart.md"
        },
        {
          "path": "registry/agent-rules/skills/quill-components/reference/chat.md",
          "type": "registry:file",
          "target": "~/.claude/skills/quill-components/reference/chat.md"
        },
        {
          "path": "registry/agent-rules/skills/quill-components/reference/ai-home.md",
          "type": "registry:file",
          "target": "~/.claude/skills/quill-components/reference/ai-home.md"
        },
        {
          "path": "registry/agent-rules/skills/quill-components/reference/checkbox.md",
          "type": "registry:file",
          "target": "~/.claude/skills/quill-components/reference/checkbox.md"
        },
        {
          "path": "registry/agent-rules/skills/quill-components/reference/checkout.md",
          "type": "registry:file",
          "target": "~/.claude/skills/quill-components/reference/checkout.md"
        },
        {
          "path": "registry/agent-rules/skills/quill-components/reference/collapsible.md",
          "type": "registry:file",
          "target": "~/.claude/skills/quill-components/reference/collapsible.md"
        },
        {
          "path": "registry/agent-rules/skills/quill-components/reference/combobox.md",
          "type": "registry:file",
          "target": "~/.claude/skills/quill-components/reference/combobox.md"
        },
        {
          "path": "registry/agent-rules/skills/quill-components/reference/command.md",
          "type": "registry:file",
          "target": "~/.claude/skills/quill-components/reference/command.md"
        },
        {
          "path": "registry/agent-rules/skills/quill-components/reference/command-palette.md",
          "type": "registry:file",
          "target": "~/.claude/skills/quill-components/reference/command-palette.md"
        },
        {
          "path": "registry/agent-rules/skills/quill-components/reference/contact-form.md",
          "type": "registry:file",
          "target": "~/.claude/skills/quill-components/reference/contact-form.md"
        },
        {
          "path": "registry/agent-rules/skills/quill-components/reference/context-menu.md",
          "type": "registry:file",
          "target": "~/.claude/skills/quill-components/reference/context-menu.md"
        },
        {
          "path": "registry/agent-rules/skills/quill-components/reference/cookie-consent.md",
          "type": "registry:file",
          "target": "~/.claude/skills/quill-components/reference/cookie-consent.md"
        },
        {
          "path": "registry/agent-rules/skills/quill-components/reference/dashboard.md",
          "type": "registry:file",
          "target": "~/.claude/skills/quill-components/reference/dashboard.md"
        },
        {
          "path": "registry/agent-rules/skills/quill-components/reference/data-table.md",
          "type": "registry:file",
          "target": "~/.claude/skills/quill-components/reference/data-table.md"
        },
        {
          "path": "registry/agent-rules/skills/quill-components/reference/dialog.md",
          "type": "registry:file",
          "target": "~/.claude/skills/quill-components/reference/dialog.md"
        },
        {
          "path": "registry/agent-rules/skills/quill-components/reference/drawer.md",
          "type": "registry:file",
          "target": "~/.claude/skills/quill-components/reference/drawer.md"
        },
        {
          "path": "registry/agent-rules/skills/quill-components/reference/dropdown-menu.md",
          "type": "registry:file",
          "target": "~/.claude/skills/quill-components/reference/dropdown-menu.md"
        },
        {
          "path": "registry/agent-rules/skills/quill-components/reference/empty.md",
          "type": "registry:file",
          "target": "~/.claude/skills/quill-components/reference/empty.md"
        },
        {
          "path": "registry/agent-rules/skills/quill-components/reference/empty-state.md",
          "type": "registry:file",
          "target": "~/.claude/skills/quill-components/reference/empty-state.md"
        },
        {
          "path": "registry/agent-rules/skills/quill-components/reference/error-404.md",
          "type": "registry:file",
          "target": "~/.claude/skills/quill-components/reference/error-404.md"
        },
        {
          "path": "registry/agent-rules/skills/quill-components/reference/faq.md",
          "type": "registry:file",
          "target": "~/.claude/skills/quill-components/reference/faq.md"
        },
        {
          "path": "registry/agent-rules/skills/quill-components/reference/feature-section.md",
          "type": "registry:file",
          "target": "~/.claude/skills/quill-components/reference/feature-section.md"
        },
        {
          "path": "registry/agent-rules/skills/quill-components/reference/field.md",
          "type": "registry:file",
          "target": "~/.claude/skills/quill-components/reference/field.md"
        },
        {
          "path": "registry/agent-rules/skills/quill-components/reference/file-upload.md",
          "type": "registry:file",
          "target": "~/.claude/skills/quill-components/reference/file-upload.md"
        },
        {
          "path": "registry/agent-rules/skills/quill-components/reference/footer.md",
          "type": "registry:file",
          "target": "~/.claude/skills/quill-components/reference/footer.md"
        },
        {
          "path": "registry/agent-rules/skills/quill-components/reference/forgot-password.md",
          "type": "registry:file",
          "target": "~/.claude/skills/quill-components/reference/forgot-password.md"
        },
        {
          "path": "registry/agent-rules/skills/quill-components/reference/hero.md",
          "type": "registry:file",
          "target": "~/.claude/skills/quill-components/reference/hero.md"
        },
        {
          "path": "registry/agent-rules/skills/quill-components/reference/hover-card.md",
          "type": "registry:file",
          "target": "~/.claude/skills/quill-components/reference/hover-card.md"
        },
        {
          "path": "registry/agent-rules/skills/quill-components/reference/icon.md",
          "type": "registry:file",
          "target": "~/.claude/skills/quill-components/reference/icon.md"
        },
        {
          "path": "registry/agent-rules/skills/quill-components/reference/input.md",
          "type": "registry:file",
          "target": "~/.claude/skills/quill-components/reference/input.md"
        },
        {
          "path": "registry/agent-rules/skills/quill-components/reference/input-group.md",
          "type": "registry:file",
          "target": "~/.claude/skills/quill-components/reference/input-group.md"
        },
        {
          "path": "registry/agent-rules/skills/quill-components/reference/input-otp.md",
          "type": "registry:file",
          "target": "~/.claude/skills/quill-components/reference/input-otp.md"
        },
        {
          "path": "registry/agent-rules/skills/quill-components/reference/invoice.md",
          "type": "registry:file",
          "target": "~/.claude/skills/quill-components/reference/invoice.md"
        },
        {
          "path": "registry/agent-rules/skills/quill-components/reference/item.md",
          "type": "registry:file",
          "target": "~/.claude/skills/quill-components/reference/item.md"
        },
        {
          "path": "registry/agent-rules/skills/quill-components/reference/kanban.md",
          "type": "registry:file",
          "target": "~/.claude/skills/quill-components/reference/kanban.md"
        },
        {
          "path": "registry/agent-rules/skills/quill-components/reference/kbd.md",
          "type": "registry:file",
          "target": "~/.claude/skills/quill-components/reference/kbd.md"
        },
        {
          "path": "registry/agent-rules/skills/quill-components/reference/label.md",
          "type": "registry:file",
          "target": "~/.claude/skills/quill-components/reference/label.md"
        },
        {
          "path": "registry/agent-rules/skills/quill-components/reference/list-detail.md",
          "type": "registry:file",
          "target": "~/.claude/skills/quill-components/reference/list-detail.md"
        },
        {
          "path": "registry/agent-rules/skills/quill-components/reference/login.md",
          "type": "registry:file",
          "target": "~/.claude/skills/quill-components/reference/login.md"
        },
        {
          "path": "registry/agent-rules/skills/quill-components/reference/login-minimal.md",
          "type": "registry:file",
          "target": "~/.claude/skills/quill-components/reference/login-minimal.md"
        },
        {
          "path": "registry/agent-rules/skills/quill-components/reference/login-oauth.md",
          "type": "registry:file",
          "target": "~/.claude/skills/quill-components/reference/login-oauth.md"
        },
        {
          "path": "registry/agent-rules/skills/quill-components/reference/login-split-panel.md",
          "type": "registry:file",
          "target": "~/.claude/skills/quill-components/reference/login-split-panel.md"
        },
        {
          "path": "registry/agent-rules/skills/quill-components/reference/mail-shell.md",
          "type": "registry:file",
          "target": "~/.claude/skills/quill-components/reference/mail-shell.md"
        },
        {
          "path": "registry/agent-rules/skills/quill-components/reference/menubar.md",
          "type": "registry:file",
          "target": "~/.claude/skills/quill-components/reference/menubar.md"
        },
        {
          "path": "registry/agent-rules/skills/quill-components/reference/native-select.md",
          "type": "registry:file",
          "target": "~/.claude/skills/quill-components/reference/native-select.md"
        },
        {
          "path": "registry/agent-rules/skills/quill-components/reference/navbar.md",
          "type": "registry:file",
          "target": "~/.claude/skills/quill-components/reference/navbar.md"
        },
        {
          "path": "registry/agent-rules/skills/quill-components/reference/navigation-menu.md",
          "type": "registry:file",
          "target": "~/.claude/skills/quill-components/reference/navigation-menu.md"
        },
        {
          "path": "registry/agent-rules/skills/quill-components/reference/newsletter.md",
          "type": "registry:file",
          "target": "~/.claude/skills/quill-components/reference/newsletter.md"
        },
        {
          "path": "registry/agent-rules/skills/quill-components/reference/notifications.md",
          "type": "registry:file",
          "target": "~/.claude/skills/quill-components/reference/notifications.md"
        },
        {
          "path": "registry/agent-rules/skills/quill-components/reference/onboarding.md",
          "type": "registry:file",
          "target": "~/.claude/skills/quill-components/reference/onboarding.md"
        },
        {
          "path": "registry/agent-rules/skills/quill-components/reference/order-summary.md",
          "type": "registry:file",
          "target": "~/.claude/skills/quill-components/reference/order-summary.md"
        },
        {
          "path": "registry/agent-rules/skills/quill-components/reference/otp-verification.md",
          "type": "registry:file",
          "target": "~/.claude/skills/quill-components/reference/otp-verification.md"
        },
        {
          "path": "registry/agent-rules/skills/quill-components/reference/page-header.md",
          "type": "registry:file",
          "target": "~/.claude/skills/quill-components/reference/page-header.md"
        },
        {
          "path": "registry/agent-rules/skills/quill-components/reference/pagination.md",
          "type": "registry:file",
          "target": "~/.claude/skills/quill-components/reference/pagination.md"
        },
        {
          "path": "registry/agent-rules/skills/quill-components/reference/popover.md",
          "type": "registry:file",
          "target": "~/.claude/skills/quill-components/reference/popover.md"
        },
        {
          "path": "registry/agent-rules/skills/quill-components/reference/pricing.md",
          "type": "registry:file",
          "target": "~/.claude/skills/quill-components/reference/pricing.md"
        },
        {
          "path": "registry/agent-rules/skills/quill-components/reference/profile-card.md",
          "type": "registry:file",
          "target": "~/.claude/skills/quill-components/reference/profile-card.md"
        },
        {
          "path": "registry/agent-rules/skills/quill-components/reference/progress.md",
          "type": "registry:file",
          "target": "~/.claude/skills/quill-components/reference/progress.md"
        },
        {
          "path": "registry/agent-rules/skills/quill-components/reference/prompt-composer.md",
          "type": "registry:file",
          "target": "~/.claude/skills/quill-components/reference/prompt-composer.md"
        },
        {
          "path": "registry/agent-rules/skills/quill-components/reference/radio-group.md",
          "type": "registry:file",
          "target": "~/.claude/skills/quill-components/reference/radio-group.md"
        },
        {
          "path": "registry/agent-rules/skills/quill-components/reference/resizable.md",
          "type": "registry:file",
          "target": "~/.claude/skills/quill-components/reference/resizable.md"
        },
        {
          "path": "registry/agent-rules/skills/quill-components/reference/scroll-area.md",
          "type": "registry:file",
          "target": "~/.claude/skills/quill-components/reference/scroll-area.md"
        },
        {
          "path": "registry/agent-rules/skills/quill-components/reference/search-results.md",
          "type": "registry:file",
          "target": "~/.claude/skills/quill-components/reference/search-results.md"
        },
        {
          "path": "registry/agent-rules/skills/quill-components/reference/select.md",
          "type": "registry:file",
          "target": "~/.claude/skills/quill-components/reference/select.md"
        },
        {
          "path": "registry/agent-rules/skills/quill-components/reference/separator.md",
          "type": "registry:file",
          "target": "~/.claude/skills/quill-components/reference/separator.md"
        },
        {
          "path": "registry/agent-rules/skills/quill-components/reference/settings.md",
          "type": "registry:file",
          "target": "~/.claude/skills/quill-components/reference/settings.md"
        },
        {
          "path": "registry/agent-rules/skills/quill-components/reference/sheet.md",
          "type": "registry:file",
          "target": "~/.claude/skills/quill-components/reference/sheet.md"
        },
        {
          "path": "registry/agent-rules/skills/quill-components/reference/sidebar.md",
          "type": "registry:file",
          "target": "~/.claude/skills/quill-components/reference/sidebar.md"
        },
        {
          "path": "registry/agent-rules/skills/quill-components/reference/sidebar-nav.md",
          "type": "registry:file",
          "target": "~/.claude/skills/quill-components/reference/sidebar-nav.md"
        },
        {
          "path": "registry/agent-rules/skills/quill-components/reference/signup.md",
          "type": "registry:file",
          "target": "~/.claude/skills/quill-components/reference/signup.md"
        },
        {
          "path": "registry/agent-rules/skills/quill-components/reference/signup-social.md",
          "type": "registry:file",
          "target": "~/.claude/skills/quill-components/reference/signup-social.md"
        },
        {
          "path": "registry/agent-rules/skills/quill-components/reference/skeleton.md",
          "type": "registry:file",
          "target": "~/.claude/skills/quill-components/reference/skeleton.md"
        },
        {
          "path": "registry/agent-rules/skills/quill-components/reference/slider.md",
          "type": "registry:file",
          "target": "~/.claude/skills/quill-components/reference/slider.md"
        },
        {
          "path": "registry/agent-rules/skills/quill-components/reference/sonner.md",
          "type": "registry:file",
          "target": "~/.claude/skills/quill-components/reference/sonner.md"
        },
        {
          "path": "registry/agent-rules/skills/quill-components/reference/spinner.md",
          "type": "registry:file",
          "target": "~/.claude/skills/quill-components/reference/spinner.md"
        },
        {
          "path": "registry/agent-rules/skills/quill-components/reference/stat-cards.md",
          "type": "registry:file",
          "target": "~/.claude/skills/quill-components/reference/stat-cards.md"
        },
        {
          "path": "registry/agent-rules/skills/quill-components/reference/stats-band.md",
          "type": "registry:file",
          "target": "~/.claude/skills/quill-components/reference/stats-band.md"
        },
        {
          "path": "registry/agent-rules/skills/quill-components/reference/switch.md",
          "type": "registry:file",
          "target": "~/.claude/skills/quill-components/reference/switch.md"
        },
        {
          "path": "registry/agent-rules/skills/quill-components/reference/table.md",
          "type": "registry:file",
          "target": "~/.claude/skills/quill-components/reference/table.md"
        },
        {
          "path": "registry/agent-rules/skills/quill-components/reference/tabs.md",
          "type": "registry:file",
          "target": "~/.claude/skills/quill-components/reference/tabs.md"
        },
        {
          "path": "registry/agent-rules/skills/quill-components/reference/tabs-page.md",
          "type": "registry:file",
          "target": "~/.claude/skills/quill-components/reference/tabs-page.md"
        },
        {
          "path": "registry/agent-rules/skills/quill-components/reference/team-section.md",
          "type": "registry:file",
          "target": "~/.claude/skills/quill-components/reference/team-section.md"
        },
        {
          "path": "registry/agent-rules/skills/quill-components/reference/testimonial.md",
          "type": "registry:file",
          "target": "~/.claude/skills/quill-components/reference/testimonial.md"
        },
        {
          "path": "registry/agent-rules/skills/quill-components/reference/textarea.md",
          "type": "registry:file",
          "target": "~/.claude/skills/quill-components/reference/textarea.md"
        },
        {
          "path": "registry/agent-rules/skills/quill-components/reference/theme-selector.md",
          "type": "registry:file",
          "target": "~/.claude/skills/quill-components/reference/theme-selector.md"
        },
        {
          "path": "registry/agent-rules/skills/quill-components/reference/toggle.md",
          "type": "registry:file",
          "target": "~/.claude/skills/quill-components/reference/toggle.md"
        },
        {
          "path": "registry/agent-rules/skills/quill-components/reference/toggle-group.md",
          "type": "registry:file",
          "target": "~/.claude/skills/quill-components/reference/toggle-group.md"
        },
        {
          "path": "registry/agent-rules/skills/quill-components/reference/tone-badge.md",
          "type": "registry:file",
          "target": "~/.claude/skills/quill-components/reference/tone-badge.md"
        },
        {
          "path": "registry/agent-rules/skills/quill-components/reference/tooltip.md",
          "type": "registry:file",
          "target": "~/.claude/skills/quill-components/reference/tooltip.md"
        },
        {
          "path": "registry/agent-rules/skills/quill-components/reference/wizard.md",
          "type": "registry:file",
          "target": "~/.claude/skills/quill-components/reference/wizard.md"
        }
      ]
    },
    {
      "name": "check",
      "type": "registry:file",
      "title": "Quill check",
      "description": "A self-check an AI agent runs inside its app after changing UI: lists every place the code stepped outside Quill — stock Tailwind colours, raw colour values, bracket values where a token exists, retired names, classes that produce no CSS in this app — each with the fix to write. Generated from the design system.",
      "files": [
        {
          "path": "registry/check/quill-check.mjs",
          "type": "registry:file",
          "target": "~/scripts/quill-check.mjs"
        }
      ],
      "docs": "Installed to scripts/quill-check.mjs. Run `node scripts/quill-check.mjs` from the app root after every UI change and clear every finding; `--json` for tools, `--dir <path>` to narrow, `--include-ui` to scan the stock primitives, `--css <entry>` if the Tailwind entry is not app/globals.css. Re-run `npx shadcn@latest add @quill/check --overwrite` after each Quill release."
    },
    {
      "name": "activity-feed",
      "type": "registry:block",
      "title": "Activity feed",
      "description": "A card timeline of recent events — avatar, action text, and a relative timestamp per entry.",
      "meta": {
        "intent": [
          "data-display"
        ],
        "use_when": "You need to show a chronological history of what happened — recent events with who, what, and when.",
        "not_for": "the events need an unread/read state and a mark-all-read action, not just a read-only history → notifications; the events are really records you need to filter, sort, or act on, not just skim chronologically → data-table"
      },
      "registryDependencies": [
        "card",
        "avatar",
        "badge",
        "https://www.quilldesignsystem.com/r/icon.json"
      ],
      "files": [
        {
          "path": "registry/blocks/activity-feed.tsx",
          "type": "registry:component",
          "target": "components/quill/activity-feed.tsx"
        }
      ],
      "docs": "A card timeline of recent events — avatar, action text, and a relative timestamp per entry. Do: Use relative timestamps (\"2 hours ago\") for recent activity — they read faster than absolute dates. Don't: Force users to parse a full timestamp for something that happened minutes ago. Use notifications when the events need an unread/read state and a mark-all-read action, not just a read-only history. Use data-table when the events are really records you need to filter, sort, or act on, not just skim chronologically.",
      "categories": [
        "data-display"
      ]
    },
    {
      "name": "alerts",
      "type": "registry:block",
      "title": "Alert stack",
      "description": "A vertical stack of informational, success, and destructive alerts with icons.",
      "meta": {
        "intent": [
          "feedback"
        ],
        "use_when": "You need to surface inline status messages of varying severity (info, success, destructive) within a page.",
        "not_for": "the message is transient feedback about an action just taken — use a toast, not an inline alert → sonner; the message is site-wide and dismissible rather than local to a page section → announcement-banner; the \"message\" is really an empty view that needs an explanation and a call to action → empty-state"
      },
      "registryDependencies": [
        "alert",
        "https://www.quilldesignsystem.com/r/icon.json"
      ],
      "files": [
        {
          "path": "registry/blocks/alerts.tsx",
          "type": "registry:component",
          "target": "components/quill/alerts.tsx"
        }
      ],
      "docs": "A vertical stack of informational, success, and destructive alerts with icons. Do: Match severity to consequence: destructive for blocking errors, default for neutral information. Don't: Use destructive styling for emphasis on non-error messages. Use sonner when the message is transient feedback about an action just taken — use a toast, not an inline alert. Use announcement-banner when the message is site-wide and dismissible rather than local to a page section. Use empty-state when the \"message\" is really an empty view that needs an explanation and a call to action.",
      "categories": [
        "feedback"
      ]
    },
    {
      "name": "analytics-charts",
      "type": "registry:block",
      "title": "Analytics charts",
      "description": "A dashboard pair — an area chart of audience growth beside a bar chart of weekly sales, each on its own card.",
      "meta": {
        "intent": [
          "data-viz",
          "data-display"
        ],
        "use_when": "You need a dashboard view of trends over time — an area chart plus a bar chart on card surfaces.",
        "not_for": "you need at-a-glance numbers, not a trend shape — a single KPI reads faster as a number than a chart → stat-cards; the audience needs to inspect exact values per row, not the shape of change over time → data-table"
      },
      "registryDependencies": [
        "card",
        "chart",
        "badge"
      ],
      "files": [
        {
          "path": "registry/blocks/analytics-charts.tsx",
          "type": "registry:component",
          "target": "components/quill/analytics-charts.tsx"
        }
      ],
      "dependencies": [
        "recharts"
      ],
      "docs": "A dashboard pair — an area chart of audience growth beside a bar chart of weekly sales, each on its own card. Do: Color each series from the chart token set (--chart-1…--chart-5), assigned in a fixed order. Don't: Hardcode a raw accent pigment (--terracotta, --moss, --indigo…) for a series — some pairs are documented as failing colorblind-distinguishability. Do: Pair a multi-series chart with a ChartLegend, as the Audience chart does — color is tied to a series name in text, never left for the reader to infer. Don't: Ship a multi-series chart with no legend — color becomes the only signal distinguishing readers from subscribers. Use stat-cards when you need at-a-glance numbers, not a trend shape — a single KPI reads faster as a number than a chart. Use data-table when the audience needs to inspect exact values per row, not the shape of change over time.",
      "categories": [
        "data-viz",
        "data-display"
      ]
    },
    {
      "name": "announcement-banner",
      "type": "registry:block",
      "title": "Announcement banners",
      "description": "Two dismissible announcement banners — an inline bordered page banner and a full-bleed primary-color variant.",
      "meta": {
        "intent": [
          "feedback",
          "marketing"
        ],
        "use_when": "You need to announce something site-wide with a dismissible banner, either inline or full-bleed.",
        "not_for": "the message is local to a page section and tied to system status, not a site-wide announcement → alerts; the banner requires an explicit choice (accept/reject), not just a dismiss → cookie-consent"
      },
      "registryDependencies": [
        "badge",
        "button",
        "https://www.quilldesignsystem.com/r/icon.json"
      ],
      "files": [
        {
          "path": "registry/blocks/announcement-banner.tsx",
          "type": "registry:component",
          "target": "components/quill/announcement-banner.tsx"
        }
      ],
      "docs": "Two dismissible announcement banners — an inline bordered page banner and a full-bleed primary-color variant. Do: Give every banner variant its own dismiss button with a specific aria-label (e.g. \"Dismiss workshop banner\"), not a generic one. Don't: Ship a banner with no way to dismiss it, or multiple banners sharing one ambiguous \"Dismiss\" label. Use alerts when the message is local to a page section and tied to system status, not a site-wide announcement. Use cookie-consent when the banner requires an explicit choice (accept/reject), not just a dismiss.",
      "categories": [
        "feedback",
        "marketing"
      ]
    },
    {
      "name": "badge-on-card",
      "type": "registry:block",
      "title": "Badges on card",
      "description": "Default, secondary, and destructive badges shown together on a card surface.",
      "meta": {
        "intent": [
          "data-display"
        ],
        "use_when": "You need to show status or category badges attached to a content card.",
        "not_for": "you need a badge whose color is driven by a semantic tone token rather than the three fixed variants here → tone-badge; the badges are actually per-row status in a list of records, not a single card's labels → data-table"
      },
      "registryDependencies": [
        "card",
        "badge"
      ],
      "files": [
        {
          "path": "registry/blocks/badge-on-card.tsx",
          "type": "registry:component",
          "target": "components/quill/badge-on-card.tsx"
        }
      ],
      "docs": "Default, secondary, and destructive badges shown together on a card surface. Do: Reserve the destructive variant for a status that actually needs attention (blocked, failed, overdue). Don't: Use destructive styling for emphasis on a badge that isn't actually a warning. Use tone-badge when you need a badge whose color is driven by a semantic tone token rather than the three fixed variants here. Use data-table when the badges are actually per-row status in a list of records, not a single card's labels.",
      "categories": [
        "data-display"
      ]
    },
    {
      "name": "calendar-page",
      "type": "registry:block",
      "title": "Calendar page",
      "description": "A single-date calendar paired with the selected day's session list, in one studio-schedule card.",
      "meta": {
        "intent": [
          "scheduling"
        ],
        "use_when": "You need to pick a single date and show what's scheduled that day.",
        "not_for": "the user is booking a span of days, not viewing what's scheduled on one → calendar-range; you want a chronological history of past events, not a schedule of upcoming sessions tied to a picked date → activity-feed"
      },
      "registryDependencies": [
        "card",
        "calendar",
        "badge",
        "separator"
      ],
      "files": [
        {
          "path": "registry/blocks/calendar-page.tsx",
          "type": "registry:component",
          "target": "components/quill/calendar-page.tsx"
        }
      ],
      "docs": "A single-date calendar paired with the selected day's session list, in one studio-schedule card. Do: Keep the session list in sync with whatever date is selected in the calendar — the two panes are one control, not two independent widgets. Don't: Let the calendar selection and the listed sessions fall out of sync (e.g. a static list that ignores the picked date). Use calendar-range when the user is booking a span of days, not viewing what's scheduled on one. Use activity-feed when you want a chronological history of past events, not a schedule of upcoming sessions tied to a picked date.",
      "categories": [
        "scheduling"
      ]
    },
    {
      "name": "calendar-range",
      "type": "registry:block",
      "title": "Calendar range picker",
      "description": "A stateful two-month range calendar for booking a span of days, with clear and reserve actions.",
      "meta": {
        "intent": [
          "scheduling",
          "form"
        ],
        "use_when": "You need to book a span of days with a two-month range picker and confirm/clear actions.",
        "not_for": "the user is picking a single day to view, not a multi-day span to reserve → calendar-page; the range is just one field within a larger purchase flow, not the whole card → checkout"
      },
      "registryDependencies": [
        "card",
        "calendar",
        "button",
        "badge"
      ],
      "files": [
        {
          "path": "registry/blocks/calendar-range.tsx",
          "type": "registry:component",
          "target": "components/quill/calendar-range.tsx"
        }
      ],
      "dependencies": [
        "react-day-picker"
      ],
      "docs": "A stateful two-month range calendar for booking a span of days, with clear and reserve actions. Do: Keep the Clear action available whenever a range is selected, separate from Reserve. Don't: Force a user to re-click through the whole range to correct a mis-click — that's what Clear is for. Do: Disable Reserve until both a start and end date are selected. Don't: Let a half-made range (just a start date) submit as if it were a valid booking. Use calendar-page when the user is picking a single day to view, not a multi-day span to reserve. Use checkout when the range is just one field within a larger purchase flow, not the whole card.",
      "categories": [
        "scheduling",
        "form"
      ]
    },
    {
      "name": "ai-home",
      "type": "registry:block",
      "title": "AI home",
      "description": "An AI assistant's start page — a soft AI glow, a greeting, the large composer with Ask/Agent modes, and starter cards.",
      "meta": {
        "intent": [
          "ai"
        ],
        "use_when": "An app has a page whose main job is talking to its AI assistant, and people land on it with nothing typed yet.",
        "not_for": "you only need the box, inside a page that is about something else → prompt-composer; two people are messaging; there is no AI → chat"
      },
      "categories": [
        "ai"
      ],
      "registryDependencies": [
        "https://www.quilldesignsystem.com/r/prompt-composer.json",
        "https://www.quilldesignsystem.com/r/ai-mark.json"
      ],
      "files": [
        {
          "path": "registry/blocks/ai-home.tsx",
          "type": "registry:component",
          "target": "components/quill/ai-home.tsx"
        }
      ],
      "docs": "An AI assistant's start page — a soft AI glow, a greeting, the large composer with Ask/Agent modes, and starter cards. Do: Keep the AI glow to this one start page. Don't: Add the glow behind other sections or pages — it marks the AI home, and repeated it becomes decoration. Use prompt-composer when you only need the box, inside a page that is about something else. Use chat when two people are messaging; there is no AI."
    },
    {
      "name": "chat",
      "type": "registry:block",
      "title": "Chat panel",
      "description": "A one-on-one messaging panel — contact header, message bubbles, and a composer input.",
      "meta": {
        "intent": [
          "messaging"
        ],
        "use_when": "You need a one-on-one messaging panel with a contact header, bubbles, and a composer.",
        "not_for": "you need a list of conversations alongside the open thread, not just the single open thread → list-detail; the messages are one-way system alerts, not a two-way conversation with someone → notifications"
      },
      "registryDependencies": [
        "input",
        "button",
        "https://www.quilldesignsystem.com/r/icon.json"
      ],
      "files": [
        {
          "path": "registry/blocks/chat.tsx",
          "type": "registry:component",
          "target": "components/quill/chat.tsx"
        }
      ],
      "docs": "A one-on-one messaging panel — contact header, message bubbles, and a composer input. Do: Align the current user's messages to one side (right) and the other party's to the other (left) — position is the primary cue for who said what. Don't: Rely on color alone to distinguish sender — pair it with consistent alignment. Use list-detail when you need a list of conversations alongside the open thread, not just the single open thread. Use notifications when the messages are one-way system alerts, not a two-way conversation with someone.",
      "categories": [
        "messaging"
      ]
    },
    {
      "name": "checkout",
      "type": "registry:block",
      "title": "Checkout",
      "description": "A two-column checkout — payment method picker and card form beside an order summary sidebar.",
      "meta": {
        "intent": [
          "commerce",
          "form"
        ],
        "use_when": "You need to collect payment and card details alongside an order summary.",
        "not_for": "you only need the cart-review card, not the full payment form beside it → order-summary; payment is one step in a longer multi-step flow, not a single standalone page → wizard"
      },
      "registryDependencies": [
        "card",
        "input",
        "label",
        "button",
        "radio-group",
        "separator",
        "https://www.quilldesignsystem.com/r/icon.json"
      ],
      "files": [
        {
          "path": "registry/blocks/checkout.tsx",
          "type": "registry:component",
          "target": "components/quill/checkout.tsx"
        }
      ],
      "docs": "A two-column checkout — payment method picker and card form beside an order summary sidebar. Do: Use a RadioGroup for payment-method choice (Card/Bank/Wallet) — it's a single mutually exclusive choice, styled as cards. Don't: Use checkboxes or a dropdown for a single mutually exclusive payment method. Do: Pair the payment submit button with a lock icon, so the action itself visibly reads as a secure transaction. Don't: Ship the payment submit button with no lock icon — nothing on the button signals that submitting card data is secure. Use order-summary when you only need the cart-review card, not the full payment form beside it. Use wizard when payment is one step in a longer multi-step flow, not a single standalone page.",
      "categories": [
        "commerce",
        "form"
      ]
    },
    {
      "name": "command-palette",
      "type": "registry:block",
      "title": "Command palette",
      "description": "A searchable ⌘K command palette with grouped actions, recent items, and keyboard shortcuts.",
      "meta": {
        "intent": [
          "navigation"
        ],
        "use_when": "You need a searchable ⌘K launcher for actions and quick navigation.",
        "not_for": "search results should live inline on the page, not in a global keyboard-triggered overlay → search-results; the list of options is small and tied to a specific trigger element, not a global searchable launcher → dropdown-menu"
      },
      "registryDependencies": [
        "command",
        "https://www.quilldesignsystem.com/r/icon.json"
      ],
      "files": [
        {
          "path": "registry/blocks/command-palette.tsx",
          "type": "registry:component",
          "target": "components/quill/command-palette.tsx"
        }
      ],
      "docs": "A searchable ⌘K command palette with grouped actions, recent items, and keyboard shortcuts. Do: Group items into labeled sections (Actions, Recent) so a long list stays scannable. Don't: Dump every possible command into one flat, unlabeled list. Use search-results when search results should live inline on the page, not in a global keyboard-triggered overlay. Use dropdown-menu when the list of options is small and tied to a specific trigger element, not a global searchable launcher.",
      "categories": [
        "navigation"
      ]
    },
    {
      "name": "contact-form",
      "type": "registry:block",
      "title": "Contact form",
      "description": "A get-in-touch card — name, email, a topic select, and a message field.",
      "meta": {
        "intent": [
          "form"
        ],
        "use_when": "You need a get-in-touch form with name, email, topic, and message fields.",
        "not_for": "you only need a single email field to grow a list, not a full multi-field inquiry form → newsletter; the fields are updating an existing profile, not sending a one-off message → settings"
      },
      "registryDependencies": [
        "card",
        "input",
        "label",
        "button",
        "textarea",
        "select"
      ],
      "files": [
        {
          "path": "registry/blocks/contact-form.tsx",
          "type": "registry:component",
          "target": "components/quill/contact-form.tsx"
        }
      ],
      "docs": "A get-in-touch card — name, email, a topic select, and a message field. Do: State a response-time expectation in the description (\"We usually reply within one working day.\") so the form doesn't feel like it disappears into a void. Don't: Leave users with no sense of whether or when they'll hear back. Use newsletter when you only need a single email field to grow a list, not a full multi-field inquiry form. Use settings when the fields are updating an existing profile, not sending a one-off message.",
      "categories": [
        "form"
      ]
    },
    {
      "name": "cookie-consent",
      "type": "registry:block",
      "title": "Cookie consent",
      "description": "A cookie consent banner offering accept, reject, and preferences actions.",
      "meta": {
        "intent": [
          "feedback"
        ],
        "use_when": "You need a compliance banner offering accept, reject, and preferences choices.",
        "not_for": "the message is informational only and doesn't require an explicit accept/reject decision → announcement-banner; the message is a local, in-page status, not a site-wide compliance notice → alerts"
      },
      "registryDependencies": [
        "button",
        "https://www.quilldesignsystem.com/r/icon.json"
      ],
      "files": [
        {
          "path": "registry/blocks/cookie-consent.tsx",
          "type": "registry:component",
          "target": "components/quill/cookie-consent.tsx"
        }
      ],
      "docs": "A cookie consent banner offering accept, reject, and preferences actions. Do: \"Reject non-essential\" gets the same one-click ease as \"Accept all\" — both are top-level buttons, not one button plus a buried settings link. Don't: Make rejecting cookies harder to find or reach than accepting them — that's a dark pattern, not a real choice. Use announcement-banner when the message is informational only and doesn't require an explicit accept/reject decision. Use alerts when the message is a local, in-page status, not a site-wide compliance notice.",
      "categories": [
        "feedback"
      ]
    },
    {
      "name": "dashboard",
      "type": "registry:block",
      "title": "Dashboard shell",
      "description": "An app shell with sidebar navigation, a search header, and KPI stat cards.",
      "meta": {
        "intent": [
          "app-shell",
          "data-display"
        ],
        "use_when": "You need a full application home — sidebar, search header, and KPI cards.",
        "not_for": "you need the collapsible icon-sidebar variant with grouped menus, not this fixed-width text sidebar → sidebar-nav; you only need the KPI row, not the full shell around it → stat-cards"
      },
      "registryDependencies": [
        "button",
        "input",
        "badge",
        "card",
        "https://www.quilldesignsystem.com/r/icon.json"
      ],
      "files": [
        {
          "path": "registry/blocks/dashboard.tsx",
          "type": "registry:component",
          "target": "components/quill/dashboard.tsx"
        }
      ],
      "docs": "An app shell with sidebar navigation, a search header, and KPI stat cards. Do: Give the current nav item a distinct active state (background + text color), not just a subtle underline. Don't: Leave every nav item looking identical — users lose track of where they are. Use sidebar-nav when you need the collapsible icon-sidebar variant with grouped menus, not this fixed-width text sidebar. Use stat-cards when you only need the KPI row, not the full shell around it.",
      "categories": [
        "app-shell",
        "data-display"
      ]
    },
    {
      "name": "data-table",
      "type": "registry:block",
      "title": "Data table",
      "description": "A filterable members table with a toolbar, ToneBadge status pills, and a per-row actions menu.",
      "meta": {
        "intent": [
          "data-display"
        ],
        "use_when": "You need a filterable, actionable table of records with tone-mapped status pills and row actions.",
        "not_for": "you want a read-only chronological list, not sortable/filterable records with row actions → activity-feed; the records are better organized by status columns than by table rows → kanban"
      },
      "registryDependencies": [
        "table",
        "https://www.quilldesignsystem.com/r/tone-badge.json",
        "button",
        "input",
        "https://www.quilldesignsystem.com/r/icon.json"
      ],
      "files": [
        {
          "path": "registry/blocks/data-table.tsx",
          "type": "registry:component",
          "target": "components/quill/data-table.tsx"
        }
      ],
      "docs": "A filterable members table with a toolbar, ToneBadge status pills, and a per-row actions menu. Do: Give every icon-only row-action button a per-row aria-label (e.g. \"Actions for Ada Lovelace\"), not a generic one. Don't: Ship a table full of icon-only buttons that all announce as the same unlabeled button to a screen reader. Use activity-feed when you want a read-only chronological list, not sortable/filterable records with row actions. Use kanban when the records are better organized by status columns than by table rows.",
      "categories": [
        "data-display"
      ]
    },
    {
      "name": "empty-state",
      "type": "registry:block",
      "title": "Empty state",
      "description": "A dashed-border empty state with an icon, explanatory text, and a primary action.",
      "meta": {
        "intent": [
          "feedback"
        ],
        "use_when": "You need to explain why a view is empty and offer the primary action to fill it.",
        "not_for": "the view is empty because the resource doesn't exist or the route is wrong, not because the user hasn't created anything yet → error-404; there's a multi-step setup to walk through, not a single action to take right now → onboarding"
      },
      "registryDependencies": [
        "button",
        "https://www.quilldesignsystem.com/r/icon.json"
      ],
      "files": [
        {
          "path": "registry/blocks/empty-state.tsx",
          "type": "registry:component",
          "target": "components/quill/empty-state.tsx"
        }
      ],
      "docs": "A dashed-border empty state with an icon, explanatory text, and a primary action. Do: Pair the explanation with a real, primary action button that actually fills the view (e.g. \"New project\"). Don't: Explain that a view is empty and leave the user with no way to act on it from that screen. Use error-404 when the view is empty because the resource doesn't exist or the route is wrong, not because the user hasn't created anything yet. Use onboarding when there's a multi-step setup to walk through, not a single action to take right now.",
      "categories": [
        "feedback"
      ]
    },
    {
      "name": "error-404",
      "type": "registry:block",
      "title": "404 page",
      "description": "A full-page 404 error state with go-back and home recovery actions.",
      "meta": {
        "intent": [
          "feedback"
        ],
        "use_when": "You need a full-page not-found state with recovery actions.",
        "not_for": "the resource exists but is legitimately empty (no items yet), not missing or misrouted → empty-state; the error is recoverable inline on the current page, not a full-page dead end that needs its own route → alerts"
      },
      "registryDependencies": [
        "button",
        "https://www.quilldesignsystem.com/r/icon.json"
      ],
      "files": [
        {
          "path": "registry/blocks/error-404.tsx",
          "type": "registry:component",
          "target": "components/quill/error-404.tsx"
        }
      ],
      "docs": "A full-page 404 error state with go-back and home recovery actions. Do: Offer both a contextual escape (Go back) and an absolute one (Take me home) — never strand the user with only one recovery path. Don't: Leave a 404 page with no action at all, or only a single 'Home' link buried in a header the user has to hunt for. Use empty-state when the resource exists but is legitimately empty (no items yet), not missing or misrouted. Use alerts when the error is recoverable inline on the current page, not a full-page dead end that needs its own route.",
      "categories": [
        "feedback"
      ]
    },
    {
      "name": "faq",
      "type": "registry:block",
      "title": "FAQ section",
      "description": "A centered FAQ section — an accordion of common questions with a contact call-to-action footer.",
      "meta": {
        "intent": [
          "content",
          "marketing"
        ],
        "use_when": "You need to answer common questions in an accordion with a contact fallback.",
        "not_for": "you need a bare accordion with no marketing framing (heading, contact footer) around it → accordion; the user needs to ask something not covered — this pattern only offers a CTA button, not the form itself → contact-form"
      },
      "registryDependencies": [
        "accordion",
        "button"
      ],
      "files": [
        {
          "path": "registry/blocks/faq.tsx",
          "type": "registry:component",
          "target": "components/quill/faq.tsx"
        }
      ],
      "docs": "A centered FAQ section — an accordion of common questions with a contact call-to-action footer. Do: Open the first question by default (defaultValue=['item-0']) so the section doesn't read as empty on load. Don't: Start every item collapsed and force a first click just to prove the section has content. Use accordion when you need a bare accordion with no marketing framing (heading, contact footer) around it. Use contact-form when the user needs to ask something not covered — this pattern only offers a CTA button, not the form itself.",
      "categories": [
        "content",
        "marketing"
      ]
    },
    {
      "name": "feature-section",
      "type": "registry:block",
      "title": "Feature section",
      "description": "A marketing section with an editorial heading and a three-column feature grid.",
      "meta": {
        "intent": [
          "marketing"
        ],
        "use_when": "You need to present product features in an editorial multi-column grid.",
        "not_for": "you're presenting numbers, not descriptive feature callouts with icons and body text → stats-band; the features are tied to specific paid tiers, not the product as a whole → pricing"
      },
      "registryDependencies": [
        "https://www.quilldesignsystem.com/r/icon.json"
      ],
      "files": [
        {
          "path": "registry/blocks/feature-section.tsx",
          "type": "registry:component",
          "target": "components/quill/feature-section.tsx"
        }
      ],
      "docs": "A marketing section with an editorial heading and a three-column feature grid. Do: Keep the grid to three (or a multiple of three) features so it reads evenly across the row. Don't: Let an uneven feature count leave a dangling, unbalanced last row on wide screens. Use stats-band when you're presenting numbers, not descriptive feature callouts with icons and body text. Use pricing when the features are tied to specific paid tiers, not the product as a whole.",
      "categories": [
        "marketing"
      ]
    },
    {
      "name": "file-upload",
      "type": "registry:block",
      "title": "File upload",
      "description": "An asset-upload card with a drag-and-drop dropzone and a progress-tracked upload queue.",
      "meta": {
        "intent": [
          "form"
        ],
        "use_when": "You need drag-and-drop asset upload with a progress-tracked queue.",
        "not_for": "you need a single attachment inside a broader form, not a dedicated upload queue as the whole card → contact-form"
      },
      "registryDependencies": [
        "card",
        "button",
        "progress",
        "separator",
        "https://www.quilldesignsystem.com/r/icon.json"
      ],
      "files": [
        {
          "path": "registry/blocks/file-upload.tsx",
          "type": "registry:component",
          "target": "components/quill/file-upload.tsx"
        }
      ],
      "docs": "An asset-upload card with a drag-and-drop dropzone and a progress-tracked upload queue. Do: Make the dropzone a real, focusable <button> that also opens a file picker on click/Enter — never make drag-and-drop the only way in. Don't: Ship a dropzone that only responds to a pointer drag gesture. Do: Give each in-progress file its own progress bar, so users can see exactly how far each individual upload has gotten. Don't: Show one shared progress bar for the whole queue — users can't tell which file it belongs to or how far any single file has gotten. Use contact-form when you need a single attachment inside a broader form, not a dedicated upload queue as the whole card.",
      "categories": [
        "form"
      ]
    },
    {
      "name": "footer",
      "type": "registry:block",
      "title": "Site footer",
      "description": "A marketing footer with brand blurb, link columns, and legal links.",
      "meta": {
        "intent": [
          "marketing",
          "navigation"
        ],
        "use_when": "You need a site-wide footer with link columns, a brand blurb, and legal links.",
        "not_for": "the links are primary in-app navigation, not secondary site-wide links at the page's end → sidebar-nav; the links belong at the top of the page as primary navigation, not the bottom as reference → navbar"
      },
      "registryDependencies": [
        "separator"
      ],
      "files": [
        {
          "path": "registry/blocks/footer.tsx",
          "type": "registry:component",
          "target": "components/quill/footer.tsx"
        }
      ],
      "docs": "A marketing footer with brand blurb, link columns, and legal links. Do: Wrap each link column in its own <nav aria-label>, as this block already does, so screen-reader users can jump between them. Don't: Render link columns as bare, unlabeled <div> lists that all announce as one undifferentiated block. Do: Separate the bottom legal row (copyright, Privacy, Terms) from the link columns with a visible Separator, as this block does. Don't: Rely on extra margin alone with no divider — the legal row reads as just another link column, not a distinct footer end-cap. Use sidebar-nav when the links are primary in-app navigation, not secondary site-wide links at the page's end. Use navbar when the links belong at the top of the page as primary navigation, not the bottom as reference.",
      "categories": [
        "marketing",
        "navigation"
      ]
    },
    {
      "name": "forgot-password",
      "type": "registry:block",
      "title": "Forgot password",
      "description": "A password-reset request card — an email field, a send-link action, and a way back to sign in.",
      "meta": {
        "intent": [
          "auth"
        ],
        "use_when": "You need a password-reset request card that sends a recovery link.",
        "not_for": "recovery works by a typed one-time code rather than an emailed link → otp-verification; the user hasn't actually forgotten anything — this card is only the detour reached from login's \"Forgot your password?\" link → login"
      },
      "registryDependencies": [
        "card",
        "input",
        "label",
        "button",
        "https://www.quilldesignsystem.com/r/icon.json"
      ],
      "files": [
        {
          "path": "registry/blocks/forgot-password.tsx",
          "type": "registry:component",
          "target": "components/quill/forgot-password.tsx"
        }
      ],
      "docs": "A password-reset request card — an email field, a send-link action, and a way back to sign in. Do: Keep the ghost \"Back to sign in\" button so a user who clicked in by mistake isn't stuck. Don't: Ship this card as a dead end with no return path to sign-in. Use otp-verification when recovery works by a typed one-time code rather than an emailed link. Use login when the user hasn't actually forgotten anything — this card is only the detour reached from login's \"Forgot your password?\" link.",
      "categories": [
        "auth"
      ]
    },
    {
      "name": "hero",
      "type": "registry:block",
      "title": "Hero",
      "description": "A centered marketing hero — a release badge, serif headline, supporting copy, and primary/secondary calls to action.",
      "meta": {
        "intent": [
          "marketing"
        ],
        "use_when": "You need the top-of-page marketing statement — headline, supporting copy, and calls to action.",
        "not_for": "you're past the opening statement and need to break down specific product capabilities → feature-section; the message is a small, dismissible update, not the page's primary opening statement → announcement-banner"
      },
      "registryDependencies": [
        "badge",
        "button",
        "https://www.quilldesignsystem.com/r/icon.json"
      ],
      "files": [
        {
          "path": "registry/blocks/hero.tsx",
          "type": "registry:component",
          "target": "components/quill/hero.tsx"
        }
      ],
      "docs": "A centered marketing hero — a release badge, serif headline, supporting copy, and primary/secondary calls to action. Do: Keep exactly one primary (default-variant) button — the single most important action — with any secondary action as outline/ghost. Don't: Give two calls-to-action equal visual weight; competing primaries dilute the one action that matters most. Use feature-section when you're past the opening statement and need to break down specific product capabilities. Use announcement-banner when the message is a small, dismissible update, not the page's primary opening statement.",
      "categories": [
        "marketing"
      ]
    },
    {
      "name": "invoice",
      "type": "registry:block",
      "title": "Invoice",
      "description": "A printable invoice card — sender and recipient details, a ToneBadge payment status, a line-item table with totals, and a download action.",
      "meta": {
        "intent": [
          "commerce",
          "data-display"
        ],
        "use_when": "You need a printable invoice with parties, line-item totals, and a download action.",
        "not_for": "you're showing a cart before payment, not a record of a completed transaction → order-summary; you need a list of many invoices to browse, not the full detail of one → data-table"
      },
      "registryDependencies": [
        "card",
        "table",
        "https://www.quilldesignsystem.com/r/tone-badge.json",
        "button",
        "separator",
        "https://www.quilldesignsystem.com/r/icon.json"
      ],
      "files": [
        {
          "path": "registry/blocks/invoice.tsx",
          "type": "registry:component",
          "target": "components/quill/invoice.tsx"
        }
      ],
      "docs": "A printable invoice card — sender and recipient details, a ToneBadge payment status, a line-item table with totals, and a download action. Do: Keep the total in a table footer, visually distinct from line items (its own row, right-aligned). Don't: Let the total blend in as just another line item — it needs to read as the sum, not another charge. Use order-summary when you're showing a cart before payment, not a record of a completed transaction. Use data-table when you need a list of many invoices to browse, not the full detail of one.",
      "categories": [
        "commerce",
        "data-display"
      ]
    },
    {
      "name": "kanban",
      "type": "registry:block",
      "title": "Kanban board",
      "description": "A three-column kanban board with card counts, tagged task cards, and an add-card affordance per column.",
      "meta": {
        "intent": [
          "productivity"
        ],
        "use_when": "You need to manage work across status columns with draggable, tagged task cards.",
        "not_for": "status is one column among many sortable fields — a table reads better than columns once you need to sort or filter across many records → data-table; the steps are a single sequential checklist, not parallel work items across independent columns → onboarding"
      },
      "registryDependencies": [
        "badge",
        "https://www.quilldesignsystem.com/r/icon.json"
      ],
      "files": [
        {
          "path": "registry/blocks/kanban.tsx",
          "type": "registry:component",
          "target": "components/quill/kanban.tsx"
        }
      ],
      "docs": "A three-column kanban board with card counts, tagged task cards, and an add-card affordance per column. Do: Keep each column's card-count badge in sync with its actual card list — it's a running total, not a caption. Don't: Let the count badge drift out of sync when cards move between columns. Use data-table when status is one column among many sortable fields — a table reads better than columns once you need to sort or filter across many records. Use onboarding when the steps are a single sequential checklist, not parallel work items across independent columns.",
      "categories": [
        "productivity"
      ]
    },
    {
      "name": "list-detail",
      "type": "registry:block",
      "title": "List + detail",
      "description": "An inbox-style split view — a selectable message list beside a detail pane with archive and delete actions.",
      "meta": {
        "intent": [
          "messaging",
          "app-shell"
        ],
        "use_when": "You need an inbox-style split view pairing a selectable list with a detail pane.",
        "not_for": "you need a fuller mail client — search, reply composer, forward — not just list-and-read → mail-shell; the conversation is a live back-and-forth thread, not discrete messages you select and read one at a time → chat"
      },
      "registryDependencies": [
        "badge",
        "button",
        "separator",
        "https://www.quilldesignsystem.com/r/icon.json"
      ],
      "files": [
        {
          "path": "registry/blocks/list-detail.tsx",
          "type": "registry:component",
          "target": "components/quill/list-detail.tsx"
        }
      ],
      "docs": "An inbox-style split view — a selectable message list beside a detail pane with archive and delete actions. Do: Keep the selected thread visually marked in the list (background fill) while its detail is open, so context isn't lost. Don't: Let the list's selection state go stale or unmarked once a thread is open in the detail pane. Use mail-shell when you need a fuller mail client — search, reply composer, forward — not just list-and-read. Use chat when the conversation is a live back-and-forth thread, not discrete messages you select and read one at a time.",
      "categories": [
        "messaging",
        "app-shell"
      ]
    },
    {
      "name": "login",
      "type": "registry:block",
      "title": "Login",
      "description": "The standard email-and-password sign-in card, with remember-me and a forgot-password escape hatch.",
      "meta": {
        "intent": [
          "auth"
        ],
        "use_when": "You need the standard email-and-password sign-in with remember-me and reset links.",
        "not_for": "the sign-in is a full page, not an embedded card, and you want a branded testimonial panel alongside it → login-split-panel; you want the leanest possible sign-in — a single email field for a one-time code, no password at all → login-minimal; most of your users sign in through Google, GitHub, or Apple rather than a password you store → login-oauth; the user has already clicked \"Forgot your password?\" — that's a separate card, not a state of this one → forgot-password"
      },
      "registryDependencies": [
        "card",
        "input",
        "label",
        "button",
        "checkbox"
      ],
      "files": [
        {
          "path": "registry/blocks/login.tsx",
          "type": "registry:component",
          "target": "components/quill/login.tsx"
        }
      ],
      "docs": "The standard email-and-password sign-in card, with remember-me and a forgot-password escape hatch. Do: Treat \"Remember me\" as extending session length, never as the only thing standing between a device and the account. Don't: Rely on the remember-me checkbox as a security boundary. Do: Style \"Forgot your password?\" as a link beneath \"Sign in\" — one unmistakable primary action per card. Don't: Give \"Forgot your password?\" the same solid button treatment as \"Sign in\" — now two buttons compete to be primary. Use login-split-panel when the sign-in is a full page, not an embedded card, and you want a branded testimonial panel alongside it. Use login-minimal when you want the leanest possible sign-in — a single email field for a one-time code, no password at all. Use login-oauth when most of your users sign in through Google, GitHub, or Apple rather than a password you store. Use forgot-password when the user has already clicked \"Forgot your password?\" — that's a separate card, not a state of this one.",
      "categories": [
        "auth"
      ]
    },
    {
      "name": "login-minimal",
      "type": "registry:block",
      "title": "Minimal login",
      "description": "The bare-minimum sign-in — no card chrome, a single email field, sign-in by one-time code.",
      "meta": {
        "intent": [
          "auth"
        ],
        "use_when": "You need the leanest possible sign-in — one email field that sends a one-time code, no password.",
        "not_for": "you're collecting a password, not sending a one-time code — this pattern has no password field at all → login; you want a provider-first flow instead of email-only → login-oauth; the user already submitted their email and you're now showing the six-digit code entry — that's a separate step from this one → otp-verification"
      },
      "registryDependencies": [
        "input",
        "label",
        "button",
        "https://www.quilldesignsystem.com/r/icon.json"
      ],
      "files": [
        {
          "path": "registry/blocks/login-minimal.tsx",
          "type": "registry:component",
          "target": "components/quill/login-minimal.tsx"
        }
      ],
      "docs": "The bare-minimum sign-in — no card chrome, a single email field, sign-in by one-time code. Do: Reserve the bare, uncontained layout for cases where the surrounding page or modal already frames it. Don't: Drop this pattern directly onto a busy page background with nothing to separate it visually. Use login when you're collecting a password, not sending a one-time code — this pattern has no password field at all. Use login-oauth when you want a provider-first flow instead of email-only. Use otp-verification when the user already submitted their email and you're now showing the six-digit code entry — that's a separate step from this one.",
      "categories": [
        "auth"
      ]
    },
    {
      "name": "login-oauth",
      "type": "registry:block",
      "title": "Login with OAuth providers",
      "description": "Provider-first sign-in — Google, GitHub, and Apple buttons above an email fallback.",
      "registryDependencies": [
        "input",
        "label",
        "button",
        "separator"
      ],
      "files": [
        {
          "path": "registry/blocks/login-oauth.tsx",
          "target": "components/quill/login-oauth.tsx",
          "type": "registry:component"
        }
      ],
      "meta": {
        "intent": [
          "auth"
        ],
        "use_when": "Identity comes from a provider (Google, GitHub, Apple) rather than a password you store.",
        "not_for": "this is account creation, not sign-in — signup-social also leads with OAuth providers → signup-social; you store first-party passwords and don't want a provider-first order at all → login; you don't have OAuth providers configured and just need a single email field → login-minimal"
      },
      "docs": "Provider-first sign-in — Google, GitHub, and Apple buttons above an email fallback. Do: Treat the provider buttons as the primary path; keep the email form below the rule as a fallback, not the headline. Don't: Give the email field equal visual weight to the provider buttons when most users have a provider account. Do: Keep provider marks as their official inlined artwork, with GitHub and Apple taking currentColor so they invert correctly in Dusk. Don't: Restyle a provider mark to match your palette — that breaks the brand guidelines you agree to by using their sign-in. Use signup-social when this is account creation, not sign-in — signup-social also leads with OAuth providers. Use login when you store first-party passwords and don't want a provider-first order at all. Use login-minimal when you don't have OAuth providers configured and just need a single email field.",
      "categories": [
        "auth"
      ]
    },
    {
      "name": "login-split-panel",
      "type": "registry:block",
      "title": "Login with split panel",
      "description": "A full-page, branded sign-in — a testimonial panel beside an email/password form with a magic-link option.",
      "meta": {
        "intent": [
          "auth",
          "marketing"
        ],
        "use_when": "You need a branded full-page sign-in with a testimonial side panel and magic-link option.",
        "not_for": "the sign-in is an embedded card inside an existing page shell, not its own full page → login; you don't have a testimonial or brand story worth the real estate — go bare instead → login-minimal"
      },
      "registryDependencies": [
        "input",
        "label",
        "button",
        "separator",
        "https://www.quilldesignsystem.com/r/icon.json"
      ],
      "files": [
        {
          "path": "registry/blocks/login-split-panel.tsx",
          "type": "registry:component",
          "target": "components/quill/login-split-panel.tsx"
        }
      ],
      "docs": "A full-page, branded sign-in — a testimonial panel beside an email/password form with a magic-link option. Do: Let the brand panel drop out on small viewports and let the form take the full width. Don't: Force the two-column grid at phone widths — the testimonial panel has no room to be legible. Use login when the sign-in is an embedded card inside an existing page shell, not its own full page. Use login-minimal when you don't have a testimonial or brand story worth the real estate — go bare instead.",
      "categories": [
        "auth",
        "marketing"
      ]
    },
    {
      "name": "mail-shell",
      "type": "registry:block",
      "title": "Mail inbox shell",
      "description": "A two-pane mail client shell — a searchable message list and a reading pane with toolbar and inline reply.",
      "meta": {
        "intent": [
          "messaging",
          "app-shell"
        ],
        "use_when": "You need a two-pane mail client — searchable list plus a reading pane with toolbar and reply.",
        "not_for": "you need the simpler read-and-select pattern with no search, toolbar, or reply composer → list-detail; the messaging is a live conversational thread, not discrete emails with subjects → chat"
      },
      "registryDependencies": [
        "badge",
        "button",
        "input",
        "label",
        "separator",
        "avatar",
        "https://www.quilldesignsystem.com/r/icon.json"
      ],
      "files": [
        {
          "path": "registry/blocks/mail-shell.tsx",
          "type": "registry:component",
          "target": "components/quill/mail-shell.tsx"
        }
      ],
      "docs": "A two-pane mail client shell — a searchable message list and a reading pane with toolbar and inline reply. Do: Hide the reading pane on narrow viewports so the message list gets the full width instead of squeezing both panes. Don't: Force the two-pane layout at phone widths where neither pane has room to be usable. Use list-detail when you need the simpler read-and-select pattern with no search, toolbar, or reply composer. Use chat when the messaging is a live conversational thread, not discrete emails with subjects.",
      "categories": [
        "messaging",
        "app-shell"
      ]
    },
    {
      "name": "navbar",
      "type": "registry:block",
      "title": "Navbar",
      "description": "A top navigation bar with brand wordmark, a responsive link list, and sign-in / get-started actions.",
      "meta": {
        "intent": [
          "navigation"
        ],
        "use_when": "You need a top navigation bar with wordmark, links, and sign-in / get-started actions.",
        "not_for": "primary navigation belongs in a persistent side rail for an app, not a top bar for a marketing site → sidebar-nav; navigation is keyboard-driven and searchable, not a fixed row of links → command-palette"
      },
      "registryDependencies": [
        "button",
        "https://www.quilldesignsystem.com/r/icon.json"
      ],
      "files": [
        {
          "path": "registry/blocks/navbar.tsx",
          "type": "registry:component",
          "target": "components/quill/navbar.tsx"
        }
      ],
      "docs": "A top navigation bar with brand wordmark, a responsive link list, and sign-in / get-started actions. Do: Keep \"Get started\" as the one default-variant (primary) button; \"Sign in\" stays ghost so it doesn't compete. Don't: Style both actions as equally prominent primary buttons. Use sidebar-nav when primary navigation belongs in a persistent side rail for an app, not a top bar for a marketing site. Use command-palette when navigation is keyboard-driven and searchable, not a fixed row of links.",
      "categories": [
        "navigation"
      ]
    },
    {
      "name": "theme-selector",
      "type": "registry:block",
      "title": "Theme selector",
      "description": "A dropdown picker for the five Quill themes and four pigment accents — sets data-theme/data-accent and persists both to localStorage.",
      "meta": {
        "intent": [
          "settings"
        ],
        "use_when": "You need to let users switch among Quill's five themes and four accents, persisted to localStorage.",
        "not_for": "theme choice is one field among many in a broader preferences form, not a standalone quick-switch control → settings"
      },
      "registryDependencies": [
        "button",
        "dropdown-menu",
        "https://www.quilldesignsystem.com/r/icon.json"
      ],
      "files": [
        {
          "path": "registry/blocks/theme-selector.tsx",
          "type": "registry:component",
          "target": "components/quill/theme-selector.tsx"
        }
      ],
      "docs": "A dropdown picker for the five Quill themes and four pigment accents — sets data-theme/data-accent and persists both to localStorage. Do: Read the persisted theme/accent from localStorage in an effect, after mount — never during render, or prerendered markup mismatches the client. Don't: Read localStorage synchronously during render; that guarantees a hydration mismatch since the server always renders Dawn/moss. Do: Show a color swatch next to each accent option in the menu, as this picker does, so people see the actual hue before picking it. Don't: List accent names as plain text with no swatch, forcing a guess at what \"Terracotta\" or \"Indigo\" actually look like. Use settings when theme choice is one field among many in a broader preferences form, not a standalone quick-switch control.",
      "categories": [
        "settings"
      ]
    },
    {
      "name": "newsletter",
      "type": "registry:block",
      "title": "Newsletter signup",
      "description": "A centered newsletter-signup section — an email field, subscribe action, and social proof.",
      "meta": {
        "intent": [
          "marketing",
          "form"
        ],
        "use_when": "You need an email-capture section with social proof to grow a list.",
        "not_for": "you need more than an email — name, topic, a message — this pattern is intentionally a single field → contact-form; the signup is one small element within a full site footer, not its own standalone section → footer"
      },
      "registryDependencies": [
        "input",
        "label",
        "button",
        "https://www.quilldesignsystem.com/r/icon.json"
      ],
      "files": [
        {
          "path": "registry/blocks/newsletter.tsx",
          "type": "registry:component",
          "target": "components/quill/newsletter.tsx"
        }
      ],
      "docs": "A centered newsletter-signup section — an email field, subscribe action, and social proof. Do: Say plainly what subscribers are signing up for and that they can leave any time (\"No spam, no noise — unsubscribe any time.\"). Don't: Ask for an email with no context on frequency or an easy way out. Use contact-form when you need more than an email — name, topic, a message — this pattern is intentionally a single field. Use footer when the signup is one small element within a full site footer, not its own standalone section.",
      "categories": [
        "marketing",
        "form"
      ]
    },
    {
      "name": "notifications",
      "type": "registry:block",
      "title": "Notifications",
      "description": "A notifications card listing recent events with icons, timestamps, unread indicators, and a mark-all-read action.",
      "meta": {
        "intent": [
          "feedback",
          "data-display"
        ],
        "use_when": "You need a notifications center with unread indicators and a mark-all-read action.",
        "not_for": "the list is a read-only history with no read/unread state or mark-all action → activity-feed; the message is transient feedback about something that just happened — use a toast, not a persistent notifications list → sonner"
      },
      "registryDependencies": [
        "card",
        "button",
        "separator",
        "https://www.quilldesignsystem.com/r/icon.json"
      ],
      "files": [
        {
          "path": "registry/blocks/notifications.tsx",
          "type": "registry:component",
          "target": "components/quill/notifications.tsx"
        }
      ],
      "docs": "A notifications card listing recent events with icons, timestamps, unread indicators, and a mark-all-read action. Do: Pair the unread dot with a real accessible label (role=\"img\" aria-label=\"Unread\"), as this block already does. Don't: Ship an unread indicator that's purely decorative with no accessible signal. Do: Give each notification an icon that matches its content (a person icon for membership events, a check for successful deploys) so the list can be scanned by icon alone. Don't: Reuse one generic bell icon for every notification regardless of type, forcing people to read each title just to tell them apart. Use activity-feed when the list is a read-only history with no read/unread state or mark-all action. Use sonner when the message is transient feedback about something that just happened — use a toast, not a persistent notifications list.",
      "categories": [
        "feedback",
        "data-display"
      ]
    },
    {
      "name": "onboarding",
      "type": "registry:block",
      "title": "Onboarding checklist",
      "description": "A setup checklist card with a progress bar, completed and pending tasks, and start links for remaining steps.",
      "meta": {
        "intent": [
          "productivity"
        ],
        "use_when": "You need a setup checklist that tracks progress and links to remaining steps.",
        "not_for": "the steps must happen in a strict sequence in one sitting, not a checklist a user dips in and out of over time → wizard; there's a single action to take, not a multi-step checklist to track → empty-state"
      },
      "registryDependencies": [
        "card",
        "button",
        "https://www.quilldesignsystem.com/r/icon.json"
      ],
      "files": [
        {
          "path": "registry/blocks/onboarding.tsx",
          "type": "registry:component",
          "target": "components/quill/onboarding.tsx"
        }
      ],
      "docs": "A setup checklist card with a progress bar, completed and pending tasks, and start links for remaining steps. Do: Pair the visual progress bar with a text fraction (\"2 of 4 complete\") so the state isn't conveyed by bar width alone. Don't: Show only a progress bar with no numeric readout of how much is actually done. Use wizard when the steps must happen in a strict sequence in one sitting, not a checklist a user dips in and out of over time. Use empty-state when there's a single action to take, not a multi-step checklist to track.",
      "categories": [
        "productivity"
      ]
    },
    {
      "name": "order-summary",
      "type": "registry:block",
      "title": "Order summary",
      "description": "A checkout order-summary card — line items, a promo code field, a total, and a pay-now button.",
      "meta": {
        "intent": [
          "commerce"
        ],
        "use_when": "You need a cart-review card with line items, a promo field, a total, and a pay button.",
        "not_for": "you're showing a record of a completed, already-paid transaction, not a cart pending payment → invoice; you need the full payment form (card fields, billing address) alongside the summary, not just the review → checkout"
      },
      "registryDependencies": [
        "card",
        "button",
        "input",
        "separator",
        "https://www.quilldesignsystem.com/r/icon.json"
      ],
      "files": [
        {
          "path": "registry/blocks/order-summary.tsx",
          "type": "registry:component",
          "target": "components/quill/order-summary.tsx"
        }
      ],
      "docs": "A checkout order-summary card — line items, a promo code field, a total, and a pay-now button. Do: Recompute the total the instant a promo code applies or a line item changes — never leave a stale total on screen after an update. Don't: Require a page refresh or separate action to see the corrected total. Do: Show an applied promo as its own line item with the discount amount, so the line items and the total add up to the same number. Don't: Let the total drop after a promo applies with no corresponding line item — buyers can't verify what changed. Use invoice when you're showing a record of a completed, already-paid transaction, not a cart pending payment. Use checkout when you need the full payment form (card fields, billing address) alongside the summary, not just the review.",
      "categories": [
        "commerce"
      ]
    },
    {
      "name": "otp-verification",
      "type": "registry:block",
      "title": "OTP verification",
      "description": "A six-digit one-time-passcode entry card for verifying an email, with expiry messaging and a resend action.",
      "meta": {
        "intent": [
          "auth"
        ],
        "use_when": "You need to verify an email with a six-digit one-time passcode and resend.",
        "not_for": "you're sending the initial one-time code, not verifying a code the user already received — that's a separate step upstream of this card → login-minimal; recovery works by emailed link, not a typed code → forgot-password"
      },
      "registryDependencies": [
        "card",
        "input-otp",
        "label",
        "button"
      ],
      "files": [
        {
          "path": "registry/blocks/otp-verification.tsx",
          "type": "registry:component",
          "target": "components/quill/otp-verification.tsx"
        }
      ],
      "docs": "A six-digit one-time-passcode entry card for verifying an email, with expiry messaging and a resend action. Do: State the code's expiry window in the card body (\"expires in 10 minutes\"), not just in the email. Don't: Leave users guessing why a code that worked a moment ago now fails. Use login-minimal when you're sending the initial one-time code, not verifying a code the user already received — that's a separate step upstream of this card. Use forgot-password when recovery works by emailed link, not a typed code.",
      "categories": [
        "auth"
      ]
    },
    {
      "name": "page-header",
      "type": "registry:block",
      "title": "Page header",
      "description": "A page header with a breadcrumb trail, title and description, and duplicate/new action buttons.",
      "meta": {
        "intent": [
          "navigation",
          "app-shell"
        ],
        "use_when": "You need a screen header with breadcrumbs, title, description, and primary actions.",
        "not_for": "you need the breadcrumb as part of a full app shell's top bar, not a standalone header block → sidebar-nav; this is a marketing page's opening statement, not a utility screen's title bar → hero"
      },
      "registryDependencies": [
        "breadcrumb",
        "button",
        "https://www.quilldesignsystem.com/r/icon.json"
      ],
      "files": [
        {
          "path": "registry/blocks/page-header.tsx",
          "type": "registry:component",
          "target": "components/quill/page-header.tsx"
        }
      ],
      "docs": "A page header with a breadcrumb trail, title and description, and duplicate/new action buttons. Do: Render the current page as BreadcrumbPage (plain text), not a link — you can't navigate to where you already are. Don't: Make every breadcrumb crumb, including the current page, a clickable link. Use sidebar-nav when you need the breadcrumb as part of a full app shell's top bar, not a standalone header block. Use hero when this is a marketing page's opening statement, not a utility screen's title bar.",
      "categories": [
        "navigation",
        "app-shell"
      ]
    },
    {
      "name": "pricing",
      "type": "registry:block",
      "title": "Pricing",
      "description": "A three-tier pricing grid with a highlighted popular plan, feature checklists, and per-plan calls to action.",
      "meta": {
        "intent": [
          "marketing",
          "commerce"
        ],
        "use_when": "You need a tiered pricing grid with a highlighted plan and feature checklists.",
        "not_for": "you're describing capabilities in general, not comparing specific paid tiers against each other → feature-section; the user has already chosen a plan and is now reviewing a specific purchase, not comparing options → order-summary"
      },
      "registryDependencies": [
        "card",
        "button",
        "badge",
        "https://www.quilldesignsystem.com/r/icon.json"
      ],
      "files": [
        {
          "path": "registry/blocks/pricing.tsx",
          "type": "registry:component",
          "target": "components/quill/pricing.tsx"
        }
      ],
      "docs": "A three-tier pricing grid with a highlighted popular plan, feature checklists, and per-plan calls to action. Do: Mark exactly one plan as featured (ring + Popular badge) to guide the decision. Don't: Feature more than one plan, or none — either dilutes the recommendation this pattern exists to make. Use feature-section when you're describing capabilities in general, not comparing specific paid tiers against each other. Use order-summary when the user has already chosen a plan and is now reviewing a specific purchase, not comparing options.",
      "categories": [
        "marketing",
        "commerce"
      ]
    },
    {
      "name": "profile-card",
      "type": "registry:block",
      "title": "Profile card",
      "description": "A compact, centered profile card — avatar initials, role, follower stats, and follow/message actions.",
      "meta": {
        "intent": [
          "data-display"
        ],
        "use_when": "You need a compact user profile with avatar, role, stats, and follow / message actions.",
        "not_for": "you want to show what someone did, not a static summary of who they are → activity-feed; you're listing many people at once — a table or list reads better than a full card per person → data-table"
      },
      "registryDependencies": [
        "card",
        "button",
        "badge",
        "separator",
        "https://www.quilldesignsystem.com/r/icon.json"
      ],
      "files": [
        {
          "path": "registry/blocks/profile-card.tsx",
          "type": "registry:component",
          "target": "components/quill/profile-card.tsx"
        }
      ],
      "docs": "A compact, centered profile card — avatar initials, role, follower stats, and follow/message actions. Do: Label every stat (\"Followers\", \"Following\") directly beneath its number — a bare number has no meaning on its own. Don't: Show raw numbers with no label and expect position alone to convey what they mean. Use activity-feed when you want to show what someone did, not a static summary of who they are. Use data-table when you're listing many people at once — a table or list reads better than a full card per person.",
      "categories": [
        "data-display"
      ]
    },
    {
      "name": "search-results",
      "type": "registry:block",
      "title": "Search results",
      "description": "A docs search panel — query input, result count, and a linked result list with breadcrumbs and type badges.",
      "meta": {
        "intent": [
          "navigation",
          "data-display"
        ],
        "use_when": "You need a search panel with a query input, result count, and a linked result list.",
        "not_for": "search is a global, keyboard-triggered overlay (⌘K) rather than an inline panel on the page → command-palette; results are structured records with multiple sortable columns, not a simple linked list → data-table"
      },
      "registryDependencies": [
        "input",
        "badge",
        "separator",
        "https://www.quilldesignsystem.com/r/icon.json"
      ],
      "files": [
        {
          "path": "registry/blocks/search-results.tsx",
          "type": "registry:component",
          "target": "components/quill/search-results.tsx"
        }
      ],
      "docs": "A docs search panel — query input, result count, and a linked result list with breadcrumbs and type badges. Do: State the result count in visible text (\"4 results for \\\"token\\\"\") so users know the query actually ran. Don't: Leave users guessing whether zero results means the search hasn't run yet or genuinely found nothing. Use command-palette when search is a global, keyboard-triggered overlay (⌘K) rather than an inline panel on the page. Use data-table when results are structured records with multiple sortable columns, not a simple linked list.",
      "categories": [
        "navigation",
        "data-display"
      ]
    },
    {
      "name": "settings",
      "type": "registry:block",
      "title": "Settings form",
      "description": "A profile settings card — name fields, a bio textarea, and an email-notification toggle.",
      "meta": {
        "intent": [
          "settings",
          "form"
        ],
        "use_when": "You need a profile settings form with name, bio, and notification preferences.",
        "not_for": "you're sending a one-off message, not editing a persistent profile → contact-form; setup needs multiple sequential steps, not a single settings page a user returns to and edits freely → wizard"
      },
      "registryDependencies": [
        "card",
        "input",
        "textarea",
        "label",
        "button",
        "switch",
        "separator"
      ],
      "files": [
        {
          "path": "registry/blocks/settings.tsx",
          "type": "registry:component",
          "target": "components/quill/settings.tsx"
        }
      ],
      "docs": "A profile settings card — name fields, a bio textarea, and an email-notification toggle. Do: Keep Save changes and Cancel as two distinct, clearly differentiated actions (primary vs ghost). Don't: Make Cancel look as prominent as Save — the user should never mis-tap away unsaved changes as the default action. Use contact-form when you're sending a one-off message, not editing a persistent profile. Use wizard when setup needs multiple sequential steps, not a single settings page a user returns to and edits freely.",
      "categories": [
        "settings",
        "form"
      ]
    },
    {
      "name": "sidebar-nav",
      "type": "registry:block",
      "title": "Sidebar navigation shell",
      "description": "A collapsible icon-sidebar app shell with grouped menus, badges, a top bar, and a main area for the page — a card grid by default, or the children you pass in.",
      "meta": {
        "intent": [
          "app-shell",
          "navigation"
        ],
        "use_when": "You need a collapsible icon-sidebar app shell with grouped menus and a content area.",
        "not_for": "you need a simpler, fixed-width text sidebar without the icon-collapse behavior → dashboard; the main content area is a two-pane message list/reading layout, not a card grid → mail-shell"
      },
      "registryDependencies": [
        "sidebar",
        "breadcrumb",
        "avatar",
        "separator",
        "card",
        "https://www.quilldesignsystem.com/r/icon.json"
      ],
      "files": [
        {
          "path": "registry/blocks/sidebar-nav.tsx",
          "type": "registry:component",
          "target": "components/quill/sidebar-nav.tsx"
        }
      ],
      "docs": "A collapsible icon-sidebar app shell with grouped menus, badges, a top bar, and a main area for the page — a card grid by default, or the children you pass in. Do: Group sidebar items under labeled sections (e.g. \"Workspace\", \"Studio\"), as this block already does, rather than one long flat list. Don't: List every nav item at the same level with no grouping once the count grows past a handful. Use dashboard when you need a simpler, fixed-width text sidebar without the icon-collapse behavior. Use mail-shell when the main content area is a two-pane message list/reading layout, not a card grid.",
      "categories": [
        "app-shell",
        "navigation"
      ]
    },
    {
      "name": "signup",
      "type": "registry:block",
      "title": "Sign up",
      "description": "Standard account-creation card — name, email, password, and a link back to sign-in.",
      "meta": {
        "intent": [
          "auth"
        ],
        "use_when": "You need standard account creation — name, email, password, and a sign-in link.",
        "not_for": "you want OAuth providers to lead instead of a bare email/password form → signup-social; the user already has an account — this card is only for new ones → login"
      },
      "registryDependencies": [
        "card",
        "input",
        "label",
        "button"
      ],
      "files": [
        {
          "path": "registry/blocks/signup.tsx",
          "type": "registry:component",
          "target": "components/quill/signup.tsx"
        }
      ],
      "docs": "Standard account-creation card — name, email, password, and a link back to sign-in. Do: Use the description line to state what happens next (trial length, no card required) so the form isn't just fields with no context. Don't: Leave the card as a bare field list with no framing for why someone would fill it out. Use signup-social when you want OAuth providers to lead instead of a bare email/password form. Use login when the user already has an account — this card is only for new ones.",
      "categories": [
        "auth"
      ]
    },
    {
      "name": "signup-social",
      "type": "registry:block",
      "title": "Signup — social first",
      "description": "Signup that leads with GitHub and Google provider buttons, falling back to an email/password form.",
      "meta": {
        "intent": [
          "auth"
        ],
        "use_when": "You need signup that leads with OAuth providers and falls back to email/password.",
        "not_for": "you don't have OAuth providers configured, or want email/password as the primary path, not a fallback → signup; this is sign-in, not new-account creation — login-oauth is the matching pattern for returning users → login-oauth"
      },
      "registryDependencies": [
        "card",
        "input",
        "label",
        "button",
        "separator"
      ],
      "files": [
        {
          "path": "registry/blocks/signup-social.tsx",
          "type": "registry:component",
          "target": "components/quill/signup-social.tsx"
        }
      ],
      "docs": "Signup that leads with GitHub and Google provider buttons, falling back to an email/password form. Do: Put the provider buttons above the divider and the email/password fields below it, matching login-oauth's provider-first order. Don't: Bury the provider buttons below a full email/password form — that defeats the point of offering them. Use signup when you don't have OAuth providers configured, or want email/password as the primary path, not a fallback. Use login-oauth when this is sign-in, not new-account creation — login-oauth is the matching pattern for returning users.",
      "categories": [
        "auth"
      ]
    },
    {
      "name": "stat-cards",
      "type": "registry:block",
      "title": "Stat cards",
      "description": "A responsive grid of KPI cards, each showing a value with a delta badge versus last month.",
      "meta": {
        "intent": [
          "data-display"
        ],
        "use_when": "You need a row of KPI cards showing values with period-over-period deltas.",
        "not_for": "you need to show the trend shape over time, not just the current value and one delta → analytics-charts; you have more metrics than fit comfortably in a card grid, or need to compare many rows at once → data-table"
      },
      "registryDependencies": [
        "card",
        "badge"
      ],
      "files": [
        {
          "path": "registry/blocks/stat-cards.tsx",
          "type": "registry:component",
          "target": "components/quill/stat-cards.tsx"
        }
      ],
      "docs": "A responsive grid of KPI cards, each showing a value with a delta badge versus last month. Do: Match badge tone to whether the delta is actually good news for that metric (e.g. rising churn is bad, so it gets destructive tone even though the number itself looks like growth). Don't: Default every rising number to a positive tone — a rising \"Open tickets\" count is bad news, not good. Use analytics-charts when you need to show the trend shape over time, not just the current value and one delta. Use data-table when you have more metrics than fit comfortably in a card grid, or need to compare many rows at once.",
      "categories": [
        "data-display"
      ]
    },
    {
      "name": "stats-band",
      "type": "registry:block",
      "title": "Stats band",
      "description": "A marketing band of headline statistics separated by vertical dividers on a card background.",
      "meta": {
        "intent": [
          "marketing"
        ],
        "use_when": "You need a marketing band of headline statistics separated by dividers.",
        "not_for": "each number needs its own card with a period-over-period delta — this pattern is a single flat band with no per-item chrome or comparison → stat-cards; you're describing capabilities, not reporting numbers → feature-section"
      },
      "registryDependencies": [
        "separator"
      ],
      "files": [
        {
          "path": "registry/blocks/stats-band.tsx",
          "type": "registry:component",
          "target": "components/quill/stats-band.tsx"
        }
      ],
      "docs": "A marketing band of headline statistics separated by vertical dividers on a card background. Do: Color headline numbers from the accent's TEXT cut (--accent-pigment-text), so they follow the page's data-accent and still clear WCAG contrast on every ground. Don't: Use --accent-pigment for text. That is the decorative cut: on a Dawn card it is 2.9:1 for moss (the default accent) and 2.1:1 for gold, both under the 3:1 large-text minimum. It is also what --link and --ring already avoid. And never hardcode a fixed pigment (e.g. --terracotta) — that breaks the moment a consumer sets a different accent. Do: Pair every headline number with its own visible label directly beneath it (e.g. \"Components\"), as every stat in this band does. Don't: Ship a bare number with no label — a viewer has no way to tell what it counts. Use stat-cards when each number needs its own card with a period-over-period delta — this pattern is a single flat band with no per-item chrome or comparison. Use feature-section when you're describing capabilities, not reporting numbers.",
      "categories": [
        "marketing"
      ]
    },
    {
      "name": "tabs-page",
      "type": "registry:block",
      "title": "Tabs page",
      "description": "A tabbed settings page with account, notifications, and security panels.",
      "meta": {
        "intent": [
          "navigation",
          "settings"
        ],
        "use_when": "You need a settings screen split into account, notifications, and security tabs.",
        "not_for": "everything fits on one page without needing to split into separate tabbed sections → settings; the sections are sequential setup steps completed once, not independent settings a user revisits and edits freely → wizard"
      },
      "registryDependencies": [
        "tabs",
        "card",
        "input",
        "label",
        "switch"
      ],
      "files": [
        {
          "path": "registry/blocks/tabs-page.tsx",
          "type": "registry:component",
          "target": "components/quill/tabs-page.tsx"
        }
      ],
      "docs": "A tabbed settings page with account, notifications, and security panels. Do: Keep each TabsTrigger's `value` identical to its TabsContent's `value` when you rename a section (here, `account`/`notifications`), so the tab a user lands on always has a panel to show. Don't: Rename a TabsTrigger's `value` (e.g. Notifications → Alerts) without updating its TabsContent to match — the renamed tab still highlights as active since its own value is valid, but the panel underneath renders empty because no content shares that value anymore. Use settings when everything fits on one page without needing to split into separate tabbed sections. Use wizard when the sections are sequential setup steps completed once, not independent settings a user revisits and edits freely.",
      "categories": [
        "navigation",
        "settings"
      ]
    },
    {
      "name": "team-section",
      "type": "registry:block",
      "title": "Team section",
      "description": "A marketing team grid with avatar cards showing each member's name, role, specialty badge, and email action.",
      "meta": {
        "intent": [
          "marketing"
        ],
        "use_when": "You need a marketing team grid with member cards, roles, and contact actions.",
        "not_for": "you're showing one person in detail (stats, follow/message), not a grid of many team members at a glance → profile-card; you're quoting what someone said, not introducing who's on the team → testimonial"
      },
      "registryDependencies": [
        "card",
        "avatar",
        "badge",
        "button",
        "https://www.quilldesignsystem.com/r/icon.json"
      ],
      "files": [
        {
          "path": "registry/blocks/team-section.tsx",
          "type": "registry:component",
          "target": "components/quill/team-section.tsx"
        }
      ],
      "docs": "A marketing team grid with avatar cards showing each member's name, role, specialty badge, and email action. Do: Give every team member their own contact action, labeled with their name (e.g. \"Email Ada Lovelace\"). Don't: Ship one generic \"Contact us\" action for the whole grid — it defeats the point of a per-person team grid. Use profile-card when you're showing one person in detail (stats, follow/message), not a grid of many team members at a glance. Use testimonial when you're quoting what someone said, not introducing who's on the team.",
      "categories": [
        "marketing"
      ]
    },
    {
      "name": "testimonial",
      "type": "registry:block",
      "title": "Testimonial",
      "description": "A customer-quote card with a serif pull-quote, avatar initials, and attribution.",
      "meta": {
        "intent": [
          "marketing",
          "content"
        ],
        "use_when": "You need a customer-quote card with a serif pull-quote and attribution.",
        "not_for": "you're introducing people, not quoting what a customer said about the product → team-section; the proof point is a number, not a quote → stats-band"
      },
      "registryDependencies": [],
      "files": [
        {
          "path": "registry/blocks/testimonial.tsx",
          "type": "registry:component",
          "target": "components/quill/testimonial.tsx"
        }
      ],
      "docs": "A customer-quote card with a serif pull-quote, avatar initials, and attribution. Do: Pair every quote with a real name, role, and organization — an anonymous quote reads as unverifiable. Don't: Ship a testimonial with no attribution, or attribution too small/muted to actually read. Use team-section when you're introducing people, not quoting what a customer said about the product. Use stats-band when the proof point is a number, not a quote.",
      "categories": [
        "marketing",
        "content"
      ]
    },
    {
      "name": "wizard",
      "type": "registry:block",
      "title": "Setup wizard step",
      "description": "A multi-step setup card — a progress stepper, workspace fields, and back/continue navigation.",
      "meta": {
        "intent": [
          "form",
          "productivity"
        ],
        "use_when": "You need a multi-step setup flow with a progress stepper and back/continue navigation.",
        "not_for": "the steps are a checklist of tasks to complete over time, not a linear form flow completed in one sitting → onboarding; there's only one step and no sequence to track — this is a single settings page, not a flow → settings"
      },
      "registryDependencies": [
        "card",
        "input",
        "label",
        "button",
        "https://www.quilldesignsystem.com/r/icon.json"
      ],
      "files": [
        {
          "path": "registry/blocks/wizard.tsx",
          "type": "registry:component",
          "target": "components/quill/wizard.tsx"
        }
      ],
      "docs": "A multi-step setup card — a progress stepper, workspace fields, and back/continue navigation. Do: Show every step in the stepper up front (done/current/todo), so users know how much is left. Don't: Reveal steps one at a time with no sense of total progress. Use onboarding when the steps are a checklist of tasks to complete over time, not a linear form flow completed in one sitting. Use settings when there's only one step and no sequence to track — this is a single settings page, not a flow.",
      "categories": [
        "form",
        "productivity"
      ]
    }
  ]
}