{
 "id": "image-card",
 "name": "Image card",
 "purpose": "One photo with a caption, an optional credit line and an optional button, for when the answer is a picture of something.",
 "use_when": [
  "when an answer is best shown as one photo of a place, dish, product or room, with a line about it",
  "the person asked to see something, and one photo with a line of context answers it"
 ],
 "avoid_when": [
  "several photos or options to choose between: use result-list",
  "a product with a price to buy: use product-card",
  "a place to find: use location-card"
 ],
 "type": "content",
 "style": "quiet",
 "width": "narrow",
 "tags": {
  "audience": "consumer",
  "industries": [
   "any"
  ],
  "keywords": [
   "image",
   "photo",
   "caption",
   "media",
   "card"
  ]
 },
 "root": ".odl-image-card",
 "parts": [
  {
   "name": "image",
   "selector": ".odl-photo",
   "what": "the photo, cropped to 3:2",
   "slot": "media"
  },
  {
   "name": "caption",
   "selector": ".odl-caption",
   "what": "one or two sentences about the photo",
   "slot": "text"
  },
  {
   "name": "credit",
   "selector": ".odl-credit",
   "what": "who took the photo or where it is from",
   "slot": "text"
  },
  {
   "name": "open",
   "selector": ".odl-image-card button",
   "what": "an optional quiet action",
   "slot": "action"
  }
 ],
 "data": {
  "type": "object",
  "required": [
   "image",
   "caption"
  ],
  "properties": {
   "image": {
    "type": "object",
    "part": "image",
    "required": [
     "src",
     "alt"
    ],
    "properties": {
     "src": {
      "type": "string",
      "maxLength": 2048
     },
     "alt": {
      "type": "string",
      "maxLength": 200
     }
    }
   },
   "caption": {
    "type": "string",
    "maxLength": 160,
    "part": "caption"
   },
   "credit": {
    "type": "string",
    "maxLength": 60,
    "part": "credit"
   },
   "open": {
    "type": "object",
    "part": "open",
    "properties": {
     "label": {
      "type": "string",
      "maxLength": 40
     },
     "event": {
      "type": "object"
     }
    },
    "required": [
     "label",
     "event"
    ]
   }
  }
 },
 "states": {
  "shown": [
   "with credit",
   "image missing",
   "hover",
   "focus",
   "disabled"
  ],
  "edge": {
   "empty": {
    "status": "not_built",
    "how": "without a photo, answer in text; the card is only for a picture"
   },
   "loading": {
    "status": "handled",
    "how": "the photo box keeps its 3:2 shape in a sunken colour while the image loads",
    "evidence": "aspect-ratio: 3 / 2; object-fit: cover; background: var(--ds-color-surface-sunken);"
   },
   "error": {
    "status": "handled",
    "how": "a photo that fails to load is replaced by its alt text in the same box (the renderer swaps it and keeps the class)",
    "evidence": "class=\"odl-photo\""
   },
   "disabled": {
    "status": "shown",
    "how": "a disabled or still-loading button turns quiet neutral (secondary text on a subtle fill), still readable at AA",
    "evidence": "button:disabled { cursor: not-allowed;"
   },
   "overflow": {
    "status": "handled",
    "how": "on a phone the button moves under the caption",
    "evidence": "@container (max-width: 26rem)"
   },
   "long_text": {
    "status": "handled",
    "how": "caption and credit wrap, also long words",
    "evidence": "overflow-wrap: anywhere"
   },
   "missing_image": {
    "status": "handled",
    "evidence": "data-od-media",
    "how": "the Smart UI renderer swaps a photo that fails to load for a block of the same size with its alt text"
   }
  }
 },
 "tokens": [
  "--ds-border-width-default",
  "--ds-color-bg-neutral-subtle",
  "--ds-color-border-default",
  "--ds-color-border-focus",
  "--ds-color-border-subtle",
  "--ds-color-surface-raised",
  "--ds-color-surface-sunken",
  "--ds-color-text-primary",
  "--ds-color-text-secondary",
  "--ds-elevation-raised",
  "--ds-focus-ring-offset",
  "--ds-focus-ring-width",
  "--ds-font-weight-label",
  "--ds-icon-stroke-md",
  "--ds-motion-duration-short",
  "--ds-motion-easing-standard",
  "--ds-radius-container",
  "--ds-radius-control",
  "--ds-size-control-md",
  "--ds-size-icon-sm",
  "--ds-size-target-min",
  "--ds-space-inline-md",
  "--ds-space-inline-sm",
  "--ds-space-inset-lg",
  "--ds-space-inset-md",
  "--ds-space-inset-xl",
  "--ds-space-inset-xs",
  "--ds-space-stack-sm",
  "--ds-space-stack-xs",
  "--ds-text-body-md",
  "--ds-text-label-lg",
  "--ds-text-label-md"
 ],
 "a11y": {
  "summary": "A figure whose caption is its figcaption; the photo carries alt text from the data, and the optional button is a real button.",
  "roles": [],
  "keyboard": [
   "Tab reaches the button when there is one",
   "Enter or Space presses it"
  ],
  "controls": {
   "button": 1,
   "input": 0,
   "link": 0,
   "select": 0,
   "textarea": 0,
   "summary": 0
  },
  "focus_visible": true,
  "reduced_motion": true,
  "min_target": true
 },
 "files": {
  "html": "components/image-card/component.html",
  "bytes": 4177,
  "script": false
 },
 "source": null,
 "photos": 1,
 "urls": {
  "html": "https://opendesigner.dev/library/image-card.html",
  "json": "https://opendesigner.dev/library/image-card.json",
  "page": "https://opendesigner.dev/library/image-card/"
 },
 "get": {
  "curl": "curl -fsSLo image-card.html https://opendesigner.dev/library/image-card.html",
  "opendesigner": "python3 path/to/skills/opendesigner/scripts/library.py add image-card --from https://opendesigner.dev",
  "prompt": "Add the OpenDesigner component image-card to this project: https://opendesigner.dev/library/image-card.html. Keep its markup and states; map its --ds-* variables to my tokens."
 }
}
