{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://taste-hq.vercel.app/schema/grammar-v2.json",
  "title": "tasteHQ Design Grammar v2.0",
  "description": "Evaluation specification for all 30 taste axes. Defines valid values, ordinal mappings, extraction method, and per-axis metadata. Pin this version in audit blocks. For the validation-only grammar schema used in brand entries, see brand-style-v2.json#/$defs/grammar.",
  "version": "2.0.0",
  "released": "2026-05-17",
  "minimum_graded_axes": 15,
  "richly_graded_threshold": 25,
  "scoring_note": "Ordinal axes: distance is meaningful; use c_a = clip(1 - |b_a - o_a| / max_grade, 0, 1). Nominal axes: use binary match (match=1, mismatch=0) until a proximity_matrix is published for that axis. Scale type is encoded per axis.",
  "categories": [
    "surface",
    "palette",
    "type",
    "emphasis",
    "whitespace",
    "voice",
    "motion",
    "imagery"
  ],
  "axes": [
    {
      "key": "surface.ground",
      "category": "surface",
      "ordinal_position": 1,
      "label": "Page ground",
      "description": "Dominant page-background color family.",
      "rubric_summary": "Open homepage. Sample largest background area. Map to nearest family.",
      "scale": "nominal",
      "values": [
        "white",
        "cream",
        "gray-light",
        "gray-dark",
        "black",
        "warm-tinted",
        "cool-tinted"
      ],
      "ordinal_map": {
        "white": 1,
        "cream": 2,
        "warm-tinted": 3,
        "gray-light": 4,
        "cool-tinted": 5,
        "gray-dark": 6,
        "black": 7
      },
      "extraction": "deterministic",
      "convergence_prior": null,
      "examples": [
        {
          "brand": "anthropic",
          "value": "cream"
        },
        {
          "brand": "linear",
          "value": "black"
        },
        {
          "brand": "stripe",
          "value": "white"
        }
      ]
    },
    {
      "key": "surface.radius",
      "category": "surface",
      "ordinal_position": 2,
      "label": "Corner radius",
      "description": "Corner radius regime for buttons, cards, inputs.",
      "rubric_summary": "Inspect primary CTA + content card. Dominant one wins. pill = ≥ half height.",
      "scale": "ordinal",
      "values": [
        "0px",
        "4-6px",
        "8-10px",
        "12-16px",
        "pill"
      ],
      "ordinal_map": {
        "0px": 1,
        "4-6px": 2,
        "8-10px": 3,
        "12-16px": 4,
        "pill": 5
      },
      "extraction": "deterministic",
      "convergence_prior": null,
      "examples": [
        {
          "brand": "acne-studios",
          "value": "0px"
        },
        {
          "brand": "anthropic",
          "value": "8-10px"
        },
        {
          "brand": "stripe",
          "value": "4-6px"
        }
      ]
    },
    {
      "key": "surface.borders",
      "category": "surface",
      "ordinal_position": 3,
      "label": "Border philosophy",
      "description": "Border presence and weight across cards, sections, dividers.",
      "rubric_summary": "hairline = 1px subtle. medium = 1-2px visible. heavy = ≥2px or high-contrast.",
      "scale": "ordinal",
      "values": [
        "none",
        "hairline",
        "medium",
        "heavy"
      ],
      "ordinal_map": {
        "none": 1,
        "hairline": 2,
        "medium": 3,
        "heavy": 4
      },
      "extraction": "deterministic",
      "convergence_prior": null,
      "examples": [
        {
          "brand": "apple",
          "value": "none"
        },
        {
          "brand": "linear",
          "value": "hairline"
        },
        {
          "brand": "faculty-department",
          "value": "hairline"
        }
      ]
    },
    {
      "key": "surface.shadows",
      "category": "surface",
      "ordinal_position": 4,
      "label": "Shadow / elevation",
      "description": "Shadow usage as a depth signal.",
      "rubric_summary": "subtle = barely-perceptible blur. layered = clear stack. dramatic = strong drop.",
      "scale": "ordinal",
      "values": [
        "none",
        "subtle",
        "layered",
        "dramatic"
      ],
      "ordinal_map": {
        "none": 1,
        "subtle": 2,
        "layered": 3,
        "dramatic": 4
      },
      "extraction": "deterministic",
      "convergence_prior": null,
      "examples": [
        {
          "brand": "anthropic",
          "value": "none"
        },
        {
          "brand": "stripe",
          "value": "subtle"
        },
        {
          "brand": "apple",
          "value": "subtle"
        }
      ]
    },
    {
      "key": "surface.texture",
      "category": "surface",
      "ordinal_position": 5,
      "label": "Surface texture",
      "description": "Hero background treatment type.",
      "rubric_summary": "flat = solid. grain = subtle noise. gradient = linear blend. mesh = multi-stop. photo = photographic.",
      "scale": "nominal",
      "values": [
        "flat",
        "grain",
        "gradient",
        "mesh",
        "photo"
      ],
      "ordinal_map": {
        "flat": 1,
        "grain": 2,
        "gradient": 3,
        "mesh": 4,
        "photo": 5
      },
      "extraction": "model_graded",
      "convergence_prior": null,
      "examples": [
        {
          "brand": "linear",
          "value": "flat"
        },
        {
          "brand": "stripe",
          "value": "mesh"
        },
        {
          "brand": "mercury",
          "value": "photo"
        }
      ]
    },
    {
      "key": "surface.dark_mode",
      "category": "surface",
      "ordinal_position": 6,
      "label": "Dark mode handling",
      "description": "How dark mode is implemented.",
      "rubric_summary": "inversion = flipped colors. custom-palette = curated dark palette. dark-first = primary surface is dark.",
      "scale": "nominal",
      "values": [
        "none",
        "system-adaptive",
        "inversion",
        "custom-palette",
        "dark-first"
      ],
      "ordinal_map": {
        "none": 1,
        "system-adaptive": 2,
        "inversion": 3,
        "custom-palette": 4,
        "dark-first": 5
      },
      "extraction": "deterministic",
      "convergence_prior": null,
      "examples": [
        {
          "brand": "stripe",
          "value": "none"
        },
        {
          "brand": "anthropic",
          "value": "custom-palette"
        },
        {
          "brand": "linear",
          "value": "dark-first"
        }
      ]
    },
    {
      "key": "palette.strategy",
      "category": "palette",
      "ordinal_position": 7,
      "label": "Color strategy",
      "description": "Number of distinct chromatic families in active use.",
      "rubric_summary": "Count chromatic colors (not greys). mono=0, mono+1=1 accent, full-spectrum=≥4 families.",
      "scale": "ordinal",
      "values": [
        "mono",
        "mono+1",
        "duotone",
        "triadic",
        "full-spectrum"
      ],
      "ordinal_map": {
        "mono": 1,
        "mono+1": 2,
        "duotone": 3,
        "triadic": 4,
        "full-spectrum": 5
      },
      "extraction": "deterministic",
      "convergence_prior": null,
      "examples": [
        {
          "brand": "anthropic",
          "value": "mono+1"
        },
        {
          "brand": "stripe",
          "value": "full-spectrum"
        },
        {
          "brand": "acne-studios",
          "value": "mono+1"
        }
      ]
    },
    {
      "key": "palette.saturation",
      "category": "palette",
      "ordinal_position": 8,
      "label": "Accent saturation",
      "description": "Overall saturation of accent / chromatic colors.",
      "rubric_summary": "Eyeball accent HSL S. <20%=desaturated, 20-50%=muted, 50-80%=balanced, 80-100%=vivid, 100%+bright=neon.",
      "scale": "ordinal",
      "values": [
        "desaturated",
        "muted",
        "balanced",
        "vivid",
        "neon"
      ],
      "ordinal_map": {
        "desaturated": 1,
        "muted": 2,
        "balanced": 3,
        "vivid": 4,
        "neon": 5
      },
      "extraction": "deterministic",
      "convergence_prior": null,
      "examples": [
        {
          "brand": "anthropic",
          "value": "muted"
        },
        {
          "brand": "antimetal",
          "value": "neon"
        },
        {
          "brand": "stripe",
          "value": "balanced"
        }
      ]
    },
    {
      "key": "palette.warmth",
      "category": "palette",
      "ordinal_position": 9,
      "label": "Color temperature",
      "description": "Color temperature bias of the dominant palette.",
      "rubric_summary": "Hue dominance: blues/greens=cool, reds/oranges/yellows=warm, grey balance=neutral, both ends=mixed.",
      "scale": "nominal",
      "values": [
        "cool",
        "neutral",
        "warm",
        "mixed"
      ],
      "ordinal_map": {
        "cool": 1,
        "neutral": 2,
        "warm": 3,
        "mixed": 4
      },
      "extraction": "deterministic",
      "convergence_prior": null,
      "examples": [
        {
          "brand": "anthropic",
          "value": "warm"
        },
        {
          "brand": "stripe",
          "value": "cool"
        },
        {
          "brand": "linear",
          "value": "cool"
        }
      ]
    },
    {
      "key": "palette.accent_use",
      "category": "palette",
      "ordinal_position": 10,
      "label": "Accent frequency",
      "description": "How often the accent color appears.",
      "rubric_summary": "rare-signal=1-3 instances, recurring=disciplined throughout, pervasive=ambient (gradient hero, repeat CTA).",
      "scale": "ordinal",
      "values": [
        "rare-signal",
        "recurring",
        "pervasive"
      ],
      "ordinal_map": {
        "rare-signal": 1,
        "recurring": 2,
        "pervasive": 3
      },
      "extraction": "deterministic",
      "convergence_prior": null,
      "examples": [
        {
          "brand": "linear",
          "value": "rare-signal"
        },
        {
          "brand": "anthropic",
          "value": "recurring"
        },
        {
          "brand": "stripe",
          "value": "pervasive"
        }
      ]
    },
    {
      "key": "palette.contrast",
      "category": "palette",
      "ordinal_position": 11,
      "label": "Text contrast",
      "description": "Text-on-ground contrast ratio (WCAG-style).",
      "rubric_summary": "Read body copy. low=<4.5:1, medium=4.5-7, high=7-12, extreme=>12.",
      "scale": "ordinal",
      "values": [
        "low",
        "medium",
        "high",
        "extreme"
      ],
      "ordinal_map": {
        "low": 1,
        "medium": 2,
        "high": 3,
        "extreme": 4
      },
      "extraction": "deterministic",
      "convergence_prior": null,
      "examples": [
        {
          "brand": "anthropic",
          "value": "high"
        },
        {
          "brand": "linear",
          "value": "medium"
        },
        {
          "brand": "acne-studios",
          "value": "extreme"
        }
      ]
    },
    {
      "key": "type.pairing",
      "category": "type",
      "ordinal_position": 12,
      "label": "Typeface pairing",
      "description": "Dominant typeface pairing pattern.",
      "rubric_summary": "Identify display + body face. grotesque = neutral neo-grotesque (Inter, Söhne). single-family = one family for all.",
      "scale": "nominal",
      "values": [
        "serif/sans",
        "sans/sans",
        "sans/mono",
        "serif/grotesque",
        "grotesque/mono",
        "single-family"
      ],
      "ordinal_map": {
        "single-family": 1,
        "sans/sans": 2,
        "grotesque/mono": 3,
        "sans/mono": 4,
        "serif/grotesque": 5,
        "serif/sans": 6
      },
      "extraction": "mixed",
      "convergence_prior": null,
      "examples": [
        {
          "brand": "anthropic",
          "value": "serif/sans"
        },
        {
          "brand": "stripe",
          "value": "sans/sans"
        },
        {
          "brand": "antimetal",
          "value": "grotesque/mono"
        }
      ]
    },
    {
      "key": "type.heading_weight",
      "category": "type",
      "ordinal_position": 13,
      "label": "Display heading weight",
      "description": "Weight regime for primary display headlines.",
      "rubric_summary": "Inspect hero h1. ultralight=100-200, light=300-330, regular=400, medium=500-550, bold=600-700, black=800-900.",
      "scale": "ordinal",
      "values": [
        "ultralight",
        "light",
        "regular",
        "medium",
        "bold",
        "black"
      ],
      "ordinal_map": {
        "ultralight": 1,
        "light": 2,
        "regular": 3,
        "medium": 4,
        "bold": 5,
        "black": 6
      },
      "extraction": "deterministic",
      "convergence_prior": null,
      "examples": [
        {
          "brand": "anthropic",
          "value": "light"
        },
        {
          "brand": "linear",
          "value": "medium"
        },
        {
          "brand": "apple",
          "value": "regular"
        }
      ]
    },
    {
      "key": "type.body_size",
      "category": "type",
      "ordinal_position": 14,
      "label": "Body text size",
      "description": "Body text size class.",
      "rubric_summary": "Measure. small=≤14px, regular=15-17px, large=≥18px.",
      "scale": "ordinal",
      "values": [
        "small",
        "regular",
        "large"
      ],
      "ordinal_map": {
        "small": 1,
        "regular": 2,
        "large": 3
      },
      "extraction": "deterministic",
      "convergence_prior": null,
      "examples": [
        {
          "brand": "linear",
          "value": "small"
        },
        {
          "brand": "anthropic",
          "value": "regular"
        },
        {
          "brand": "acne-studios",
          "value": "large"
        }
      ]
    },
    {
      "key": "type.display_scale",
      "category": "type",
      "ordinal_position": 15,
      "label": "Display-to-body scale ratio",
      "description": "Display headline size relative to body text.",
      "rubric_summary": "compact=display ≤3× body, balanced=3-5×, oversized=≥5× (cinematic).",
      "scale": "ordinal",
      "values": [
        "compact",
        "balanced",
        "oversized"
      ],
      "ordinal_map": {
        "compact": 1,
        "balanced": 2,
        "oversized": 3
      },
      "extraction": "deterministic",
      "convergence_prior": null,
      "examples": [
        {
          "brand": "linear",
          "value": "compact"
        },
        {
          "brand": "stripe",
          "value": "balanced"
        },
        {
          "brand": "acne-studios",
          "value": "oversized"
        }
      ]
    },
    {
      "key": "type.tracking",
      "category": "type",
      "ordinal_position": 16,
      "label": "Display tracking",
      "description": "Letter-spacing on display type.",
      "rubric_summary": "Inspect hero h1. negative=≤-0.04em, tight=-0.01 to -0.03, normal=0, loose=≥0.02em.",
      "scale": "ordinal",
      "values": [
        "negative",
        "tight",
        "normal",
        "loose"
      ],
      "ordinal_map": {
        "negative": 1,
        "tight": 2,
        "normal": 3,
        "loose": 4
      },
      "extraction": "deterministic",
      "convergence_prior": null,
      "examples": [
        {
          "brand": "anthropic",
          "value": "negative"
        },
        {
          "brand": "linear",
          "value": "tight"
        },
        {
          "brand": "stripe",
          "value": "normal"
        }
      ]
    },
    {
      "key": "emphasis.mechanism",
      "category": "emphasis",
      "ordinal_position": 17,
      "label": "Emphasis device",
      "description": "Primary device used to emphasize a word or phrase.",
      "rubric_summary": "Read body copy + headings. Note what marks emphasis. Pick dominant device.",
      "scale": "nominal",
      "values": [
        "weight",
        "color",
        "underline",
        "scale",
        "spacing"
      ],
      "ordinal_map": {
        "weight": 1,
        "color": 2,
        "underline": 3,
        "scale": 4,
        "spacing": 5
      },
      "extraction": "model_graded",
      "convergence_prior": null,
      "examples": [
        {
          "brand": "anthropic",
          "value": "underline"
        },
        {
          "brand": "linear",
          "value": "weight"
        },
        {
          "brand": "stripe",
          "value": "color"
        }
      ]
    },
    {
      "key": "emphasis.cta_treatment",
      "category": "emphasis",
      "ordinal_position": 18,
      "label": "Primary CTA treatment",
      "description": "Visual treatment of the primary call-to-action.",
      "rubric_summary": "Find the primary action on the homepage hero. Map to nearest treatment.",
      "scale": "ordinal",
      "values": [
        "underline-only",
        "text-link",
        "outlined",
        "filled-solid",
        "filled-gradient"
      ],
      "ordinal_map": {
        "underline-only": 1,
        "text-link": 2,
        "outlined": 3,
        "filled-solid": 4,
        "filled-gradient": 5
      },
      "extraction": "mixed",
      "convergence_prior": null,
      "examples": [
        {
          "brand": "anthropic",
          "value": "filled-solid"
        },
        {
          "brand": "stripe",
          "value": "filled-gradient"
        },
        {
          "brand": "acne-studios",
          "value": "text-link"
        }
      ]
    },
    {
      "key": "emphasis.density_signals",
      "category": "emphasis",
      "ordinal_position": 19,
      "label": "Section density signals",
      "description": "How structural sections and density transitions are signaled.",
      "rubric_summary": "Look at section transitions. What separates section A from section B?",
      "scale": "nominal",
      "values": [
        "dividers",
        "whitespace",
        "borders",
        "grouping-cards"
      ],
      "ordinal_map": {
        "whitespace": 1,
        "dividers": 2,
        "borders": 3,
        "grouping-cards": 4
      },
      "extraction": "model_graded",
      "convergence_prior": null,
      "examples": [
        {
          "brand": "faculty-department",
          "value": "dividers"
        },
        {
          "brand": "apple",
          "value": "whitespace"
        },
        {
          "brand": "stripe",
          "value": "grouping-cards"
        }
      ]
    },
    {
      "key": "whitespace.discipline",
      "category": "whitespace",
      "ordinal_position": 20,
      "label": "Whitespace generosity",
      "description": "Overall whitespace generosity.",
      "rubric_summary": "dense=packed (Bloomberg). medium=balanced SaaS. generous=editorial. extreme=museum / runway.",
      "scale": "ordinal",
      "values": [
        "dense",
        "medium",
        "generous",
        "extreme"
      ],
      "ordinal_map": {
        "dense": 1,
        "medium": 2,
        "generous": 3,
        "extreme": 4
      },
      "extraction": "mixed",
      "convergence_prior": null,
      "examples": [
        {
          "brand": "antimetal",
          "value": "dense"
        },
        {
          "brand": "anthropic",
          "value": "generous"
        },
        {
          "brand": "acne-studios",
          "value": "extreme"
        }
      ]
    },
    {
      "key": "whitespace.section_gap",
      "category": "whitespace",
      "ordinal_position": 21,
      "label": "Section gap",
      "description": "Vertical gap between major page sections.",
      "rubric_summary": "Measure. compact=≤48px, balanced=64-120px, grand=≥160px.",
      "scale": "ordinal",
      "values": [
        "compact",
        "balanced",
        "grand"
      ],
      "ordinal_map": {
        "compact": 1,
        "balanced": 2,
        "grand": 3
      },
      "extraction": "deterministic",
      "convergence_prior": null,
      "examples": [
        {
          "brand": "antimetal",
          "value": "compact"
        },
        {
          "brand": "linear",
          "value": "balanced"
        },
        {
          "brand": "apple",
          "value": "grand"
        }
      ]
    },
    {
      "key": "whitespace.element_gap",
      "category": "whitespace",
      "ordinal_position": 22,
      "label": "Element gap",
      "description": "Gap between elements within a section.",
      "rubric_summary": "Inspect feature card grid. Measure inter-element gap. tight=≤16px, medium=24-32px, airy=≥40px.",
      "scale": "ordinal",
      "values": [
        "tight",
        "medium",
        "airy"
      ],
      "ordinal_map": {
        "tight": 1,
        "medium": 2,
        "airy": 3
      },
      "extraction": "deterministic",
      "convergence_prior": null,
      "examples": [
        {
          "brand": "linear",
          "value": "medium"
        },
        {
          "brand": "anthropic",
          "value": "medium"
        },
        {
          "brand": "acne-studios",
          "value": "airy"
        }
      ]
    },
    {
      "key": "voice.archetype",
      "category": "voice",
      "ordinal_position": 23,
      "label": "Voice archetype",
      "description": "Persona of the documentation / marketing voice.",
      "rubric_summary": "Read 5 sample sentences. Who would say this? Use 'generic' when the brand has a clear voice but no dominant archetype (heal_entry default).",
      "scale": "nominal",
      "values": [
        "librarian",
        "engineer",
        "artist",
        "friend",
        "concierge",
        "curator",
        "challenger",
        "generic"
      ],
      "ordinal_map": {
        "librarian": 1,
        "engineer": 2,
        "artist": 3,
        "friend": 4,
        "concierge": 5,
        "curator": 6,
        "challenger": 7,
        "generic": 0
      },
      "extraction": "model_graded",
      "convergence_prior": null,
      "examples": [
        {
          "brand": "anthropic",
          "value": "librarian"
        },
        {
          "brand": "linear",
          "value": "engineer"
        },
        {
          "brand": "acne-studios",
          "value": "artist"
        }
      ]
    },
    {
      "key": "voice.formality",
      "category": "voice",
      "ordinal_position": 24,
      "label": "Voice formality",
      "description": "Formality register of the copy.",
      "rubric_summary": "Count contractions, second-person, sentence fragments. Heavy=casual, rare=formal.",
      "scale": "ordinal",
      "values": [
        "casual",
        "conversational",
        "professional",
        "formal"
      ],
      "ordinal_map": {
        "casual": 1,
        "conversational": 2,
        "professional": 3,
        "formal": 4
      },
      "extraction": "mixed",
      "convergence_prior": null,
      "examples": [
        {
          "brand": "anthropic",
          "value": "conversational"
        },
        {
          "brand": "mercury",
          "value": "professional"
        },
        {
          "brand": "acne-studios",
          "value": "formal"
        }
      ]
    },
    {
      "key": "voice.hedging",
      "category": "voice",
      "ordinal_position": 25,
      "label": "Hedging frequency",
      "description": "Frequency of hedging words (may, might, could, usually).",
      "rubric_summary": "Count hedges per 100 words. none=0, low=1-2, medium=3-5, high=≥6.",
      "scale": "ordinal",
      "values": [
        "none",
        "low",
        "medium",
        "high"
      ],
      "ordinal_map": {
        "none": 1,
        "low": 2,
        "medium": 3,
        "high": 4
      },
      "extraction": "deterministic",
      "convergence_prior": null,
      "examples": [
        {
          "brand": "linear",
          "value": "none"
        },
        {
          "brand": "anthropic",
          "value": "low"
        }
      ]
    },
    {
      "key": "voice.sentence_length",
      "category": "voice",
      "ordinal_position": 26,
      "label": "Sentence length",
      "description": "Average sentence length in body copy.",
      "rubric_summary": "Sample 10 sentences. terse=≤10 words avg, balanced=11-18, flowing=≥19.",
      "scale": "ordinal",
      "values": [
        "terse",
        "balanced",
        "flowing"
      ],
      "ordinal_map": {
        "terse": 1,
        "balanced": 2,
        "flowing": 3
      },
      "extraction": "deterministic",
      "convergence_prior": null,
      "examples": [
        {
          "brand": "linear",
          "value": "terse"
        },
        {
          "brand": "anthropic",
          "value": "balanced"
        },
        {
          "brand": "acne-studios",
          "value": "flowing"
        }
      ]
    },
    {
      "key": "motion.budget",
      "category": "motion",
      "ordinal_position": 27,
      "label": "Motion budget",
      "description": "How much of the experience animates.",
      "rubric_summary": "Visit homepage, scroll, hover. Count animated surfaces. none, accent=button hovers, recurring=throughout, pervasive=ambient.",
      "scale": "ordinal",
      "values": [
        "none",
        "accent",
        "recurring",
        "pervasive"
      ],
      "ordinal_map": {
        "none": 1,
        "accent": 2,
        "recurring": 3,
        "pervasive": 4
      },
      "extraction": "deterministic",
      "convergence_prior": null,
      "examples": [
        {
          "brand": "acne-studios",
          "value": "none"
        },
        {
          "brand": "linear",
          "value": "accent"
        },
        {
          "brand": "stripe",
          "value": "pervasive"
        }
      ]
    },
    {
      "key": "motion.character",
      "category": "motion",
      "ordinal_position": 28,
      "label": "Motion character",
      "description": "The feel and character of animations.",
      "rubric_summary": "Inspect timing curves. mechanical=linear/snappy, smooth=ease-out, playful=bouncy, cinematic=slow/narrative.",
      "scale": "nominal",
      "values": [
        "mechanical",
        "smooth",
        "playful",
        "cinematic"
      ],
      "ordinal_map": {
        "mechanical": 1,
        "smooth": 2,
        "playful": 3,
        "cinematic": 4
      },
      "extraction": "model_graded",
      "convergence_prior": null,
      "examples": [
        {
          "brand": "linear",
          "value": "mechanical"
        },
        {
          "brand": "stripe",
          "value": "smooth"
        },
        {
          "brand": "phantom-studios",
          "value": "cinematic"
        }
      ]
    },
    {
      "key": "motion.trigger",
      "category": "motion",
      "ordinal_position": 29,
      "label": "Motion trigger",
      "description": "Primary trigger for animations.",
      "rubric_summary": "What kicks off the animation? hover-only, scroll, autonomous (always on), gesture.",
      "scale": "nominal",
      "values": [
        "hover-only",
        "scroll",
        "autonomous",
        "gesture"
      ],
      "ordinal_map": {
        "hover-only": 1,
        "scroll": 2,
        "autonomous": 3,
        "gesture": 4
      },
      "extraction": "model_graded",
      "convergence_prior": null,
      "examples": [
        {
          "brand": "linear",
          "value": "hover-only"
        },
        {
          "brand": "stripe",
          "value": "autonomous"
        }
      ]
    },
    {
      "key": "imagery.strategy",
      "category": "imagery",
      "ordinal_position": 30,
      "label": "Imagery strategy",
      "description": "Visual content strategy beyond type and color.",
      "rubric_summary": "What dominates the visual surface? none=icons only, photographic, illustration, abstract=shapes/blobs, mixed.",
      "scale": "nominal",
      "values": [
        "none",
        "photographic",
        "illustration",
        "abstract",
        "mixed"
      ],
      "ordinal_map": {
        "none": 1,
        "abstract": 2,
        "illustration": 3,
        "photographic": 4,
        "mixed": 5
      },
      "extraction": "model_graded",
      "convergence_prior": null,
      "examples": [
        {
          "brand": "anthropic",
          "value": "none"
        },
        {
          "brand": "mercury",
          "value": "photographic"
        },
        {
          "brand": "duolingo",
          "value": "illustration"
        }
      ]
    }
  ],
  "extraction_types": {
    "deterministic": "Computed from CSS/DOM inspection without LLM involvement. Reproduces exactly across runs.",
    "model_graded": "Requires LLM or vision model judgment. Pin model + prompt version in audit block for reproducibility.",
    "mixed": "Deterministic signals provide constraints; model judgment classifies from constrained options. Lower variance than fully model_graded."
  },
  "scale_types": {
    "ordinal": "Values have a meaningful linear order. Distance scoring: c_a = clip(1 - |b_a - o_a| / (max_ordinal - 1), 0, 1).",
    "nominal": "Values are categories with no natural linear order. Use binary match until proximity_matrix is published. proximity_matrix will be derived from inter-brand catalog distances once N > 50 graded pairs per axis."
  },
  "weights_ref": "https://taste-hq.vercel.app/api/weights.json",
  "weights_note": "convergence_prior is null in this spec; computed weights live in api/weights.json (updated after each Surge). w_a = α·catalog_prior_a + (1-α)·kendall_w_a where α decays from 1.0 toward 0.2 as N judge evaluations accumulate.",
  "citation": "Leonelli, Simone. tasteHQ Design Grammar v2.0. Studio W230, 2026. https://taste-hq.vercel.app/schema/grammar-v2.json"
}
