{
 "id": "comparison",
 "name": "Comparison",
 "purpose": "Two to four options side by side: each with its name, price and a Choose button, then one row per attribute so the differences line up.",
 "use_when": [
  "when someone is choosing between a few fares, plans or memberships and wants the differences in one view",
  "two to four options of the same kind that differ on a few named attributes, such as fare types or plan tiers"
 ],
 "avoid_when": [
  "more than four options or a long list to browse: use result-list",
  "one item and its details: use product-card",
  "options that only need a name to pick from: use quick-replies"
 ],
 "type": "commerce",
 "style": "quiet",
 "width": "medium",
 "tags": {
  "audience": "work",
  "industries": [
   "travel",
   "retail",
   "saas",
   "money",
   "any"
  ],
  "keywords": [
   "compare",
   "options",
   "plans",
   "fares",
   "side by side"
  ]
 },
 "root": ".odl-comparison",
 "parts": [
  {
   "name": "title",
   "selector": ".odl-comparison h3",
   "what": "what is being compared",
   "slot": "text"
  },
  {
   "name": "note",
   "selector": ".odl-note",
   "what": "one line of context: route and date, or who it is for",
   "slot": "text"
  },
  {
   "name": "options",
   "selector": ".odl-head > .odl-opt",
   "what": "one option's column header",
   "slot": "list"
  },
  {
   "name": "name",
   "selector": ".odl-name",
   "what": "the option's name",
   "slot": "text"
  },
  {
   "name": "badge",
   "selector": ".odl-badge",
   "what": "a short badge on the recommended option, which also gets the accent button",
   "slot": "text"
  },
  {
   "name": "price",
   "selector": ".odl-price",
   "what": "the price or headline value",
   "slot": "text"
  },
  {
   "name": "price_note",
   "selector": ".odl-per",
   "what": "what the price covers, such as 'per person'",
   "slot": "text"
  },
  {
   "name": "choose",
   "selector": ".odl-choose",
   "what": "picks this option",
   "slot": "action"
  },
  {
   "name": "rows",
   "selector": ".odl-row",
   "what": "one attribute, with a value per option",
   "slot": "list"
  },
  {
   "name": "label",
   "selector": ".odl-label",
   "what": "the attribute's name",
   "slot": "text"
  },
  {
   "name": "values",
   "selector": ".odl-val",
   "what": "one value, in the same order as the options",
   "slot": "list"
  },
  {
   "name": "value",
   "selector": ".odl-cell",
   "what": "the value in words, with a tick or a cross when it is a yes or no",
   "slot": "text"
  }
 ],
 "data": {
  "type": "object",
  "required": [
   "title",
   "options",
   "rows"
  ],
  "properties": {
   "title": {
    "type": "string",
    "maxLength": 40,
    "part": "title"
   },
   "note": {
    "type": "string",
    "maxLength": 80,
    "part": "note"
   },
   "options": {
    "type": "array",
    "minItems": 2,
    "maxItems": 4,
    "part": "options",
    "items": {
     "type": "object",
     "required": [
      "name",
      "choose"
     ],
     "properties": {
      "name": {
       "type": "string",
       "maxLength": 24,
       "part": "name"
      },
      "badge": {
       "type": "string",
       "maxLength": 18,
       "part": "badge"
      },
      "price": {
       "type": "string",
       "maxLength": 14,
       "part": "price"
      },
      "price_note": {
       "type": "string",
       "maxLength": 24,
       "part": "price_note"
      },
      "choose": {
       "type": "object",
       "part": "choose",
       "properties": {
        "label": {
         "type": "string",
         "maxLength": 40
        },
        "event": {
         "type": "object"
        }
       },
       "required": [
        "label",
        "event"
       ]
      }
     }
    }
   },
   "rows": {
    "type": "array",
    "minItems": 1,
    "maxItems": 10,
    "part": "rows",
    "items": {
     "type": "object",
     "required": [
      "label",
      "values"
     ],
     "properties": {
      "label": {
       "type": "string",
       "maxLength": 32,
       "part": "label"
      },
      "values": {
       "type": "array",
       "minItems": 1,
       "maxItems": 4,
       "part": "values",
       "items": {
        "type": "object",
        "required": [
         "value"
        ],
        "properties": {
         "value": {
          "type": "string",
          "maxLength": 40,
          "part": "value"
         },
         "mark": {
          "type": "string",
          "enum": [
           "none",
           "yes",
           "no"
          ],
          "part": "value"
         }
        }
       }
      }
     }
    }
   }
  }
 },
 "states": {
  "shown": [
   "recommended option",
   "included",
   "not included",
   "hover",
   "focus",
   "disabled",
   "scrolls sideways on a phone"
  ],
  "edge": {
   "empty": {
    "status": "handled",
    "evidence": "data-od-list",
    "how": "the Smart UI renderer puts one plain 'Nothing to show yet.' line in an empty list"
   },
   "loading": {
    "status": "handled",
    "evidence": "data-od-slot",
    "how": "the Smart UI renderer draws each marked slot as a quiet block of its size while the data arrives; the static file shows the filled part"
   },
   "error": {
    "status": "not_built",
    "how": "if prices cannot load, leave price out and say why in the note"
   },
   "disabled": {
    "status": "shown",
    "how": "a Choose button for a sold-out option is disabled and dimmed",
    "evidence": ".odl-choose:disabled"
   },
   "overflow": {
    "status": "handled",
    "how": "on a phone each attribute name moves above its values; four options scroll sideways in their own box",
    "evidence": "overflow-x: auto"
   },
   "long_text": {
    "status": "handled",
    "how": "names, values, labels and the badge wrap inside their column",
    "evidence": "overflow-wrap: anywhere"
   },
   "missing_image": {
    "status": "none",
    "how": "the part has no photo"
   }
  }
 },
 "tokens": [
  "--ds-border-width-default",
  "--ds-color-bg-accent-subtle",
  "--ds-color-bg-action-primary",
  "--ds-color-bg-action-primary-hover",
  "--ds-color-bg-neutral-subtle",
  "--ds-color-border-default",
  "--ds-color-border-focus",
  "--ds-color-border-separator",
  "--ds-color-border-subtle",
  "--ds-color-surface-raised",
  "--ds-color-text-accent",
  "--ds-color-text-on-action",
  "--ds-color-text-primary",
  "--ds-color-text-secondary",
  "--ds-color-text-success",
  "--ds-color-text-tertiary",
  "--ds-elevation-raised",
  "--ds-focus-ring-offset",
  "--ds-focus-ring-width",
  "--ds-font-weight-heading",
  "--ds-font-weight-label",
  "--ds-icon-stroke-md",
  "--ds-motion-duration-short",
  "--ds-motion-easing-standard",
  "--ds-radius-container",
  "--ds-radius-control",
  "--ds-radius-full",
  "--ds-size-control-md",
  "--ds-size-control-sm",
  "--ds-size-icon-sm",
  "--ds-size-target-min",
  "--ds-space-2",
  "--ds-space-inline-md",
  "--ds-space-inline-sm",
  "--ds-space-inset-lg",
  "--ds-space-inset-sm",
  "--ds-space-inset-xl",
  "--ds-space-inset-xs",
  "--ds-space-stack-lg",
  "--ds-space-stack-md",
  "--ds-space-stack-sm",
  "--ds-space-stack-xs",
  "--ds-text-body-md",
  "--ds-text-label-lg",
  "--ds-text-label-md",
  "--ds-text-numeric-md",
  "--ds-text-title-md",
  "--ds-text-title-sm"
 ],
 "a11y": {
  "summary": "A table with a column header per option and a row header per attribute, so each value is read with both; ticks and crosses are decorative and the value is always in words; each Choose button is named with its option.",
  "roles": [
   "banner",
   "cell",
   "columnheader",
   "region",
   "row",
   "rowgroup",
   "rowheader",
   "table"
  ],
  "keyboard": [
   "Tab moves through the Choose buttons, one per option, left to right",
   "Enter or Space presses one"
  ],
  "controls": {
   "button": 4,
   "input": 0,
   "link": 0,
   "select": 0,
   "textarea": 0,
   "summary": 0
  },
  "focus_visible": true,
  "reduced_motion": true,
  "min_target": true
 },
 "files": {
  "html": "components/comparison/component.html",
  "bytes": 13763,
  "script": true
 },
 "source": null,
 "photos": 0,
 "urls": {
  "html": "https://opendesigner.dev/library/comparison.html",
  "json": "https://opendesigner.dev/library/comparison.json",
  "page": "https://opendesigner.dev/library/comparison/"
 },
 "get": {
  "curl": "curl -fsSLo comparison.html https://opendesigner.dev/library/comparison.html",
  "opendesigner": "python3 path/to/skills/opendesigner/scripts/library.py add comparison --from https://opendesigner.dev",
  "prompt": "Add the OpenDesigner component comparison to this project: https://opendesigner.dev/library/comparison.html. Keep its markup and states; map its --ds-* variables to my tokens."
 }
}
