schema: ai-cjm-component-contract/v1 id: media-frame version: 2.0.0 status: stable owner: AI CJM Design purpose: Показывает визуальное доказательство с понятным типом, crop и подписью. use_when: - Изображение доказывает процесс, результат, человека или интерфейс. evidence: - id: production-style url: https://aicjm.ru/edu/cases/case.css?v=20260811-card-source locator: .case-hero__brand, .case-hero__brand img, .case-hero__brand-copy supports: - anatomy - variant:default - size:default - state:default - id: production-dom url: https://aicjm.ru/edu/cases/ozon/ locator: .case-hero .case-hero__brand supports: - approved-example - content anatomy: - id: media required: true role: Изображение, видео или интерфейсный кадр. - id: caption required: true role: Что показано и почему это важно. - id: source required: false role: Источник и дата доказательства. - id: fallback required: true role: Текстовый fallback для недоступного asset. variants: - id: default status: stable description: Каноническая композиция v2. evidence_refs: - production-style sizes: - id: default status: stable description: Размер следует токенам и содержимому без локальных чисел. evidence_refs: - production-style states: default: status: stable basis: observed description: media-frame default is observed at the exact production locator. evidence_refs: - production-style hover: status: not-applicable basis: not-applicable description: hover is not owned by media-frame. focus-visible: status: not-applicable basis: not-applicable description: focus-visible is not owned by media-frame. active: status: not-applicable basis: not-applicable description: active is not owned by media-frame. selected: status: not-applicable basis: not-applicable description: selected is not owned by media-frame. open: status: not-applicable basis: not-applicable description: open is not owned by media-frame. disabled: status: not-applicable basis: not-applicable description: disabled is not owned by media-frame. loading: status: not-applicable basis: not-applicable description: loading is not owned by media-frame. success: status: not-applicable basis: not-applicable description: success is not owned by media-frame. error: status: not-applicable basis: not-applicable description: error is not owned by media-frame. empty: status: not-applicable basis: not-applicable description: empty is not owned by media-frame. responsive: mode: aspect-safe-media-with-caption reading_order: 'media-frame: DOM order remains authoritative at every viewport.' rules: - Preserve media-frame anatomy and primary action in one reading sequence. - Wrap text without horizontal page overflow and preserve evidence labels. accessibility: pattern: captioned-evidence-media semantics: - Expose media-frame as the nearest correct native landmark, article or control. keyboard: - Tab reaches real actions in DOM order; Enter or Space follows the native control contract. focus: - Interactive descendants use focus.ring and preserve a visible label. motion: - Reduced motion removes nonessential transitions without hiding state or evidence. tokens: - surface.subtle - border.default - text.primary - text.secondary - type.size.metadata content: required: - Изображение, видео или интерфейсный кадр. - Что показано и почему это важно. - Текстовый fallback для недоступного asset. constraints: - Фиксировать focal point и содержательную подпись. - Каждый факт и asset сохраняет provenance. do: - Фиксировать focal point и содержательную подпись. dont: - Не использовать декоративный stock как доказательство. examples: approved: status: stable description: Live media-frame at the scoped production locator. evidence: https://aicjm.ru/edu/cases/ozon/ prohibited: description: Не использовать декоративный stock как доказательство. acceptance: - id: media-frame-1 criterion: Все обязательные anatomy parts присутствуют в DOM и видимы. method: automated-and-manual - id: media-frame-2 criterion: На mobile сохраняются reading order, target size и отсутствие overflow. method: browser