[
  {
    "component": "Badge (src/canonical/Badge.vue)",
    "verifierCovered": true,
    "overallFidelity": "high",
    "findings": [
      {
        "dimension": "geometry",
        "severity": "low",
        "summary": "Filled variants always render border: 1px solid var(--badge-border) with --badge-border:transparent, while Figma Filled variants have empty strokes[] (no border). The verifier records rootBorderWidth actual=1 expected=0 but marks it pass=true because the border color is transparent (zero visual effect). Benign, but a strict 1:1 reproduction would set border-width:0 on Filled rather than relying on a transparent paint over a 1px box. Border-box sizing makes it visually inert here.",
        "existingBacklogId": null,
        "suggestedFix": "For Filled tag set --badge-border-width:0 (or border:none) instead of a transparent 1px border, so the rendered box exactly matches Figma's zero-stroke geometry. Cosmetic / consistency only — no visible change.",
        "codeEvidence": "src/canonical/Badge.vue:87 border: 1px solid var(--badge-border); and :54 '--badge-border': props.tag === 'Line' ? p.lineBorder : 'transparent'",
        "figmaEvidence": "variant 4821:1668 (Type=Rectangle,Color=Green,Tag=Filled) strokes: [] , strokeWeight context: no visible stroke layer; verifier check rootBorderWidth actual=1 expected=0"
      },
      {
        "dimension": "geometry",
        "severity": "low",
        "summary": "Figma node carries gap=10 (item spacing) but the badge has a single text child, so spacing never applies. Code renders gap 0 (no flex gap declared). Verifier shows rootGap actual=0 expected=10 pass=true — correctly tolerated as a no-op for single-child layout. No action needed; noted only so a future multi-child slot use does not silently lose the 10px Figma spacing.",
        "existingBacklogId": null,
        "suggestedFix": "No change required. If multi-element slot content is ever expected, add gap: var(--sp-xs?) matching Figma's 10px; currently irrelevant.",
        "codeEvidence": "src/canonical/Badge.vue:78-94 .canonical-badge uses display:inline-flex with no gap declaration; slot renders single text node (:73 <slot>{{ content }}</slot>)",
        "figmaEvidence": "variant Type=Circle,Color=Green,Tag=Filled gap:10; verifier check rootGap actual=0 expected=10"
      }
    ],
    "verified": [],
    "notes": "Badge is an exemplary high-fidelity canonical component — no real drift found. Evidence: (1) color-token: every paint uses a CSS var, zero hardcoded hex (grep NONE at src/canonical/Badge.vue); figmaPalette token mappings match Figma 1:1 — Neutral Filled bg --bg-layer4=#353535, Neutral text --text-body=#f8f8f8, Neutral Line border --line-deep=#353535, Green --brand=#2fb54e, Filled non-Neutral text --text-primary-btn=#ffffff, Line text = palette color (all verified against variant fills/strokes/text.fills tokens). (2) composite-layer: NOT applicable — every fills/strokes/text.fills array has length 1 (single SOLID layer), so no multi-layer composite drift (EXTRACT-008 class) exists here. (3) geometry: Circle 24x24 (--badge-circle-size 24px), Rectangle pH/pR=12 (--sp-s 12px), pV/pB=4 (--sp-xxs 4px), radius 16 (--r-xl 16px), font 400 12px/16px (--text-style-tips) — all match Figma and all verifier geometry checks pass. (4) content fallbacks match Figma text.characters exactly (Circle='5'; Rectangle Green=Done/Blue=Active/Orange=Warn/Red=Error/Neutral=Msg). (5) coverage: FULLY covered — Badge is in COMPONENT_TARGETS (scripts/generate-render-verification-manifest.mjs:101-105) and render-verification.report.json has all 20 variants x 2 themes = 40 entries, every check pass=true (NOT a CANONICAL-017 instance). (6) composition-reuse / a11y: Badge is a non-interactive presentational <span> with a default slot — no canonical child to reuse, no interactive affordance needed. (7) divergences.md:142 registers the canonical-vs-legacy Badge dual-source and scopes audit to canonical/Badge.vue (followed). The two reported findings are low-severity verifier-tolerated deltas (transparent Filled border width; unused single-child gap), not visual drift. No new backlog entries warranted."
  },
  {
    "component": "Breadcrumb (canonical wrapper) + BreadcrumbItem (Base, Figma item-level SoT)",
    "verifierCovered": true,
    "overallFidelity": "high",
    "findings": [
      {
        "dimension": "coverage",
        "severity": "low",
        "summary": "BreadcrumbItem IS covered by render-verification (CANONICAL-017 Batch 1), but every variant currently reports status=FAIL solely on textFillHex (actual #000000 vs expected #cccccc/#434343/etc). This is a DOCUMENTED harness limitation classified B_RESIDUAL_SCHEMA_GAP — empty <slot/> makes the label 0-dimension so the verifier reads the root LI (no color → #000000). Real token colors resolve correctly at runtime. Geometry/padding/gap/opacity/border all pass. No real drift, but the persistent FAIL pollutes the report and is worth a known-limitation suppression or a slot-fixture so the dimension can actually be exercised.",
        "existingBacklogId": "CANONICAL-017",
        "suggestedFix": "Inject non-empty slot fixture content (e.g. 'Label') into the BreadcrumbItem render-verification harness so textFillHex measures the real label, OR mark textFillHex as known-limitation skip for this component to clear the standing FAIL.",
        "codeEvidence": "scripts/generate-render-verification-manifest.mjs:298 warning text 'BreadcrumbItem label uses <slot/> — harness limitation: empty slot content makes label dimensions 0 → not visible to verifier; textFillHex falls back to root LI ... reads #000000'",
        "figmaEvidence": "render-verification.report.json manifestId 'breadcrumb-item--state-default--...': textFillHex actual #000000 expected #cccccc, classification B_RESIDUAL_SCHEMA_GAP (FAIL); all geometry checks pass"
      },
      {
        "dimension": "a11y",
        "severity": "low",
        "summary": "Disabled BreadcrumbItem visually communicates disabled (color --text-disabled, cursor not-allowed, pointer-events:none) but exposes no semantic disabled state. When href is present and state=disabled, the element renders as a non-interactive <span> with no aria-disabled, so AT users get no disabled cue. current state correctly uses aria-current='page'.",
        "existingBacklogId": null,
        "suggestedFix": "Add :aria-disabled=\"resolvedState === 'disabled' ? 'true' : undefined\" to the label element so the disabled state is programmatically conveyed.",
        "codeEvidence": "src/components/Breadcrumb/BreadcrumbItem.vue:44-49 <component :is=\"isInteractiveLink ? 'a' : 'span'\" ... :aria-current=...> (no aria-disabled branch); :104 .breadcrumb-item--disabled { pointer-events:none }",
        "figmaEvidence": "breadcrumb_item__5003_7495.json variant 5003:7491 state=disabled text token --text-disabled #595959"
      }
    ],
    "verified": [],
    "notes": "Fidelity is HIGH. The canonical Breadcrumb.vue (src/canonical/Breadcrumb.vue) is a thin wrapper over BaseBreadcrumb (src/components/Breadcrumb/Breadcrumb.vue), a pure <nav>/<ol> layout container; the Figma SoT is item-level (Breadcrumb/Item, file breadcrumb_item__5003_7495.json, 4 state variants). The container-vs-item topology and the wrapper-over-legacy layer are BOTH registered in src/design-system/translation/divergences.md:84-89 and :163, so 'Figma container missing' is a legal divergence, not drift.\n\nColor: all 4 state text colors map 1:1 to theme-aware tokens and are correct — Default --text-2 (#cccccc), hover --text-body (#f8f8f8), current --brand (#2fb54e), disabled --text-disabled (#595959). No hardcoded hex anywhere (BreadcrumbItem.vue:74,84,90,95,99,105,111).\n\nGeometry: matches Figma exactly per report — rootPadding 4/8/4/8 via --sp-xxs(4px)/--sp-xs(8px) (variables.css:94-95), rootGap 4 via --sp-xxs, opacity 1, borderWidth 0. Text style --text-style-body = 400 14px/21px (variables.css:232) matches Figma text size 14 weight 400 lineHeight 21px.\n\nComposition-reuse: GOOD — separator uses the canonical Icon component (name='arrow-right', resolves via src/icons/raw.ts:1306 / navigation.ts alias), not an inline SVG; no hand-rolled affordance. The separator itself has no paint node in the Figma item data (item file contains only text.fills); it is a code-side inter-item affordance consistent with the registered container topology divergence — NOT flagged as drift.\n\nNo composite-layer issue: every fills/strokes/text.fills array is length 1 (single SOLID layer), so the EXTRACT-008/CANONICAL-018 composite class does not apply here.\n\nState-matrix complete: Default/hover/current/disabled all present with correct colors + correct interaction (current & disabled set pointer-events:none; Default href → interactive <a>). The only state-matrix nuance is the a11y gap reported above."
  },
  {
    "component": "BreadcrumbItem",
    "verifierCovered": true,
    "overallFidelity": "high",
    "findings": [
      {
        "dimension": "coverage",
        "severity": "low",
        "summary": "BreadcrumbItem IS in COMPONENT_TARGETS (CANONICAL-017 Batch 1), but the verifier cannot actually validate text color: the verifyHint admits the empty <slot/> gives the label 0 dimensions, so textFillHex falls back to the root LI and reads #000000 instead of the per-state token. So all four state text colors (--text-2 / --text-body / --brand / --text-disabled) are effectively UNVERIFIED at render time despite the row existing.",
        "existingBacklogId": "CANONICAL-017",
        "suggestedFix": "Have the harness inject placeholder slot text (e.g. 'Label') for BreadcrumbItem render rows so the label node gains dimensions and the verifier reads the real per-state computed color instead of the #000000 fallback. Track under CANONICAL-017.",
        "codeEvidence": "scripts/generate-render-verification-manifest.mjs:298 'BreadcrumbItem label uses <slot/> — harness limitation: empty slot content makes label dimensions 0 → not visible to verifier; textFillHex falls back to root LI (no color) reads #000000.'; src/components/Breadcrumb/BreadcrumbItem.vue:50 <slot/>",
        "figmaEvidence": "breadcrumb_item__5003_7495.json variants state=Default text.fills[0].hex=#cccccc(--text-2), state=hover #f8f8f8(--text-body), state=current #2fb54e(--brand), state=disabled #595959(--text-disabled)"
      }
    ],
    "verified": [],
    "notes": "Read both the canonical wrapper (src/canonical/BreadcrumbItem.vue) and the delegated base (src/components/Breadcrumb/BreadcrumbItem.vue) fully; the wrapper layer is a registered healthy bridge pattern (divergences.md:163 lists Breadcrumb). Audited against breadcrumb_item__5003_7495.json (4 state variants).\n\nFidelity is HIGH — code maps 1:1 to Figma on every audited dimension:\n- color-token: all 4 state text colors use the exact CSS var the Figma variable resolves to (--text-2/--text-body/--brand/--text-disabled). No hardcoded hex. Tokens confirmed in variables.css. No multi-layer composites (every text.fills array has length 1), so EXTRACT-008/CANONICAL-018 composite class does NOT apply here.\n- geometry: Figma gap=4 → gap:var(--sp-xxs)=4px; pH=8/pV=4 → padding:var(--sp-xxs) var(--sp-xs)=4px 8px; layoutMode HORIZONTAL + counterAxisAlignItems CENTER → inline-flex/align-items:center. All match. r=null (no radius) and code sets none. ✓\n- state-matrix: Default/hover/current/disabled all present with correct colors + cursor/pointer-events semantics; Default also has a :hover→--text-body rule matching the hover variant. ✓\n- a11y: interactive link renders real <a> with href only in Default state; current uses aria-current=page; disabled renders non-interactive span with pointer-events:none. No inline @click affordance — CANONICAL-013 class does NOT apply.\n- composition-reuse: separator uses canonical Icon (name=arrow-right, aria-hidden) — no hand-rolled markup that should be a canonical child. CANONICAL-007/012/013 class does NOT apply.\n\nSeparator note (not a drift): Figma subnodeCount=2 with a vectorNodeId (the separator icon) confirms a 2-child layout (icon + label); code matches. The separator icon's own paint is not separately tokenized in this data file, so the code's --text-2 default / --text-body hover separator color is a reasonable inference and cannot be flagged as drift without evidence.\n\nThe only finding is a coverage-QUALITY gap already owned by CANONICAL-017: the verifier row exists but the empty-slot harness limitation means the text colors are not actually exercised. No NEW backlog entry created."
  },
  {
    "component": "ButtonBridge.vue (wraps src/components/Button/Button.vue — the canonical Button impl)",
    "verifierCovered": true,
    "overallFidelity": "medium",
    "findings": [
      {
        "dimension": "coverage",
        "severity": "high",
        "summary": "The 8 main Button theme×size sets (~3200 variants) have ZERO render-verification coverage; only the separate 'Button/url link' set (4 variants, rendered via a rimless approximation) is in COMPONENT_TARGETS. The entire color/geometry/state matrix of the primary Button family is audit-invisible — exactly the CANONICAL-017 class.",
        "existingBacklogId": "CANONICAL-017",
        "suggestedFix": "Track under CANONICAL-017 follow-up (Batch 6.2+). Add at least one COMPONENT_TARGETS entry per theme×size set, or a representative-variant sampling strategy, so the main Button family's computed colors/geometry are verified rather than only the url-link approximation.",
        "codeEvidence": "scripts/generate-render-verification-manifest.mjs:~550 — only target is `figmaName: 'Button/url link', files: ['button_url_link__438_7995.json']`; comment 'Main 8 sets (~3200 variants) deferred to independent sprint'. ButtonBridge appears nowhere in COMPONENT_TARGETS (grep found only url-link codeComponent:'Button').",
        "figmaEvidence": "button_light_l__1545_47446.json has 400 variants (and 7 more sets for dark/light × L/M/S/XS); none are referenced by any COMPONENT_TARGETS entry."
      },
      {
        "dimension": "coverage",
        "severity": "high",
        "summary": "Even the one covered Button set is mis-wired: the manifest sets textTargetSelector '.btn__label', but Button.vue renders the label as a bare <slot/> with no .btn__label (or any text) element. The text-color verification for the url-link set therefore targets a non-existent node, so the only Button text-fidelity check silently no-ops.",
        "existingBacklogId": "CANONICAL-017",
        "suggestedFix": "Either wrap the default slot in a `<span class=\"btn__label\">` so the declared selector resolves, or change textTargetSelector to a real node. Until then mark the url-link entry's text check as non-functional.",
        "codeEvidence": "Button.vue:374 `<slot />` (label) — grep for 'btn__label'/'btn-label' in Button.vue returns nothing. Manifest entry: `textTargetSelector: '.btn__label'`.",
        "figmaEvidence": "button_url_link__438_7995.json variants carry a text node (text.characters='Button', text.fills token); manifest declares textTargetSelector '.btn__label' to read that color but no such element is rendered."
      },
      {
        "dimension": "color-token",
        "severity": "high",
        "summary": "Filling green DISABLE text color drift. Figma label fill is --color-grey-2 (#f8f8f8, near-white). Code maps filling/green/disable text to --text-tips (light #595959, dark #9e9e9e) — a dark-grey, the opposite end of the scale. This is a real value drift, not a token-name remap, and is not registered in divergences.md.",
        "existingBacklogId": null,
        "suggestedFix": "Map filling/green/disable text to a token resolving to #f8f8f8 (e.g. --color-grey-2) per Figma, or register the divergence in divergences.md with rationale.",
        "codeEvidence": "Button.vue:221 `disable: { bg: 'var(--brand-disable)', text: 'var(--text-tips)', border: 'transparent' }`; variables.css --text-tips light #595959 / dark #9e9e9e.",
        "figmaEvidence": "button_light_l__1545_47446.json variant 'icon=no, style=filling, color=green, status=disable, Radius=square, fixed width=no' → text.fills[0] token --color-grey-2, hex #f8f8f8 (bg --brand-disable #8fcc9d)."
      },
      {
        "dimension": "color-token",
        "severity": "medium",
        "summary": "Filling gray DISABLE text color drift. Figma label fill is --color-grey-6 (#9e9e9e light). Code maps filling/gray/disable text to --text-placeholder (light #7b7b7b, dark #9e9e9e). Light value mismatch (#7b7b7b vs #9e9e9e); dark coincidentally matches. Unregistered.",
        "existingBacklogId": null,
        "suggestedFix": "Use a token resolving to #9e9e9e in light (e.g. --color-grey-6 / --text-tips light #595959 is also wrong — pick the one mapping to #9e9e9e) for filling/gray/disable text, or register divergence.",
        "codeEvidence": "Button.vue:226 `disable: { bg: 'var(--bg-grey-btn-dis)', text: 'var(--text-placeholder)', border: 'transparent' }`; variables.css --text-placeholder light #7b7b7b / dark #9e9e9e.",
        "figmaEvidence": "button_light_l__1545_47446.json variant 'icon=no, style=filling, color=gray 1, status=disable, ...' → text.fills[0] token --color-grey-6, hex #9e9e9e (bg --color-grey-4 #dbdbdb)."
      },
      {
        "dimension": "state-matrix",
        "severity": "low",
        "summary": "Dark-theme parity for disable text could not be confirmed: the dark-L green disable variant did not resolve under the same name used in the light set, so the dark side of the disable text tokens (--text-tips / --text-placeholder) is unverified against Figma. Not a confirmed drift, but a coverage gap in this audit given no render-verification backstop exists for these sets.",
        "existingBacklogId": "CANONICAL-017",
        "suggestedFix": "Re-probe dark-L set with its actual variant naming and confirm disable text hex parity; fold into the CANONICAL-017 main-set coverage work so this is machine-verified rather than manually spot-checked.",
        "codeEvidence": "Button.vue:221,226 disable text tokens are single values shared across themes via CSS var theme overrides; no dark-specific override in palette map.",
        "figmaEvidence": "jq on button_dark_l__1545_51854.json for 'icon=no, style=filling, color=green, status=disable, Radius=square, fixed width=no' returned empty (variant naming differs in dark set), so expected dark hex not captured."
      }
    ],
    "verified": [
      {
        "summary": "Filling green DISABLE text color drift. Figma label fill is --color-grey-2 (#f8f8f8, near-white). Code maps filling/green/disable text to --text-tips (light #595959, dark #9e9e9e) — a dark-grey, the opposite end of the scale. This is a real value drift, not a token-name remap, and is not registered in divergences.md.",
        "real": true,
        "correctedSeverity": "medium",
        "reason": "Independently verified. CODE: the cited mapping exists exactly — runtime Button.vue:221 `disable: { bg: 'var(--brand-disable)', text: 'var(--text-tips)', border: 'transparent' }` for filling/green (the auditor labeled the path ButtonBridge.vue, but ButtonBridge is a thin wrapper that delegates to ../components/Button/Button.vue; the line content is correct). --text-tips resolves to #595959 (light, variables.css:326) and #9e9e9e (dark, :45). FIGMA: button_light_l__1545_47446.json variant 'icon=no, style=filling, color=green, status=disable, Radius=square, fixed width=no' (id 314:46774) is a real COMPONENT with a runtime counterpart (not Is-Parent/preview-only). Its text.fills is a SINGLE fully-opaque SOLID layer hex #f8f8f8, token --color-grey-2, and compositeToken is null — so this is NOT a fills[0]-only false positive (no stacking). So Figma wants near-white #f8f8f8 text while code emits dark-grey #595959/#9e9e9e: a genuine value drift across opposite ends of the grey scale, not a token-name remap. Not registered: the only two Button entries in divergences.md (lines 98, 277) cover the 8-sets→single-component architecture and the dual-API migration, neither of which addresses the disabled text color. (Side note, not part of this claim: code's --brand-disable=#1a652c also diverges from Figma's #8fcc9d for the bg — a separate potential drift.) Corrected to medium: confirmed real but scoped to the disabled state's label color of one color/style family, not a primary high-traffic surface."
      }
    ],
    "notes": "ButtonBridge.vue is a thin pass-through wrapper (data-figma-* attrs + canonical-* props) over src/components/Button/Button.vue; all real logic/styling is in Button.vue, so the audit targets that file. Native &lt;button&gt; in Button.vue is NOT a composition/a11y drift — it is the canonical Button implementation and carries an explicit whitelist comment (Button.vue:1 \"audit-canonical-compliance: allow R2 file — this IS the Button canonical impl\"); focus-visible + :disabled are handled. The 8-set→single-component split is a registered divergence (divergences.md:98 button-eight-sets-single-component) so that structural mapping is legal. Many token NAMES differ from Figma but resolve to identical theme-aware hex (filling green default: Figma --color-white #ffffff vs code --text-primary-btn #ffffff; filling gray default bg Figma --color-grey-4 #dbdbdb vs code --bg-grey-btn-en light #dbdbdb; ghost stroke 1.2px ✓; red/orange disable node opacity 0.4 ✓ matches surfaceOpacity) — these are value-correct and NOT flagged. Geometry for L all match (h=40, square r=4 / round r=20, pH square=24 / round=28, iconGap=8 for icon variants). Real drifts are confined to two disable text-color tokens and verifier coverage/wiring. No hardcoded hex in Button.vue (all via CSS vars). All Figma evidence from button_light_l__1545_47446.json (light L set); dark-L disable variant name did not resolve identically (naming variance) so dark-side parity unverified."
  },
  {
    "component": "src/canonical/Chart.vue (delegates to src/components/Chart/Chart.vue)",
    "verifierCovered": true,
    "overallFidelity": "low",
    "findings": [
      {
        "dimension": "geometry",
        "severity": "high",
        "summary": "Figma Chart is a card container with padding 16, corner radius 8, and inner gap (8–12), but the code wrapper .tvu-chart has no padding, no border-radius and no gap. All six variants (pie/donut/line/bar/bar-horizontal/line-bar) share pH=pV=pB=pR=16 and r=8 in Figma; the rendered chart fills the raw width/height box with zero container chrome.",
        "existingBacklogId": null,
        "suggestedFix": "Apply container styling on .tvu-chart: padding: 16px; border-radius: 8px; and account for the legend/chart gap. Use the radius/spacing tokens rather than literals if available.",
        "codeEvidence": "src/components/Chart/Chart.vue:110-115 — .tvu-chart { position: relative; display: inline-block; } (no padding / border-radius / gap)",
        "figmaEvidence": "chart__4949_7176.json all variants: pH=16 pV=16 pB=16 pR=16, r=8, gap=12 (pie/donut/line/bar), gap=10 (bar-horizontal), gap=8 (line-bar)"
      },
      {
        "dimension": "color-token",
        "severity": "high",
        "summary": "Figma chart container background is --bg-layer3 (#262626 dark / #f0f0f0 light), but the code .tvu-chart has no background-color at all. The chart renders transparent against whatever sits behind it, so the source-of-truth surface token is dropped entirely.",
        "existingBacklogId": null,
        "suggestedFix": "Add background-color: var(--bg-layer3); to .tvu-chart so the card surface matches Figma and stays theme-aware.",
        "codeEvidence": "src/components/Chart/Chart.vue:97-99,110-115 — wrapper has only width/height inline style; <style> sets no background-color",
        "figmaEvidence": "chart__4949_7176.json all 6 variants fills[0] token.cssVar = --bg-layer3 (#262626)"
      },
      {
        "dimension": "color-token",
        "severity": "medium",
        "summary": "Figma legend/label text uses --color-grey-5 (#cccccc), Roboto 400, size 12, lineHeight 16. The Chart.js legend config (plugins.legend) sets only position:'bottom' with no labels.color / font.family / font.size, so the legend renders Chart.js defaults (~#666, Helvetica/Arial, 12px) instead of the Figma token. Legend text color is therefore wrong and unsourced from tokens.",
        "existingBacklogId": null,
        "suggestedFix": "Set plugins.legend.labels = { color: resolved(--color-grey-5), font: { family: 'Roboto', size: 12, lineHeight: 16/12 } }, resolving the token at runtime like resolveChartPalette() does (and re-resolving on theme switch).",
        "codeEvidence": "src/components/Chart/Chart.vue:85-90 — plugins: { legend: { position: 'bottom' } } (no labels.color / font)",
        "figmaEvidence": "chart__4949_7176.json type=pie/bar-horizontal text: fills[0] token.cssVar=--color-grey-5 (#cccccc), fontFamily=Roboto, fontWeight=400, size=12, lineHeightPx=16"
      },
      {
        "dimension": "geometry",
        "severity": "low",
        "summary": "Default width/height (320x200) do not match any Figma variant box. Figma boxes are 240x220 (pie/donut/bar-horizontal) and 320x270 (line/bar/line-bar). The canonical default of 320x200 matches no variant's height (220 or 270). Minor since size is prop-driven, but defaults misrepresent the source spec.",
        "existingBacklogId": null,
        "suggestedFix": "Align defaults to a real Figma variant box (e.g. 320x270 for bar/line) or document the default as intentional product sizing in divergences.md.",
        "codeEvidence": "src/components/Chart/Chart.vue:38-42 and src/canonical/Chart.vue:13-17 — height:200, width:320 defaults",
        "figmaEvidence": "chart__4949_7176.json: pie/donut/bar-horizontal w=240 h=220; line/bar/line-bar w=320 h=270"
      }
    ],
    "verified": [
      {
        "summary": "Figma Chart is a card container with padding 16, corner radius 8, and inner gap (8–12), but the code wrapper .tvu-chart has no padding, no border-radius and no gap. All six variants (pie/donut/line/bar/bar-horizontal/line-bar) share pH=pV=pB=pR=16 and r=8 in Figma; the rendered chart fills the raw width/height box with zero container chrome.",
        "real": true,
        "correctedSeverity": "high",
        "reason": "Claim verified on both sides. CODE: src/components/Chart/Chart.vue style block confirms `.tvu-chart { position: relative; display: inline-block; }` with no padding, border-radius, background, or gap; the wrapper renders only `width×height` from props. The canonical src/canonical/Chart.vue is a thin pass-through to this BaseChart, adding no chrome. No chart.js `layout.padding` or container background exists (the only `backgroundColor` hits are dataset/series palette colors). FIGMA: chart__4949_7176.json contains 6 real COMPONENT variants (type=pie/donut/line/bar/bar-horizontal/line-bar), all with pH=pV=pB=pR=16, r=8, VERTICAL auto-layout; gap=12 (pie/donut/line/bar), gap=10 (bar-horizontal), gap=8 (line-bar) — matching the claim exactly. The container has a genuine single SOLID fill #262626 (--bg-layer3), so this is NOT a fills[0]-only composite false positive. None are isParent/preview-only nodes (all COMPONENT with runtime counterparts), so not a schema-gap. The audit entry (published-vs-code.audit.json) for Chart is only a name→code mapping with status:approved — component registration, not a registered geometry divergence/waiver. Therefore the card container chrome (16px padding, 8px radius, legend/chart gap, layer-3 background) is real Figma intent entirely missing in code."
      },
      {
        "summary": "Figma chart container background is --bg-layer3 (#262626 dark / #f0f0f0 light), but the code .tvu-chart has no background-color at all. The chart renders transparent against whatever sits behind it, so the source-of-truth surface token is dropped entirely.",
        "real": true,
        "correctedSeverity": "high",
        "reason": "Independently confirmed. CODE: src/components/Chart/Chart.vue lines 110-115 define .tvu-chart with only `position: relative; display: inline-block;` — no background-color; the wrapper div (line 99) inline style is only width/height. Canonical Chart.vue is a thin wrapper delegating to this base component, so the base is the correct target. FIGMA: chart__4949_7176.json all 6 variants (type=pie/donut/line/bar/bar-horizontal/line-bar) carry exactly one fill — SOLID, opacity 1, hex #262626, token.cssVar = --bg-layer3 (Color Type/Background/Layer_3). Confounders ruled out: (a) NOT a fills[0]-only artifact — each variant has a single fill layer, so fills[0] is the complete expected surface, no composite dropped; (b) no registered divergence/whitelist for Chart background in published-vs-code.audit.json or the audit md; (c) NOT a schema-gap — all 6 are real COMPONENT variants (isParent null) matching the 6 runtime ChartType values, with live template branches. Token is defined and theme-aware: src/tokens/variables.css --bg-layer3 = #262626 (dark, line 55) / #f0f0f0 (light, line 336). The SOT surface token is genuinely absent in code, so the chart renders transparent. The suggested fix (background-color: var(--bg-layer3)) is correct and theme-aware."
      }
    ],
    "notes": "Chart IS render-verification covered (scripts/generate-render-verification-manifest.mjs:471-486, report manifestIds chart--type-pie--...--theme-dark/light), so this is NOT a CANONICAL-017 coverage gap. However the verifier only reads the root .tvu-chart computed style (documented Chart.js canvas limitation), and the root currently carries NO background/padding/radius — meaning the verifier reads an empty wrapper and passes trivially while the actual Figma card chrome (bg-layer3, padding 16, radius 8) is entirely missing. The canvas-content tokens (legend color/font, palette) are by-design not pixel-introspectable. Palette resolution is correct and theme-aware (resolveChartPalette reads --chart-color-1..12, MutationObserver re-resolves on data-theme change; tokens confirmed in variables.css:78-89 / 356-367). No composition-reuse or a11y drift: Chart.js is the legit canvas renderer and role='img'+aria-label are present. No divergences.md entry covers Chart (grep empty), so the missing container bg/padding/radius are unregistered drift, not legal divergence. Did not edit/build/regenerate anything (read-only)."
  },
  {
    "component": "CheckBox.vue (src/canonical/CheckBox.vue → src/components/Checkbox/Checkbox.vue)",
    "verifierCovered": true,
    "overallFidelity": "medium",
    "findings": [
      {
        "dimension": "a11y",
        "severity": "high",
        "summary": "The checkbox affordance is a non-interactive <label @click.prevent> wrapping a <span class=\"cb-box\"> + decorative <Icon> — there is NO native input, no role=\"checkbox\", no tabindex, no aria-checked/aria-disabled, and no @keydown handler. It is mouse-only: not keyboard-focusable or operable, and not announced to screen readers. Same interactive-element-without-real-semantics drift class as CANONICAL-013.",
        "existingBacklogId": null,
        "suggestedFix": "Render a real control: either a visually-hidden native <input type=\"checkbox\"> driving the styled box, or add role=\"checkbox\" + tabindex=\"0\" + :aria-checked (true/false/'mixed' for indeterminate) + :aria-disabled + @keydown.space.prevent/@keydown.enter.prevent=\"toggle\" on the label/box.",
        "codeEvidence": "src/components/Checkbox/Checkbox.vue:19 `<label class=\"cb\" ... @click.prevent=\"toggle\">` and :20 `<span class=\"cb-box\" ...>` with icons marked aria-hidden=\"true\" (lines 32,39); toggle() at :13-15 reachable only via click — no keydown/Space/Enter binding, no role, no tabindex anywhere in template.",
        "figmaEvidence": "Component set check_box__3242_13521 exposes status axis off/on/some and enable yes/no (variants 374:771,772,773,783) — i.e. an interactive checkbox control, which implies keyboard operability + checked-state semantics the code omits."
      },
      {
        "dimension": "geometry",
        "severity": "low",
        "summary": "Box paint, corner radius, size and border-weight cannot be verified against Figma: the variant top-level fills/strokes are empty [] and the checkbox box lives in unexpanded child subnodes (subnodeCount:2) that the extract pipeline did not flatten. Only the container gap (8px) and text.fills are present. Same variant-child geometry extract gap as EXTRACT-007. Code values (--checkbox-size:16px, --checkbox-radius:1.2px, border 1.2px) are therefore unverifiable from this data, though border is hardcoded 1.2px (see border note) and gap matches.",
        "existingBacklogId": "EXTRACT-007",
        "suggestedFix": "Track under EXTRACT-007 (variant-child geometry schema gap); once child subnodes are flattened, verify --checkbox-size/--checkbox-radius and box fill/stroke per state against the actual child node values.",
        "codeEvidence": "src/components/Checkbox/Checkbox.vue:64-67 `width/height: var(--checkbox-size); border-radius: var(--checkbox-radius); border: 1.2px solid var(--control-default-border)`",
        "figmaEvidence": "Variant 374:772 geometry: layoutMode HORIZONTAL, gap 8, w 66, h 21, fills [] strokes [] r null, subnodeCount 2 — box paint/radius/size are in non-extracted child nodes."
      },
      {
        "dimension": "color-token",
        "severity": "low",
        "summary": "Minor hardcoded numeric (not hex): border width is hardcoded as 1.2px in two places (.cb-box border and the disabled box-shadow inset 1px) rather than a token, and the indeterminate uses inset box-shadow 1px while default border is 1.2px — a 0.2px inconsistency. Not a hex-color bug (all colors use tokens), so low severity. All text/state colors correctly use theme-aware tokens (verified: dark text-body #f8f8f8 / light #141414 / disabled #595959 / #cccccc all match Figma variants 374:771,774,783,779).",
        "existingBacklogId": null,
        "suggestedFix": "Introduce a --checkbox-border-width token and use it consistently for both the default border and the disabled inset shadow; reconcile 1.2 vs 1 once child stroke data is available via EXTRACT-007.",
        "codeEvidence": "src/components/Checkbox/Checkbox.vue:67 `border: 1.2px solid var(--control-default-border)` vs :101 `box-shadow: inset 0 0 0 1px var(--control-disabled-border)` — 1.2px vs 1px mismatch; both literals not tokenized.",
        "figmaEvidence": "Variant strokeWeight reported as 1 at container level (374:771 strokeWeight:1); actual box stroke weight is in unextracted child subnode, so the 1.2px source is unverified against Figma."
      }
    ],
    "verified": [
      {
        "summary": "The checkbox affordance is a non-interactive <label @click.prevent> wrapping a <span class=\"cb-box\"> + decorative <Icon> — there is NO native input, no role=\"checkbox\", no tabindex, no aria-checked/aria-disabled, and no @keydown handler. It is mouse-only: not keyboard-focusable or operable, and not announced to screen readers. Same interactive-element-without-real-semantics drift class as CANONICAL-013.",
        "real": true,
        "correctedSeverity": "high",
        "reason": "Independently confirmed. CODE: src/components/Checkbox/Checkbox.vue (the impl delegated to by canonical CheckBox.vue) line 19 is exactly `<label class=\"cb\" :class=... @click.prevent=\"toggle\">`, line 20 `<span class=\"cb-box\" ...>`, icons aria-hidden=\"true\" at lines 32 and 39, toggle() at lines 13-15 emits update:modelValue and is reachable only via the click handler. A targeted grep for input|keydown|tabindex|role|aria-checked|aria-disabled returns ZERO matches — so there is no native input, no role=\"checkbox\", no tabindex, no aria-checked/aria-disabled, and no @keydown/Space/Enter binding. The affordance is mouse-only, not keyboard-focusable/operable, and not announced to assistive tech. FIGMA: figma-data/normalized/components-tokenized/check_box__3242_13521.json is a published COMPONENT_SET (nodeId 3242:13521) with 12 variants on status (off/on/some) and enable (yes/no), variant IDs 374:771/772/773 present — a genuine interactive checkbox control, and it is matched+approved to codeNames=[\"CheckBox\"] in published-vs-code.audit.json, so this is NOT an Is-Parent/preview-only schema gap. Guard checks: (a) not a fills[0]-vs-composite color issue (this is a structural/semantic claim); (b) not a registered divergence — no a11y/role/aria entry for Checkbox in conformance-issue-log.md; the only demo-only caveat (line 1434) concerns Figma-only variants/props, not missing semantics on a real control; (c) not a schema gap — a live runtime counterpart exists. Corroborating: sibling Switch.vue carries role=\"switch\"+aria-checked (DS does implement a11y semantics where intended) while Radio.vue shares the identical @click.prevent-on-label gap, confirming this is the same interactive-element-without-real-semantics drift class as CANONICAL-013."
      }
    ],
    "notes": "CheckBox.vue itself is a clean Figma-aligned bridge (darkTheme/status/enable axes -> Checkbox props) and the canonical->legacy wrapper is an explicitly REGISTERED divergence (src/design-system/translation/divergences.md:163 lists CheckBox among healthy wrapper components), so the wrapper layer is NOT flagged as composition drift. Render-verification coverage EXISTS (scripts/generate-render-verification-manifest.mjs:334-337 codeComponent 'CheckBox'; ~12 entries in render-verification.report.json) — so CANONICAL-017 does NOT apply here. Text/state color tokens all verified theme-aware and matching Figma (dark/light enabled + disabled). overallFidelity=medium driven by the high-severity a11y gap (no role/tabindex/keyboard) in the base Checkbox; geometry/box-paint could not be fully verified due to the EXTRACT-007 variant-child flattening gap (variant fills/strokes empty, subnodeCount:2). The base Checkbox.vue inline span+Icon affordance is the documented legacy impl layer, not a CANONICAL-007/012 reuse violation (CheckBox IS the canonical leaf), but its missing keyboard semantics is the actionable issue."
  },
  {
    "component": "DropDownListSelect",
    "verifierCovered": true,
    "overallFidelity": "medium",
    "findings": [
      {
        "dimension": "composition-reuse",
        "severity": "high",
        "summary": "Multi-type check affordance is hand-rolled markup (a <span class=\"dropdown-item__check\"> wrapper with an inline border/bg + nested Icon name=\"selected\") instead of reusing the canonical CheckBox.vue. Violates hard rule #3 (canonical must reuse canonical children for shared affordances). The check box geometry (14x14, 1.2px border, --r-xs radius, --brand-match fill, --brand border) is re-declared locally and will drift from CheckBox.vue over time.",
        "existingBacklogId": "CANONICAL-012",
        "suggestedFix": "Replace the inline span+Icon with <CheckBox> (canonical) bound to item.checked, removing the local .dropdown-item__check* style block.",
        "codeEvidence": "src/canonical/DropDownListSelect.vue:56-64 <span v-if=\"type === 'Multi'\" class=\"dropdown-item__check\" :class=\"{ 'dropdown-item__check--checked': item.checked }\"><Icon v-if=\"item.checked\" name=\"selected\" :size=\"10\" .../></span>; styles :141-157 .dropdown-item__check { width:14px; height:14px; border:1.2px solid var(--control-default-border); ... } .dropdown-item__check--checked { background: var(--brand-match); border-color: var(--brand); }",
        "figmaEvidence": "drop_down_list_item__1446_118010.json variant 1446:115713 (Theme=Dark, Type=Multi, Is Parent=No, Checked=Yes) subnodeCount=2 with vector nodes I1446:115715;1480:74525 / ;1480:76742 — the checked state is a real checkbox node, the same affordance CheckBox.vue renders."
      },
      {
        "dimension": "a11y",
        "severity": "high",
        "summary": "List rows are plain <div @click=\"handleSelect\"> with no listbox/option roles, no tabindex, no keyboard (Enter/Space/arrow) handling, and the Multi check icon is aria-hidden with no checkbox role/aria-checked. The whole control is mouse-only and invisible to assistive tech, despite being a selection menu.",
        "existingBacklogId": "CANONICAL-016",
        "suggestedFix": "Add role=\"listbox\" to container, role=\"option\" + aria-selected + tabindex to each row, and keydown handlers (Enter/Space to select, Up/Down to move focus). For Multi, give the affordance role=\"checkbox\"/aria-checked (covered by the CheckBox.vue reuse above).",
        "codeEvidence": "src/canonical/DropDownListSelect.vue:45-66 <div v-for=\"item in items\" class=\"dropdown-item\" @click=\"handleSelect(item)\"> ... no role/tabindex/@keydown; container :34 <div class=\"dropdown-select\"> has no role=\"listbox\".",
        "figmaEvidence": "drop_down_list_select__1446_116439.json is a selection list (Type=Radio/Multi/Operation List/Sort By) — semantically a listbox/menu of options; interaction states (Checked/Active/Hover) imply keyboard-selectable options."
      },
      {
        "dimension": "composite-layer",
        "severity": "medium",
        "summary": "Disabled+checked row text is a 2-layer paint STACK in Figma: base --brand + an overlay of --text-heading at reduced alpha. Code composites this with color-mix (brand 54%/#fff 46% dark; brand 30%/#fff 70% light). The light layer (--text-heading=#fff @70%) matches the extract, but the dark extract here records the overlay as #000000 @46% (strategy hex-fallback) — i.e. the dark raw extract conflicts with the token resolution (--text-heading=#ffffff in dark) that the code's #fff assumption relies on. This is the in-flight composite fix; the dark raw-hex anomaly should be confirmed against the extract pipeline, not silently trusted.",
        "existingBacklogId": "CANONICAL-018",
        "suggestedFix": "Keep CANONICAL-018 fix but verify the dark overlay layer: if --text-heading=#fff in dark, the dark composite (#fff@46% over brand) and code agree; confirm the #000000 raw extract is a pipeline gap (composite-paints helper) and not a real Figma black overlay before closing.",
        "codeEvidence": "src/canonical/DropDownListSelect.vue:123-134 .dropdown-item--checked.dropdown-item--disabled { color: color-mix(in srgb, var(--brand) 54%, #fff 46%); } [data-theme='light'] ... { color: color-mix(in srgb, var(--brand) 30%, #fff 70%); }",
        "figmaEvidence": "drop_down_list_item__1446_118010.json Radio Is Parent=No Checked=Yes Disabled=Yes text.fills = [#2fb54e --brand @1.0, #000000 @0.46 token=--text-heading strategy=hex-fallback]; light file 1561_8390 same variant text.fills = [#299f45 --brand, #ffffff @0.70 --text-heading derived-overlay]. --text-heading resolves #ffffff(dark)/#000000(light) in variables.css:42/323, so the dark raw #000000 is the suspect layer."
      },
      {
        "dimension": "color-token",
        "severity": "low",
        "summary": "Light-theme Sort By container fill in Figma maps to --color-white (grey-1 #FFFFFF) while all other light types map to --bg-layer1 (also #ffffff). Code uses a single --bg-layer1 for all off-theme types. Values are identical (#ffffff) so there is no visual drift, but the token identity differs from Figma's variable binding — worth a note, not a fix.",
        "existingBacklogId": null,
        "suggestedFix": "No action required (visually identical). Optionally document that Sort By's grey-1 binding collapses to --bg-layer1 in code, or add a divergence note if strict token-identity parity is desired.",
        "codeEvidence": "src/canonical/DropDownListSelect.vue:79-85 .dropdown-select--off { background: var(--bg-layer1); } (no per-type override for sort-by background)",
        "figmaEvidence": "drop_down_list_select__1446_116439.json: Dark Theme=off Type=Sort By fill token=--color-white (VariableID:1558:94781); other off types fill token=--bg-layer1 (VariableID:312:56317); both hex #ffffff."
      }
    ],
    "verified": [],
    "notes": "Coverage: DropDownListSelect IS render-verification covered (scripts/generate-render-verification-manifest.mjs:169 codeComponent 'DropDownListSelect'; 130 hits in render-verification.report.json) — CANONICAL-017 does NOT apply here. Verified-correct mappings (no drift): container fill dark #353535=--bg-layer4, light off #ffffff=--bg-layer1; item geometry h=32 (min-height:32px), w=240 (width:240px), gap=8; padding pH=12/pR=8 = code `0 var(--sp-xs)[8] 0 var(--sp-s)[12]`; Operation List pR=12 override = padding-right:var(--sp-s)[12]; hover/active bg #0b2b13=--brand-match=--green-bg; checked text #2fb54e=--brand; disabled text #595959=--text-disabled=--control-disabled-text; Operation checked root bg --brand-match matches. The disabled+hover suppression is a REGISTERED divergence (translation/divergences.md#dropdown-disabled-hover-preview-state) — correctly NOT flagged. CANONICAL-013 (chip-close/clear inline span) does NOT apply to this component (it's SelectBoxBase/InputBoxBase). Net: structurally sound color/geometry fidelity; the open issues are composition-reuse (Multi checkbox) + a11y (no roles/keyboard) + the in-flight composite-layer fix, all already tracked."
  },
  {
    "component": "FormItem.vue (canonical wrapper → src/components/FormItem/FormItem.vue base)",
    "verifierCovered": true,
    "overallFidelity": "medium",
    "findings": [
      {
        "dimension": "color-token",
        "severity": "high",
        "summary": "Status=Error does not turn the form label red. Figma error variants render the label/required text in red (#ea4233 dark / #dc2717 light), but the base component has NO `.form-item--error .form-item__label` rule — the label stays `var(--fi-label)` (text-tips / text-2) in error state. Only the field border and the helper message switch to red.",
        "existingBacklogId": "CANONICAL-019",
        "suggestedFix": "Add `.form-item--error .form-item__label { color: var(--red); }` (theme-aware token resolves #ea4233 dark / #dc2717 light). This is exactly the real code drift half of CANONICAL-019(b).",
        "codeEvidence": "src/components/FormItem/FormItem.vue:253 — only `.form-item--error .form-item__field { border-color: var(--red-hover); }` exists; grep for `form-item--error` finds NO `__label` rule. `.form-item__label` color is fixed at `var(--fi-label)` (line 200).",
        "figmaEvidence": "form_item__1923_50705.json Status=Error variants (e.g. id 1923:49069 Input/2lines, plus 200px/120px error variants); required-marker text fill hex=#ea4233 token --red; render-verification.report.json CANONICAL-019 records 32× textFillHex error label #ea4233/#dc2717 expected vs code #cccccc/#434343."
      },
      {
        "dimension": "geometry",
        "severity": "low",
        "summary": "Tracked verifier-config rootGap mismatch: verifier reads `.form-item` root (gap=0) but Figma 1-line variants have auto-layout gap=8, which the code correctly places on the inner `.form-item__main` (`gap: var(--sp-xs)` = 8px). Token value matches Figma; this is a verifier rootTargetSelector issue, NOT a code drift. Reported only to confirm it is benign.",
        "existingBacklogId": "CANONICAL-019",
        "suggestedFix": "Per CANONICAL-019(a): change verifier rootTargetSelector to `.form-item__main` (or measure the inner row). No component change. Closes 48 false-positive A entries.",
        "codeEvidence": "src/components/FormItem/FormItem.vue:183 `.form-item__main { gap: var(--sp-xs); }`; --sp-xs:8px (variables.css:95). Outer `.form-item` has no gap.",
        "figmaEvidence": "form_item__1923_50705.json: all `Layout=1 line` variants gap=8, layoutMode HORIZONTAL; 2-line variants gap=null (code uses gap:0 — matches)."
      },
      {
        "dimension": "composition-reuse",
        "severity": "medium",
        "summary": "The Input / Selector / Textarea fallback previews are hand-rolled markup (`.form-item__field` + `.form-item__field-text` + manual resize-handle gradient) instead of reusing canonical InputBox*/SelectBox* components, even though Radio/Checkbox/Switch fallbacks correctly reuse the canonical Radio/Checkbox/Switch. This is the default-slot placeholder (real consumers pass content via <slot>), so impact is bounded, but it duplicates field surface/border/placeholder styling that should come from InputBoxBase/SelectBoxBase.",
        "existingBacklogId": null,
        "suggestedFix": "Replace the inline field preview with InputBoxBase (textarea variant) / SelectBoxBase fallbacks so the field surface, radius, placeholder color and the textarea resize affordance inherit from canonical children rather than being re-implemented. Same drift class as CANONICAL-007/012/013 but on a fallback path — track as NEW if pursued.",
        "codeEvidence": "src/components/FormItem/FormItem.vue:115-134 — `<div class=\"form-item__field\">` + `<span class=\"form-item__field-text\">` + `.form-item__resize` gradient handle (style L277-287); contrast with L136-147 which DO reuse <Radio>/<Checkbox>/<Switch>.",
        "figmaEvidence": "form_item__1923_50705.json Type axis = Label & Input / Label & Selector / Label & Textarea (subnodeCount=2, field is a nested Input/Select instance in Figma source)."
      },
      {
        "dimension": "coverage",
        "severity": "low",
        "summary": "FormItem now HAS render-verification coverage (CANONICAL-017 Batch 5, 64 entries) — not audit-invisible. Noted for completeness so it is not re-flagged as missing.",
        "existingBacklogId": "CANONICAL-017",
        "suggestedFix": "No action; coverage exists. Resolve the CANONICAL-019 verifier-config + error-label items to clear the outstanding A entries surfaced by this coverage.",
        "codeEvidence": "scripts/generate-render-verification-manifest.mjs:530-534 COMPONENT_TARGETS entry `codeComponent: 'FormItem'`; render-verification.report.json has 64 FormItem refs.",
        "figmaEvidence": "form_item__1923_50705.json nodeId 1923:50705 mapped; all Type/Layout/Theme/Status/LabelWidth axes enumerated as variants."
      },
      {
        "dimension": "other",
        "severity": "low",
        "summary": "Extraction limitation: this tokenized file flattened FormItem to the variant ROOT node only — it captured the required-marker `*` text fill but NOT the label/field/helper text-node colors (subnodeCount=2, no children array). So label/message/placeholder expected colors cannot be composite-verified from this file; the CANONICAL-019 error-label hex evidence comes from the render-verification report, not this JSON. No multi-layer composite stacks were present (all fills/strokes arrays length<=1), so no composite-layer (EXTRACT-008 class) drift applies here.",
        "existingBacklogId": null,
        "suggestedFix": "If full text-color fidelity verification of FormItem label/message is desired, the tokenization strategy needs to retain descendant text nodes (descendant-geometry/text schema gap, adjacent to EXTRACT-007). Track as NEW EXTRACT-* if pursued.",
        "codeEvidence": "n/a — auditor observation: jq on every variant shows fills:[] strokes:[] on roots and a single-fill required-marker text; no descendant text nodes.",
        "figmaEvidence": "form_item__1923_50705.json every variant: `\"subnodeCount\": 2`, `hasChildrenKey:false`, root fills/strokes empty; only `.text` (the `*` marker) survives tokenization."
      }
    ],
    "verified": [],
    "notes": "FormItem.vue (canonical) is a thin wrapper delegating to src/components/FormItem/FormItem.vue (registered healthy wrapper layer per divergences.md:163). Audit done against the base. Geometry tokens match Figma exactly: root widths 638 (1-line) / 440 (2-line), row gap 8 (--sp-xs), --red #ea4233 = required-marker hex. The one confirmed REAL code drift is the missing `.form-item--error .form-item__label` red rule (CANONICAL-019(b)). The rootGap A-entries are a verifier-config artifact, not code drift (CANONICAL-019(a)). The composition-reuse gap on the Input/Selector/Textarea FALLBACK preview is the only NEW finding worth tracking; Radio/Checkbox/Switch fallbacks already reuse canonical children correctly. No hardcoded hex in the SFC (all colors via tokens). No multi-layer composite stacks in the Figma data. Coverage exists (Batch 5), so not audit-invisible. Overall medium fidelity: one real color-state drift + a bounded composition gap, everything else aligned. READ-ONLY audit; no files modified."
  },
  {
    "component": "InputBoxBase.vue (src/canonical/InputBoxBase.vue)",
    "verifierCovered": false,
    "overallFidelity": "medium",
    "findings": [
      {
        "dimension": "a11y",
        "severity": "medium",
        "summary": "Clear affordance is an inline non-keyboard-accessible <span @click>, not a real button. Keyboard users cannot tab to it; screen readers do not announce it as actionable. Already tracked.",
        "existingBacklogId": "CANONICAL-013",
        "suggestedFix": "Convert to <button type=\"button\" aria-label=\"Clear value\" @click.stop=\"clearValue\"><Icon name=\"close\" :size=\"12\" aria-hidden=\"true\"/></button>, or reuse a canonical icon-only Button. Covered by CANONICAL-013.",
        "codeEvidence": "src/canonical/InputBoxBase.vue:84-90  <span v-if=\"showClear\" class=\"input-clear-icon\" @click=\"clearValue\"> <Icon name=\"close\" :size=\"12\" /> </span>  — no tabindex / role / keydown; clearValue() at :58-60.",
        "figmaEvidence": "input box clear affordance — the × clear icon is interactive in the published 'input box/line' & 'input box/filled' sets (figma-to-code-mapping.json:66-76)."
      },
      {
        "dimension": "coverage",
        "severity": "high",
        "summary": "InputBoxBase has ZERO render-verification coverage — not in COMPONENT_TARGETS and absent from render-verification.report.json. Its 6-axis state matrix (darkTheme/status/enable/ux/size/feature) and the wrappers riding on it cannot be machine-verified against Figma.",
        "existingBacklogId": "CANONICAL-017",
        "suggestedFix": "Add InputBoxFilled/InputBoxLine (which fully delegate to InputBoxBase) to COMPONENT_TARGETS so the shared base state matrix gets render-verified. Tracked under CANONICAL-017 (27/34 canonical uncovered).",
        "codeEvidence": "src/canonical/InputBoxBase.vue (whole file) — grep 'InputBoxBase' scripts/generate-render-verification-manifest.mjs => no match; grep in figma-data/normalized/render-verification.report.json => 0 hits.",
        "figmaEvidence": "Wrappers map to published sets 'input box/line' & 'input box/filled' (figma-to-code-mapping.json:66-76, status approved) but no verifier coverage flows through the shared base."
      },
      {
        "dimension": "other",
        "severity": "medium",
        "summary": "InputBoxBase is an undocumented architecture tier: an internal canonical base (wrapped by InputBoxFilled/InputBoxLine, both mapped+approved) that is NOT itself in figma-to-code-mapping.json and has NO divergences.md entry. The wrapper-pattern divergence (divergences.md:163) enumerates 16 legacy-wrapper components and explicitly omits the InputBox family, so an auditor cannot distinguish 'legitimate internal base' from 'unmapped/missing component'.",
        "existingBacklogId": null,
        "suggestedFix": "Add a short divergences.md entry registering InputBoxBase (and SelectBoxBase) as intentional internal canonical bases covered via their Filled/Line wrappers, so audits stop flagging them as unmapped. NEW finding.",
        "codeEvidence": "src/canonical/InputBoxFilled.vue:2,37 and InputBoxLine.vue:2,37 both 'import InputBoxBase from ./InputBoxBase.vue' and render <InputBoxBase>; InputBoxBase imports only Input + Icon (lines 3-4).",
        "figmaEvidence": "figma-to-code-mapping.json maps 'input box/filled'->InputBoxFilled (l68) and 'input box/line'->InputBoxLine (l73); InputBoxBase is in NO mapping entry; divergences.md:163 wrapper list omits InputBox*."
      },
      {
        "dimension": "geometry",
        "severity": "low",
        "summary": "Feature-icon and clear-icon offsets/padding are hand-coded magic numbers (32px / 30px input padding, 10px icon insets, 12px icon size) with no Figma citation in code and no extract-pipeline geometry to verify against. Cannot confirm 1:1 with the Figma feature='yes'/'text count' variant child geometry.",
        "existingBacklogId": "EXTRACT-007",
        "suggestedFix": "Once EXTRACT-007 lands child geometry, verify 32/30/10/12 px against Figma feature='yes' search-icon and clear-icon node positions; replace magic numbers with --sp-* tokens where one matches. Track under EXTRACT-007 padding scope.",
        "codeEvidence": "src/canonical/InputBoxBase.vue:100-130 — '.input-wrap--feature :deep(.tvu-input){padding-left:32px}', '--feature-clear{padding-right:30px}', '.input-feature-icon{left:10px}', '.input-clear-icon{right:10px}'.",
        "figmaEvidence": "InputBoxLine/Filled rootPadding child geometry (72 fields) is blocked on the extract pipeline variant-child geometry schema gap (EXTRACT-007, backlog.md:315); the feature/clear icon insets fall in this same uncaptured child-geometry class."
      }
    ],
    "verified": [],
    "notes": "InputBoxBase is a confirmed INTERNAL canonical base, not a directly-mappable component: InputBoxFilled.vue and InputBoxLine.vue both import and render it, and those two wrappers are the mapped+approved entries for 'input box/filled' / 'input box/line' (figma-to-code-mapping.json:66-76). A direct 1:1 Figma diff of THIS file is not the right frame; the right frame is (a) does it correctly delegate to the mapped wrappers' Figma contract, and (b) is its internal-base status documented.\n\nComposition-reuse: HEALTHY — it reuses canonical Input + Icon rather than hand-rolling an <input>; the only composition gap is the clear <span>, which is an a11y issue (CANONICAL-013), not composition.\n\nColor-token: CLEAN — no hardcoded hex anywhere; icons use color:var(--text-tips) (line 120). No composite-layer drift (no multi-layer fills involved at this layer).\n\nState-matrix: the 6 Figma axes are wired through to <Input> props (disabled/readonly/error/size/variant) at lines 75-82; showClear gating (l46) is plausible but UNVERIFIABLE without render coverage (CANONICAL-017).\n\nNet: two already-tracked findings recur (CANONICAL-013 a11y, CANONICAL-017 coverage); one genuinely NEW low-cost doc finding (register InputBoxBase/SelectBoxBase as internal bases in divergences.md); one geometry item under EXTRACT-007. No new color/composite drift. overallFidelity=medium is driven by the coverage gap + a11y span, not visual color/geometry drift. Do NOT mint new IDs for the a11y / coverage findings."
  },
  {
    "component": "InputBoxFilled (thin wrapper → InputBoxBase → Input.vue); Figma SoT input_box_filled__1436_32815.json",
    "verifierCovered": true,
    "overallFidelity": "medium",
    "findings": [
      {
        "dimension": "geometry",
        "severity": "high",
        "summary": "feature=yes (search-icon) forces input padding-left:32px but Figma rootPadding.left=12px. 32 FAIL entries in render-verification report classified A_TRUE_DRIFT_CANDIDATE. This is the icon-affordance offset that the canonical base hand-rolls via positioned overlay + padding hack instead of reproducing Figma's auto-layout child geometry.",
        "existingBacklogId": "EXTRACT-007",
        "suggestedFix": "Source the feature-icon inset from Figma variant-child geometry once the extract pipeline exposes it; track under EXTRACT-007 (left/right padding for feature fields blocked on variant-child geometry schema gap).",
        "codeEvidence": "src/canonical/InputBoxBase.vue:100-102 `.input-wrap--feature :deep(.tvu-input){padding-left:32px;}`",
        "figmaEvidence": "variant 1436:31692 (dark theme=off,...,feature=yes) check rootPadding.left actual=32 expected=12 pass=false A_TRUE_DRIFT_CANDIDATE (x32 entries)"
      },
      {
        "dimension": "geometry",
        "severity": "high",
        "summary": "feature=yes + showClear forces input padding-right:30px but Figma rootPadding.right=12px. 4 FAIL entries A_TRUE_DRIFT_CANDIDATE. Same class as the left-padding hack — clear-icon overlay reserves 30px instead of the Figma 12px.",
        "existingBacklogId": "EXTRACT-007",
        "suggestedFix": "Derive clear-affordance inset from Figma child geometry rather than a magic 30px; fold into EXTRACT-007 (rootPadding.left/right blocked on extract pipeline variant-child geometry schema gap).",
        "codeEvidence": "src/canonical/InputBoxBase.vue:104-106 `.input-wrap--feature-clear :deep(.tvu-input){padding-right:30px;}`",
        "figmaEvidence": "render-verification.report.json InputBoxFilled FAIL checks rootPadding.right actual=30 expected=12 pass=false A_TRUE_DRIFT_CANDIDATE (x4)"
      },
      {
        "dimension": "a11y",
        "severity": "high",
        "summary": "Clear affordance is a bare <span @click=\"clearValue\"> with no role, tabindex, or key handler — not keyboard operable, not announced. Identical pattern to the InputBoxBase chip-close/clear already tracked. Should reuse a canonical Button/IconButton or at minimum be a real <button type=button> with aria-label.",
        "existingBacklogId": "CANONICAL-013",
        "suggestedFix": "Replace inline span with a keyboard-accessible <button type=button aria-label=\"Clear\"> (or canonical IconButton); add Enter/Space handling. Same fix family as CANONICAL-013.",
        "codeEvidence": "src/canonical/InputBoxBase.vue:84-90 `<span v-if=\"showClear\" class=\"input-clear-icon\" @click=\"clearValue\"><Icon name=\"close\" :size=\"12\" /></span>`",
        "figmaEvidence": "feature=yes click variants (e.g. dark theme=on,status=normal,UX=click,size=M,feature=yes) render a clear/close affordance as an interactive sub-element of input box/filled"
      },
      {
        "dimension": "color-token",
        "severity": "medium",
        "summary": "One render-verification FAIL: light-theme focus, size L, feature=no — textFillHex actual=#9e9e9e (--text-tips/placeholder) but Figma expects #434343 (--color-grey-9 / light --text-2). Likely the focused-but-empty input root resolves placeholder grey where Figma's variant text layer is the darker body/secondary grey. Isolated edge case (1 entry) but flagged as A_TRUE_DRIFT_CANDIDATE, not a verifier skip.",
        "existingBacklogId": null,
        "suggestedFix": "Reconcile the focus/click text color for the light filled L variant against Figma #434343; confirm whether verifier is reading placeholder vs entered-text color (warning notes placeholder is a pseudo-element the verifier can't fully inspect) before changing a token.",
        "codeEvidence": "src/components/Input/Input.vue:118 `.tvu-input::placeholder{color:var(--text-placeholder);}` resolves #9e9e9e in light theme (variables.css:327)",
        "figmaEvidence": "render-verification.report.json InputBoxFilled variant 'dark theme=off,status=default,enable=on,UX=click,size=L,feature=no' theme=light state=focus: textFillHex actual=#9e9e9e expected=#434343 pass=false A_TRUE_DRIFT_CANDIDATE"
      },
      {
        "dimension": "color-token",
        "severity": "low",
        "summary": "Filled background token-name divergence: Figma fill for filled is --line-deep (Color Type/Line/Deep Divider, #353535 dark / #dbdbdb light) but code uses --input-filled-bg = --bg-layer4 (#353535 dark / #dbdbdb light). Hex matches in both themes so it renders correctly (report rootFillHex passes), but the semantic token name diverges from Figma and is not registered in divergences.md. Low risk of drift if the two tokens are ever re-themed independently.",
        "existingBacklogId": null,
        "suggestedFix": "Either alias --input-filled-bg to --line-deep to keep a single source, or add a divergences.md entry documenting the input-filled-bg ↔ line-deep mapping so it isn't future drift.",
        "codeEvidence": "src/components/Input/Input.vue:149-152 `.tvu-input--filled{background:var(--input-filled-bg);}`; variables.css:260 `--input-filled-bg: var(--bg-layer4)` = #353535",
        "figmaEvidence": "variant 1431:54604 default M dark: fills[0].token.cssVar=--line-deep hex #353535; light counterpart fills[0]=--color-white #ffffff"
      },
      {
        "dimension": "state-matrix",
        "severity": "low",
        "summary": "InputBoxBase declares Status type member 'Filled' that does not exist on the Figma status axis (Figma only has status=default | normal). Dead/incorrect axis value risks miscalibrated render-manifest mapping (report warnings already note 'No axis-implementation-map.json entry found for Input.status; mapped by render manifest generator').",
        "existingBacklogId": null,
        "suggestedFix": "Drop the 'Filled' member from the Status union (the filled vs line distinction is the separate `variant` prop), so the typed axis matches the Figma status axis exactly.",
        "codeEvidence": "src/canonical/InputBoxBase.vue:7 `type Status = 'default' | 'normal' | 'Filled'`",
        "figmaEvidence": "jq over input_box_filled__1436_32815.json variant names: status axis only ever 'default' or 'normal' (no 'Filled')"
      }
    ],
    "verified": [],
    "notes": "InputBoxFilled.vue is a 50-line pure pass-through wrapper (InputBoxFilled → InputBoxBase variant=\\\"filled\\\" → Input.vue), a healthy bridge layer per divergences.md:163. The real implementation audited is InputBoxBase.vue + Input.vue. The Input dual-family split (input box/filled ∪ input box/line → single Input component) is a REGISTERED divergence (divergences.md:69-79, id input-dual-family-single-component) — NOT flagged. Coverage: InputBoxFilled IS in COMPONENT_TARGETS (manifest line 135) with 112 report entries (79 PASS_BY_MODE_SKIP, 33 FAIL) — so NOT a CANONICAL-017 coverage gap. Composite-layer check: every variant has exactly 1 visible fill and 0-1 strokes (no multi-layer paint stacks) — clean, no EXTRACT-008/CANONICAL-018 class drift here. Geometry size/padding/cornerRadius are all null in the tokenized JSON (the EXTRACT-007 schema gap), so the authoritative geometry numbers come from the render-verification report rather than the tokenized file. Color tokens for default/error(#ea4233 --red)/focus+hover(#2fb54e --brand) strokes all map correctly. The two padding drifts and the clear-icon a11y are the substantive issues; both map to existing backlog IDs."
  },
  {
    "component": "InputBoxLine (src/canonical/InputBoxLine.vue → InputBoxBase.vue → components/Input/Input.vue)",
    "verifierCovered": true,
    "overallFidelity": "medium",
    "findings": [
      {
        "dimension": "geometry",
        "severity": "high",
        "summary": "feature=yes adds 32px left padding to the input text box, but Figma variant geometry for every feature=yes variant reports pH=12 / pR=12 (same as feature=no). Code's search-icon inset (padding-left:32px) is not reflected in the Figma source value, so all 36 render-verification FAILs for InputBoxLine are dominated by rootPadding.left actual:32 / expected:12 (plus rootPadding.right 30/12 on the clear-icon click state). This is a real visual divergence: the affordance icon is laid over the text area in Figma without reserving 32px of inner text padding.",
        "existingBacklogId": "EXTRACT-007",
        "suggestedFix": "Tracked under EXTRACT-007 (variant child-geometry extract schema gap). Confirm with designer whether the search/clear icons overlay the text (Figma pH=12) vs reserve inset; if overlay is intentional the verifier expectation is correct and code must use a non-padding offset (or accept the 12 expectation). Do not invent a new ID.",
        "codeEvidence": "InputBoxBase.vue:100-106 `.input-wrap--feature :deep(.tvu-input){padding-left:32px} .input-wrap--feature-clear :deep(.tvu-input){padding-right:30px}`",
        "figmaEvidence": "node 1818_8063 variants feature=yes (e.g. 'dark theme=off,...,size=M,feature=yes') pH=12, pR=12, pV=8, pB=8 — identical to feature=no; render-verification.report.json 36 FAIL entries rootPadding.left act:32/exp:12"
      },
      {
        "dimension": "a11y",
        "severity": "high",
        "summary": "The clear (close) affordance is a hand-rolled non-keyboard-accessible <span @click>. It is not a real button, has no role/tabindex/keyboard handler, and is unreachable via keyboard — same drift class as the chip-close/clear affordances already tracked. The search feature icon is also a bare <Icon> with no semantics (acceptable as decorative, but the clear control is interactive).",
        "existingBacklogId": "CANONICAL-013",
        "suggestedFix": "Use a real <button type=\"button\"> (or Button/ButtonBridge canonical) with aria-label for the clear affordance, keyboard-focusable and Enter/Space activatable. Matches CANONICAL-013 remediation pattern.",
        "codeEvidence": "InputBoxBase.vue:84-90 `<span v-if=\"showClear\" class=\"input-clear-icon\" @click=\"clearValue\"><Icon name=\"close\" :size=\"12\" /></span>`",
        "figmaEvidence": "node 1818_8063 feature=yes + status=normal + UX=click variants render a clear control; interactive per UX=click state"
      },
      {
        "dimension": "state-matrix",
        "severity": "medium",
        "summary": "Disabled state color mismatch. Figma enable=off renders BOTH stroke and text in a full-strength grey token (dark --color-grey-8 #595959 / light --color-grey-5 #cccccc) with rootOpacity=1. Code instead applies opacity:0.4 plus --input-disabled-border + --text-tips/--text-disabled, which double-dims the border/text and diverges from the Figma single-token approach. Figma variants show no 0.4 opacity reduction.",
        "existingBacklogId": null,
        "suggestedFix": "Remove opacity:0.4 on disabled (or verify it composites to the Figma hex); drive disabled border/text directly from the grey-8/grey-5 tokens so computed color matches Figma single-layer values without an extra alpha multiply.",
        "codeEvidence": "Input.vue:121-127 `.tvu-input:disabled{border-color:var(--input-disabled-border);color:var(--text-tips);opacity:0.4;...}`",
        "figmaEvidence": "node 1818_8063 'enable=off,UX=default,size=M' strokes #595959/--color-grey-8 (dark) #cccccc/--color-grey-5 (light), text same hex; sample entry rootOpacity expected:1"
      },
      {
        "dimension": "color-token",
        "severity": "medium",
        "summary": "XL textarea (size=XL) text fill drifts in light theme for several states. Verifier FAILs show actual #141414 vs expected #9e9e9e for Filled+error/hover/click XL (light), and actual #cccccc vs expected #141414 for the text-count XL disabled (light). The XL textarea path does not reproduce the per-state text-fill tokens Figma assigns (e.g. Filled XL -> --color-grey-6 #9e9e9e).",
        "existingBacklogId": null,
        "suggestedFix": "Add XL filled/error/hover/text-count text-color rules mapping to the Figma per-state grey tokens; reconcile light-theme disabled text-count expectation (#141414).",
        "codeEvidence": "Input.vue:128-129 only handles `.tvu-input--xl:disabled{color:var(--text-disabled)}` and `.tvu-input--xl.tvu-input--filled:disabled:not(:placeholder-shown){color:var(--text-tips)}`; no rule maps Filled/error/hover XL filled text to grey-6",
        "figmaEvidence": "node 1818_8063 status=Filled,size=XL text fill #9e9e9e/--color-grey-6; render-verification.report.json XL FAIL entries textFillHex act:#141414/exp:#9e9e9e and act:#cccccc/exp:#141414"
      },
      {
        "dimension": "composition-reuse",
        "severity": "low",
        "summary": "The feature/clear icons use raw Icon with hardcoded name=\"search\" and name=\"close\". The search icon name is hardcoded rather than driven from the Figma feature axis (feature=yes implies search affordance) — acceptable but worth noting the feature='text count' branch and any non-search affordance are not represented; the icon choice is an assumption not verified against a Figma vector (the variant file exposes no vectorNodeIds for feature=yes, childCount=0).",
        "existingBacklogId": null,
        "suggestedFix": "Confirm the feature=yes icon is 'search' against the Figma component (icon not present in extracted node data); document the mapping so it is not silent drift.",
        "codeEvidence": "InputBoxBase.vue:72 `<Icon v-if=\"hasFeatureIcon\" name=\"search\" class=\"input-feature-icon\" />`",
        "figmaEvidence": "node 1818_8063 feature=yes variants childCount=0, no vectorNodeIds — icon identity not extractable from this node; search is an inference"
      }
    ],
    "verified": [],
    "notes": "InputBoxLine is a thin pass-through to InputBoxBase, which wraps the legacy Input.vue base (Input.vue carries an audit-canonical-compliance allow-R3 comment and is the registered dual-family divergence 'input-dual-family-single-component' in divergences.md — so the line/filled single-component split is NOT drift). Coverage: InputBoxLine IS in COMPONENT_TARGETS (generate-render-verification-manifest.mjs:148) with 112 report entries (36 FAIL / 76 PASS_BY_MODE_SKIP) — NOT a CANONICAL-017 audit-invisible case. The 36 FAILs decompose cleanly: ~32 are rootPadding.left=32/12 (feature search-icon inset) + 4 rootPadding.right=30/12 (clear-icon) = the geometry finding (EXTRACT-007 family, but note Figma pH actually equals 12, so this is a genuine visual drift the pipeline gap masks, not pure schema noise); 3 XL Filled light textFillHex #141414/#9e9e9e + 1 text-count XL disabled #cccccc/#141414 = the color-token finding. No hardcoded hex found in any of the three files — all colors are CSS-var tokens (passes hard rule #2). No multi-layer composite issue: all fills/strokes/text.fills arrays in this node are length 1. Default border correctly resolves --input-line-border -> --color-grey-8 #595959 matching Figma. Hover/click both map to --brand correctly. The two NEW findings worth tracking are the disabled opacity:0.4 double-dim (state-matrix) and the XL filled/error text-fill token gap (color-token); the clear-icon a11y maps to CANONICAL-013 and the padding to EXTRACT-007."
  },
  {
    "component": "InputNumber (src/canonical/InputNumber.vue → src/components/InputNumber/InputNumber.vue)",
    "verifierCovered": true,
    "overallFidelity": "high",
    "findings": [
      {
        "dimension": "a11y",
        "severity": "medium",
        "summary": "Spinner increment/decrement buttons are real <button> elements with aria-labels (good), but carry tabindex=\"-1\", removing them from the keyboard tab order. A user navigating by keyboard cannot reach or activate the +/- spinbox controls; the value can only be changed by typing in the input. This is a keyboard-accessibility gap on interactive controls (same a11y drift class as CANONICAL-013, though a distinct component).",
        "existingBacklogId": null,
        "suggestedFix": "Remove tabindex=\"-1\" so the spinner buttons are keyboard-focusable/operable, or implement ArrowUp/ArrowDown keydown handlers on the input as the equivalent keyboard path for a spinbox (role=spinbutton pattern).",
        "codeEvidence": "src/components/InputNumber/InputNumber.vue:78 `<button class=\"inputnum-btn\" :disabled=\"!canDecrement\" @click=\"decrement\" tabindex=\"-1\" aria-label=\"decrement\">` and :90 same for increment",
        "figmaEvidence": "Component set inputnumber__4684_7159, variants 4684:7158/7160/7172/7184 each subnodeCount=3 (two spinner buttons + input); spinners are interactive affordances per Property 1=Only Add / Only Reduce variants"
      },
      {
        "dimension": "state-matrix",
        "severity": "low",
        "summary": "Code introduces a disabled visual state via hardcoded `opacity: 0.4` that has no Figma source. Figma defines only 4 Property 1 variants (Default / Only Add / Only Reduce / Readonly) — there is NO disabled variant, so neither the 0.4 opacity nor any disabled token is design-derived. Runtime disabled handling in code is an accepted pattern (divergences.md), but the magic 0.4 is an un-sourced literal.",
        "existingBacklogId": null,
        "suggestedFix": "Confirm the disabled treatment with design; if kept, source the opacity from a token (e.g. an --opacity-disabled token) rather than the inline 0.4 literal, and register as a runtime-only state in divergences.md alongside the existing line-195 pattern.",
        "codeEvidence": "src/components/InputNumber/InputNumber.vue:109-112 `.inputnum--disabled { opacity: 0.4; cursor: not-allowed; }`",
        "figmaEvidence": "jq over variants[].name returns only Property 1=Default/Only Add/Only Reduce/Readonly — no disabled axis/variant exists in inputnumber__4684_7159.json"
      },
      {
        "dimension": "state-matrix",
        "severity": "low",
        "summary": "Hover state on spinner buttons (`background: var(--bg-layer4)`) has no Figma variant source — the component set has no Hover axis. bg-layer4 resolves to #353535 (dark), identical to --line-deep used for the borders, so on hover the button background visually merges with the divider lines. Worth a design confirm; not a hardcoded-hex bug since it uses a token.",
        "existingBacklogId": null,
        "suggestedFix": "Verify the intended hover affordance with design; if a hover bg is desired ensure it differs from the divider/border color so the button reads as distinct on hover.",
        "codeEvidence": "src/components/InputNumber/InputNumber.vue:128-130 `.inputnum-btn:hover:not(:disabled) { background: var(--bg-layer4); }`; --bg-layer4: #353535 and --line-deep: #353535 (variables.css:56,63)",
        "figmaEvidence": "No Hover axis in inputnumber__4684_7159.json variants; only Property 1 axis present"
      }
    ],
    "verified": [],
    "notes": "High fidelity on the audited dimensions. Geometry matches Figma 1:1: w=128px (--input-number-default-width), h=32px (--control-height-xxs), cornerRadius=4 (--r-s), strokeWeight=1 (border 1px --line-deep #353535). Text fill #f8f8f8 → --text-body and Readonly text #7b7b7b → --text-grey-dis match the variant text.fills exactly; font size 14/weight 400/lineHeight 16px all match. NO color-token drift (no hardcoded hex in color paths; all colors tokenized). NO composite-layer issue: every variant has fills=[] (transparent), strokes length=1, and text.fills length=1 — single visible layer each, no multi-paint stack to composite (the `.text length=14` is object-key count, not a paint stack). Composition-reuse: the canonical wrapper importing BaseInputNumber and the spinner +/- icon-color cascade pattern are BOTH registered legal divergences (src/design-system/translation/divergences.md lines 34-35, 163) — not flagged. The R2 hand-rolled +/- markup is whitelisted by the file-top comment referencing CANONICAL-015 (spinner is part of the spinbox primitive). Coverage: PRESENT — InputNumber is in COMPONENT_TARGETS (scripts/generate-render-verification-manifest.mjs:364-371) and appears in render-verification.report.json, so NOT a CANONICAL-017 finding. The 3 reported findings are all minor/medium runtime-state & a11y polish items, none structural."
  },
  {
    "component": "Notification.vue (canonical wrapper) → src/components/Notification/Notification.vue (base impl)",
    "verifierCovered": true,
    "overallFidelity": "medium",
    "findings": [
      {
        "dimension": "color-token",
        "severity": "high",
        "summary": "Light-theme background drifts and ignores the Figma-specified token. Figma fills the container with token --bg-layer4 (light = #dbdbdb). Code light theme uses --notification-bg-light which resolves to --color-grey-2 = #f8f8f8, a different value AND a different token than the one Figma binds. Dark happens to coincide (#353535) but is still routed through a non-Figma token (--notification-bg-dark) rather than --bg-layer4.",
        "existingBacklogId": null,
        "suggestedFix": "Bind .notif--dark and .notif--light background directly to var(--bg-layer4) (theme-aware token already overrides #353535→#dbdbdb), removing the bespoke --notification-bg-dark/light tokens that drift from the Figma-bound variable.",
        "codeEvidence": "src/components/Notification/Notification.vue:178-181 `.notif--light { background: var(--notification-bg-light); ... }`; variables.css:130 `--notification-bg-light: var(--color-grey-2)`; variables.css:11 `--color-grey-2: #f8f8f8`",
        "figmaEvidence": "variant 1408:17124 (theme=dark) / 1408:17126 etc. fills[0].token.cssVar = --bg-layer4 figmaName Color Type/Background/Layer_4; variables.css:337 light override --bg-layer4: #dbdbdb"
      },
      {
        "dimension": "geometry",
        "severity": "medium",
        "summary": "Border width drift. Figma strokeWeight is 1.2px on every variant; code hardcodes border: 1px.",
        "existingBacklogId": null,
        "suggestedFix": "Set border-width to 1.2px (or a token) to match Figma strokeWeight; or register a rounding divergence if 1px is an intentional snap.",
        "codeEvidence": "src/components/Notification/Notification.vue:168 `border: 1px solid var(--line-light);`",
        "figmaEvidence": "variants 1408:17124/17125/17126/17127/17128 all strokeWeight = 1.2000000476837158"
      },
      {
        "dimension": "geometry",
        "severity": "low",
        "summary": "CANONICAL-019 +50px width drift appears RESOLVED. Figma default width = 480, quick-confirm = 280, side-pop = 320. Code tokens --notification-width-default = 480px, --notification-width-side-pop = 320px, and .notif--compact width 280px all match Figma exactly now. No live width drift observed.",
        "existingBacklogId": "CANONICAL-019",
        "suggestedFix": "Close/update the width portion of CANONICAL-019 — width no longer drifts; remaining live drift in this component is the light-bg color and 1.2px border, not width.",
        "codeEvidence": "variables.css:162 `--notification-width-default: 480px`; variables.css:163 `--notification-width-side-pop: 320px`; Notification.vue:185 `.notif--compact { width: 280px }`",
        "figmaEvidence": "variant 1408:17124 w=480; 1408:17128 w=280; 1408:17127 w=320"
      },
      {
        "dimension": "coverage",
        "severity": "low",
        "summary": "Render-verification coverage now EXISTS (not audit-invisible). Notification is registered in COMPONENT_TARGETS (CANONICAL-017 Batch 4) with axes theme/status and has 56 references in render-verification.report.json. No coverage finding.",
        "existingBacklogId": "CANONICAL-017",
        "suggestedFix": "None — coverage satisfied. Confirms CANONICAL-017 Batch 4 landed for this component.",
        "codeEvidence": "scripts/generate-render-verification-manifest.mjs:454-460 `figmaName: 'Notification' ... codeComponent: 'Notification'`",
        "figmaEvidence": "figma-data/normalized/render-verification.report.json contains 56 Notification references"
      },
      {
        "dimension": "composite-layer",
        "severity": "low",
        "summary": "No composite-layer drift detectable. All inspected fills/strokes/text.fills arrays have length 1 (single SOLID layer), so the bottom-up composite rule (EXTRACT-008/CANONICAL-018 class) is not triggered for Notification.",
        "existingBacklogId": null,
        "suggestedFix": "None.",
        "codeEvidence": "Notification.vue:172-182 single-layer background/border per theme; no stacked paints to composite",
        "figmaEvidence": "variant 1408:17126 fills length=1 (#353535 --bg-layer4), strokes length=1 (#434343 --line-light); title text.fills length=1 (--text-body)"
      },
      {
        "dimension": "other",
        "severity": "low",
        "summary": "Per-child geometry/color of action buttons, description text, and danger/confirm fills cannot be fully audited from this tokenized file — each variant exposes only one aggregated .text object (the title) and no nested child node fills/sizes. Button danger uses --red, confirm uses --brand, desc uses --text-tips; these are plausible but unverified against Figma due to extract granularity (same variant-child-geometry gap class as EXTRACT-007).",
        "existingBacklogId": "EXTRACT-007",
        "suggestedFix": "When the extract pipeline gains variant-child node geometry/paint (EXTRACT-007 scope), re-audit button/desc/close colors and the secondary-button border (--line-light dark / --line-deep light) against Figma child nodes.",
        "codeEvidence": "Notification.vue:241-319 desc color --text-tips, button --brand/--red/--text-primary-btn; close icon color --icon-default",
        "figmaEvidence": "variant 1408:17125 .text is a single object (title only, --text-body); no child node array with desc/button fills present in notification__1408_17154.json"
      }
    ],
    "verified": [
      {
        "summary": "Light-theme background drifts and ignores the Figma-specified token. Figma fills the container with token --bg-layer4 (light = #dbdbdb). Code light theme uses --notification-bg-light which resolves to --color-grey-2 = #f8f8f8, a different value AND a different token than the one Figma binds. Dark happens to coincide (#353535) but is still routed through a non-Figma token (--notification-bg-dark) rather than --bg-layer4.",
        "real": false,
        "correctedSeverity": "not-a-drift",
        "reason": "The claim's central Figma premise is false. The auditor says the light Notification variant binds --bg-layer4 (#dbdbdb). The actual data in figma-data/normalized/components-tokenized/notification__1408_17154.json shows every theme=light variant (e.g. 1408:17130 info, 1408:17132 pop confirm) binds token --bg-layer2 / Color Type/Background/Layer_2 / #f8f8f8 — NOT --bg-layer4/#dbdbdb. The cited variant nodeIds 1408:17124 and 1408:17126 are both theme=dark variants (info, pop confirm), so the auditor read a dark variant's --bg-layer4 token and misattributed it to the light theme. Code light (--notification-bg-light -> --color-grey-2 = #f8f8f8) exactly matches the true Figma light value #f8f8f8; code dark (--notification-bg-dark -> --color-grey-10 = #353535) exactly matches Figma dark --bg-layer4 #353535. Both rendered hex values MATCH Figma. The only divergence is a bespoke token-alias name, not a color value, and the alias resolves to the correct hex. The suggested fix (bind both themes to --bg-layer4) would actually INTRODUCE a drift by changing light bg from the correct #f8f8f8 to #dbdbdb. All fills are single-layer SOLID (no composite concern). Cited code lines are accurate, but the Figma evidence was matched against the wrong token/variant."
      }
    ],
    "notes": "Canonical Notification.vue (src/canonical/Notification.vue) is a thin Figma-aligned wrapper around BaseNotification (src/components/Notification/Notification.vue); the wrapper layer is a registered healthy pattern (divergences.md:163), so all substantive audit applies to the base impl. State-matrix and a11y are healthy: close affordance is a real <button type=button aria-label=Close> (no CANONICAL-013-class inline-span drift), actions are real buttons. Geometry (padding 16/24, gap 40/24/12, radius 6, widths 480/280/320) matches Figma 1:1. Two LIVE drifts remain: (1) light-theme background #f8f8f8 vs Figma --bg-layer4 #dbdbdb and use of bespoke --notification-bg-* tokens instead of the Figma-bound --bg-layer4 [HIGH]; (2) 1px border vs Figma 1.2px strokeWeight [MEDIUM]. The CANONICAL-019 +50px width drift is no longer reproducible — token is 480px = Figma; recommend updating that backlog entry to drop the width item and re-scope to the bg/border drifts. Buttons/native <button> usage is acceptable here since there is no published canonical Button reuse contract referenced for Notification's internal actions, but worth confirming against CANONICAL-007 Button work in flight. Did not edit/run anything (read-only)."
  },
  {
    "component": "Pagination (src/canonical/Pagination.vue → src/components/Pagination/Pagination.vue)",
    "verifierCovered": true,
    "overallFidelity": "high",
    "findings": [
      {
        "dimension": "coverage",
        "severity": "medium",
        "summary": "Figma extract is structurally shallow: the variant captures only root geometry + the total-count label text. subnodeCount=3 but zero children are extracted, so the page-number buttons, prev/next arrows, ellipsis, Go-to jumper Input and page-size Select have NO Figma source-of-truth values. The render-verification 'PASS' therefore only validates rootWidth/radius/gap/fill + .pg-total textFillHex; every interactive sub-element is audit-invisible. Coverage exists but is depth-limited — sub-element drift cannot be detected.",
        "existingBacklogId": null,
        "suggestedFix": "Re-run the Figma extract with child-node descent for Pagination (or register a known extract-depth limitation entry alongside EXTRACT-007), so the page-button active/default state, arrow icon, and jumper/selector geometry get a verifiable Figma anchor instead of relying on Button/Input/Select canonical inheritance.",
        "codeEvidence": "src/components/Pagination/Pagination.vue:153-178 renders <Button> page numbers, <Icon name=previous/next> arrows, <span class=pg-ellipsis>, <Input> jumper — none of these have a Figma counterpart in the extract.",
        "figmaEvidence": "pagination__4894_7210.json: all 3 variants (4884:7181 Classic / 4907:6738 Small / 4894:7211 Simple) have subnodeCount=3 but no .children array; only .text captures 'characters: 1-20 of 1,299' bound to --text-tips. fills=[] strokes=[] at root."
      },
      {
        "dimension": "geometry",
        "severity": "low",
        "summary": "Root height differs from Figma: Figma root h=32 (single 32px row), code computed rootHeight=88 because .pagination uses flex-wrap:wrap and at the 652px test width wraps into ~3 rows. The verifier records actual=88 vs expected=32 but classifies it pass-by-mode-skip ('Figma root sizing is HUG'). The skip is reasonable, but the 56px delta means the rendered layout does not reproduce Figma's single-line composition at the documented variant width.",
        "existingBacklogId": null,
        "suggestedFix": "Confirm with design whether Pagination is intended to wrap; if Figma is authoritative single-row, the wrap should be a documented responsive divergence rather than silently absorbed by the HUG skip.",
        "codeEvidence": "src/components/Pagination/Pagination.vue:197-203 .pagination { display:flex; ... flex-wrap: wrap; gap: var(--sp-l) } — wrapping is what produces 88px.",
        "figmaEvidence": "pagination__4894_7210.json variant 4884:7181 w=652 h=32 layoutMode=HORIZONTAL; render-verification.report.json rootHeight actual=88 expected=32 status=pass-by-mode-skip."
      },
      {
        "dimension": "geometry",
        "severity": "low",
        "summary": "Nav-button and ellipsis box sizing use raw magic px (width:32px / min-width:32px / height:32px) and icon 16px, while the project already tokenizes other Pagination dimensions (--pagination-pagesize-selector-width 120px, --pagination-jumper-input-width 64px, --pagination-simple-nav-width 80px) and a matching --control-height-xxs:32px token exists. Inconsistent token discipline within the same component; no hardcoded hex (not a color bug), and Figma provides no per-button anchor so this is a maintainability gap not a confirmed visual drift.",
        "existingBacklogId": null,
        "suggestedFix": "Replace literal 32px/16px with existing tokens (--control-height-xxs / --pagination-* family or a new --pagination-page-button-size) for internal consistency.",
        "codeEvidence": "src/components/Pagination/Pagination.vue:235-239 .pg-nav-row :deep(.btn){width:32px;min-width:0;padding-inline:0} ; :241-247 .pg-arrow__icon{width:16px;height:16px} ; :253-254 .pg-ellipsis{min-width:32px;height:32px}",
        "figmaEvidence": "src/tokens/variables.css:152-154 --pagination-* width tokens defined; :202 --control-height-xxs:32px exists; pagination__4894_7210.json has no child geometry to anchor the 32/16px values."
      }
    ],
    "verified": [],
    "notes": "Pagination is a HEALTHY wrapper: src/canonical/Pagination.vue is a thin bridge over src/components/Pagination/Pagination.vue, an architecture pattern explicitly registered in src/design-system/translation/divergences.md:163 (Breadcrumb/CheckBox/.../Pagination wrap legacy impl) — NOT a CANONICAL-007/012/013-class drift. Composition-reuse is GOOD: page buttons use Button.vue, arrows use Icon.vue, jumper uses Input.vue, page-size uses Select.vue — no hand-rolled markup, no native <button>. No hardcoded hex anywhere; all colors are tokens (--text-tips, --r-s, Button canonical-color 'gray 1'/'green'). No multi-layer composite paints in the Figma data (checked: 0 fills/strokes/text.fills arrays with length>1) so no EXTRACT-008/CANONICAL-018-class composite drift. Coverage: Pagination IS in COMPONENT_TARGETS (scripts/generate-render-verification-manifest.mjs:268), so it is NOT a CANONICAL-017 gap. Verifier status across all 3 variants x 2 themes = PASS / PASS_BY_MODE_SKIP, 0 hard findings. textFillHex #9e9e9e matches --text-tips exactly; rootRadius 4=--r-s, rootGap 24=--sp-l all pass. The only substantive concern is that the Figma extract is shallow (root + total label only), so the verifier's pass cannot speak to the page buttons / arrows / jumper — those rely entirely on inherited Button/Input/Select fidelity. a11y is sound: arrows are real <Button> with aria-label Previous/Next; jumper is real <Input> with keydown.enter+blur submit. No a11y, state-matrix, or color-token drift found. All 3 findings are NEW (no existing backlog ID matches; EXTRACT-007 is InputBox-specific, CANONICAL-019 does not list Pagination)."
  },
  {
    "component": "PillCounter.vue (src/canonical/PillCounter.vue)",
    "verifierCovered": false,
    "overallFidelity": "unknown",
    "findings": [
      {
        "dimension": "coverage",
        "severity": "medium",
        "summary": "PillCounter has ZERO render-verification coverage. grep 'PillCounter' in scripts/generate-render-verification-manifest.mjs returns nothing, and it is absent from figma-data/normalized/render-verification.report.json. Audit-invisible per the CANONICAL-017 class. Note: because it is a code-first bridge with no Figma SoT (see other finding), pixel verification has no expected baseline to diff against yet — coverage here would be self-referential until Figma ships Pill/Counter.",
        "existingBacklogId": "CANONICAL-017",
        "suggestedFix": "Track under CANONICAL-017. Do NOT add to COMPONENT_TARGETS yet — defer until Figma library ships Pill/Counter (BRIDGE-MOCKUP-003), otherwise the verifier diffs code against itself.",
        "codeEvidence": "scripts/generate-render-verification-manifest.mjs — no 'PillCounter' match (grep empty); render-verification.report.json — no 'PillCounter' match",
        "figmaEvidence": "No Pill/Counter node in any figma-data/normalized/*.json (grep -ril 'pill' returns nothing); figma-to-code-mapping.json has no Pill entry (37 mappings, only 'Badge' is adjacent)"
      },
      {
        "dimension": "other",
        "severity": "medium",
        "summary": "No Figma source-of-truth and no registered mapping/divergence entry. PillCounter is a legitimate code-first bridge (BRIDGE-MOCKUP-003: 'code-leads-figma-pending'), but it has no entry in src/design-system/translation/divergences.md and no entry in figma-data/figma-to-code-mapping.json. The audit contract says an un-mapped component should be flagged. Since the file header explicitly documents the code-first/Figma-pending status, this is a tracking gap, not visual drift — but the pending status should be recorded in the divergences registry so it isn't perpetually flagged as 'unmapped drift' by future audits.",
        "existingBacklogId": null,
        "suggestedFix": "Add a divergences.md (or mapping status:'figma-pending') entry recording Pill/Counter + Pill/Status as BRIDGE-MOCKUP-003 code-first pending, so audits classify them as 'intentionally unmapped' rather than 'missing mapping drift'.",
        "codeEvidence": "PillCounter.vue:1-7 header 'ships code-first. Same pending-Figma status as PillStatus'; Pill.vue:8-10 'BRIDGE-MOCKUP-003 (2026-05-19): code-leads-figma-pending'",
        "figmaEvidence": "figma-to-code-mapping.json: jq '.mappings[]' shows no Pill/Counter; divergences.md: grep -i 'pill|counter' returns nothing"
      },
      {
        "dimension": "state-matrix",
        "severity": "low",
        "summary": "Semantic color mismatch for the 'warning' kind. warning maps to bgColor:'red'/dotColor:'red', overloading the danger/error red for a warning state. Pill.vue's DotColor union already includes 'orange' (and --orange / --orange-bg tokens exist), the conventional warning hue. Conflating warning with red removes the warning/error distinction. Cannot confirm against Figma (none exists), so this is a convention-consistency flag, not a verified Figma drift.",
        "existingBacklogId": null,
        "suggestedFix": "Reconsider warning→red. If warning is meant to be amber, add --msg-bg-orange and map warning to orange; otherwise confirm with design that warning/error intentionally share red and record the decision. Low priority — blocked on Figma SoT.",
        "codeEvidence": "PillCounter.vue:23 case 'warning': return { bgColor: 'red', dotColor: 'red' }",
        "figmaEvidence": "No Figma variant to compare; Pill.vue:15 DotColor includes 'orange'; variables.css:31 --orange, :33 --orange-bg defined and unused by warning. BgColor union (Pill.vue:16) lacks an orange bg token though."
      }
    ],
    "verified": [],
    "notes": "PillCounter is a thin (8-line script) code-first bridge over the internal Pill base; it hand-rolls no canonical-child markup (Pill is the legitimate base, pill__dot is whitelisted R1 per Pill.vue:1 comment). No hardcoded hex — all colors flow through tokens (--msg-bg-brand/red/blue/grey, --brand/--red/--blue/--text-tips), all verified present in variables.css:31-45. No multi-layer composite concern because there is no Figma paint stack at all. overallFidelity = 'unknown' because there is NO Figma source-of-truth to diff against (BRIDGE-MOCKUP-003 code-leads-figma-pending) — fidelity is undeterminable, not high/low. The component is well-formed; the real findings are (1) coverage gap [CANONICAL-017], (2) missing registry entry for its pending status, (3) a convention question on warning→red. Composition-reuse, color-token, composite-layer, geometry, a11y dimensions: all clean."
  },
  {
    "component": "PillStatus.vue (src/canonical/PillStatus.vue → wraps src/components/Pill/Pill.vue)",
    "verifierCovered": false,
    "overallFidelity": "low",
    "findings": [
      {
        "dimension": "color-token",
        "severity": "high",
        "summary": "Semantic status→hue mapping inverts the Figma mockup's own legend. The mockup annotation states 'State Pill (Bi-dir): red = On-air, green = Preview · State Pill (Analyzer): blue = Analyzing'. Code maps Live→brand(green), Preview→blue, Analyzing→blue, and has no red status — so Preview renders blue (Figma says green) and the On-air/red status is missing entirely. BRIDGE-MOCKUP-003 registers the family's EXISTENCE as code-first but does not license this hue re-assignment; it calls the wrapper a 'semantic abstraction from MicroApp State Pill', yet the abstraction contradicts the source hue contract.",
        "existingBacklogId": null,
        "suggestedFix": "Re-map per Figma legend: On-air→red, Preview→brand(green), Analyzing→blue, Inactive→grey; rename 'Live' status to 'On-air' (or register the name+hue split in divergences-decisions.json with explicit value-form mapping). Add the missing red status.",
        "codeEvidence": "src/canonical/PillStatus.vue:22-28 switch: case 'Live' return {bgColor:'brand',dotColor:'brand'}; case 'Preview' return {bgColor:'blue',dotColor:'blue'}; case 'Analyzing' return {bgColor:'blue',dotColor:'blue'}",
        "figmaEvidence": "mockup DtZcMkhNy6qh6jbQQnhreQ.json legend node 'Match by component, not by hue: red = On-air, green = Preview ... blue = Analyzing'; Pill/On-air dot+text color r0.917 g0.259 b0.200 (#EA4233 = --red); Pill/Preview color r0.184 g0.710 b0.306 (#2FB54E = --brand)"
      },
      {
        "dimension": "color-token",
        "severity": "high",
        "summary": "Pill label text color is hard-set to --text-body (near-white in dark / near-black in light) for ALL statuses, but Figma renders the label in the STATUS ACCENT color (On-air text = #EA4233 red, Preview text = #2FB54E green, Inactive text = #9E9E9E grey). The dot is tinted to the accent but the text is not — code only tints background + dot, dropping the text-color channel of the variant.",
        "existingBacklogId": null,
        "suggestedFix": "Drive label color from a per-variant accent token (e.g. --pill-fg set alongside --pill-dot) so text matches the status hue; map grey→--text-tips, brand→--brand, blue→--blue, red→--red.",
        "codeEvidence": "src/components/Pill/Pill.vue:71 '.pill { ... color: var(--text-body); }' — single static color, no per-variant text token",
        "figmaEvidence": "Pill/On-air TEXT 'On-air' fill r0.918 g0.259 b0.200 (#EA4233); Pill/Preview TEXT fill r0.184 g0.710 b0.306 (#2FB54E); Pill/Inactive TEXT fill r0.620 (#9E9E9E) — text color equals status accent, not text-body"
      },
      {
        "dimension": "geometry",
        "severity": "medium",
        "summary": "Padding and typography deviate from Figma. Figma frame padding is L8/R10/T3/B3 (asymmetric, right=10); code uses symmetric 'padding: 2px 8px' (right=8, vertical=2). Font size 12px vs Figma 11px; font-weight 500 vs Figma 600. itemSpacing/gap 6px and radius 999px do match.",
        "existingBacklogId": null,
        "suggestedFix": "Set padding to 3px 10px 3px 8px, font-size 11px, font-weight 600 to match the mockup master.",
        "codeEvidence": "src/components/Pill/Pill.vue:67 'padding: 2px 8px;' line 72 'font-size: 12px;' line 73 'font-weight: 500;'",
        "figmaEvidence": "Pill/On-air|Preview|Inactive: paddingLeft 8, paddingRight 10, paddingTop 3, paddingBottom 3, itemSpacing 6, cornerRadius 999; TEXT style fontSize 11, fontWeight 600"
      },
      {
        "dimension": "coverage",
        "severity": "medium",
        "summary": "PillStatus (and base Pill) have ZERO render-verification coverage — not in scripts/generate-render-verification-manifest.mjs COMPONENT_TARGETS and absent from render-verification.report.json. Audit-invisible; the color/geometry drifts above would not be caught by the existing verifier pipeline.",
        "existingBacklogId": "CANONICAL-017",
        "suggestedFix": "Same class as CANONICAL-017. Note Pill lacks PUBLISHED Figma data so verifier target would need to anchor on the mockup master / data-figma attrs; track under CANONICAL-017 coverage backlog with a note that source is mockup-only until library promotion.",
        "codeEvidence": "grep -n 'PillStatus' / 'pill' scripts/generate-render-verification-manifest.mjs → no matches; grep 'Pill' figma-data/normalized/render-verification.report.json → no matches",
        "figmaEvidence": "n/a — coverage gap; mockup variants Pill/On-air, Pill/Preview, Pill/Inactive exist in DtZcMkhNy6qh6jbQQnhreQ.json as the de-facto truth but no manifest target maps them"
      },
      {
        "dimension": "other",
        "severity": "low",
        "summary": "PillStatus is a code-first component with NO published Figma library mapping (absent from figma-to-code-mapping.json, components-tokenized.index.json, published-vs-code.audit.json). This is legitimately registered as an accepted code-first divergence, so NOT drift — recording for traceability and to anchor the findings above to the right contract scope.",
        "existingBacklogId": null,
        "suggestedFix": "No action on existence. But the registered divergence only covers existence + msg-bg tokens — it does NOT cover the hue-mapping, text-color, or padding/typography deltas, so those remain reportable drifts. Consider expanding the decision entry to pin the exact variant→hue + geometry contract.",
        "codeEvidence": "src/canonical/PillStatus.vue:5-7 'BRIDGE-MOCKUP-003 ships code-first'; src/components/Pill/Pill.vue:8-10 same",
        "figmaEvidence": "divergences-decisions.json id 'pill-component-family-2026-05-19' status accepted-documented-divergence; id 'msg-bg-tinted-dark-set-2026-05-19' covers --msg-bg-* 0.18 tint approach (so background token approach is LEGAL, not flagged)"
      }
    ],
    "verified": [
      {
        "summary": "Semantic status→hue mapping inverts the Figma mockup's own legend. The mockup annotation states 'State Pill (Bi-dir): red = On-air, green = Preview · State Pill (Analyzer): blue = Analyzing'. Code maps Live→brand(green), Preview→blue, Analyzing→blue, and has no red status — so Preview renders blue (Figma says green) and the On-air/red status is missing entirely. BRIDGE-MOCKUP-003 registers the family's EXISTENCE as code-first but does not license this hue re-assignment; it calls the wrapper a 'semantic abstraction from MicroApp State Pill', yet the abstraction contradicts the source hue contract.",
        "real": true,
        "correctedSeverity": "high",
        "reason": "Independently confirmed on both sides. CODE (src/canonical/PillStatus.vue:22-28) maps exactly as claimed: Live→{brand,brand}, Preview→{blue,blue}, Analyzing→{blue,blue}, Inactive→{grey,grey} — no 'red', no 'On-air'. FIGMA mockup figma-data/mockup/DtZcMkhNy6qh6jbQQnhreQ.json contains the cited legend verbatim ('State Pill (Bi-dir): red = On-air, green = Preview · State Pill (Analyzer): blue = Analyzing') plus corroborating per-state token lines (On-air=UX/Red/Default, Preview=UX/Brand/Brand, Analyzing=UX/Blue/Default, Inactive=UX/Grey/grey-7). Actual rendered node fills back the legend: 'Pill / On-air' = r0.918/0.259/0.2 (#EA4233 red), 'Pill / Preview' = r0.184/0.710/0.306 (#2FB54E green/brand), 'Pill / Inactive' = grey. These are single SOLID fills on real repeated FRAME instances, so guard (a) fills[0]-composite and guard (c) preview-only/Is-Parent schema-gap do NOT apply. Guard (b): a divergence IS registered (pill-component-family-2026-05-19 / BRIDGE-MOCKUP-003) but it only licenses the family's code-first EXISTENCE and lists variant names; it does not address or license the hue assignment — so it does not cover this. Two genuine mismatches stand: (1) Preview renders blue while Figma's source legend says green/brand (direct hue inversion); (2) the red On-air state has no code counterpart, and code's green 'Live' collides with Figma's green=Preview. The Pill base already supports 'red' (Pill.vue:15-16), so the suggested fix is feasible."
      },
      {
        "summary": "Pill label text color is hard-set to --text-body (near-white in dark / near-black in light) for ALL statuses, but Figma renders the label in the STATUS ACCENT color (On-air text = #EA4233 red, Preview text = #2FB54E green, Inactive text = #9E9E9E grey). The dot is tinted to the accent but the text is not — code only tints background + dot, dropping the text-color channel of the variant.",
        "real": false,
        "correctedSeverity": "not-a-drift",
        "reason": "The raw color values cited are accurate (verified against figma-data/mockup/DtZcMkhNy6qh6jbQQnhreQ.json: On-air TEXT #EA4233, Preview TEXT #2FB54E, Inactive TEXT #9E9E9E — all matching their status accent, not text-body), and the code fact is also true: src/components/Pill/Pill.vue:70 (claim said :71) hard-sets `color: var(--text-body)` with no per-variant text token. HOWEVER this is not a real drift — it is a registered schema-gap / accepted divergence (failure mode (c)). (1) There is NO Pill component in the canonical/published Figma library — `grep -ril pill figma-data/normalized` returns zero hits and components-tokenized/ has no pill file. The ONLY Pill artifacts are file-local FRAME masters inside a PRODUCT MOCKUP file (Micro-Apps DtZcMkhNy6qh6jbQQnhreQ, \"MicroApp State Pill\"), which mockup-conventions.md and figma-component-catalog.md classify as a downstream consumer file, not the design-system SOT. (2) src/design-system/translation/divergences-decisions.json registers `pill-component-family-2026-05-19` with status `accepted-documented-divergence`: figmaSide explicitly states \"Library does not yet have Pill/Status nor Pill/Counter components; current usage is file-local masters in product mockup files,\" and PillStatus/PillCounter ship code-first under BRIDGE-MOCKUP-003 (user-approved 2026-05-19, code-leads-figma-pending). Both PillStatus.vue and Pill.vue carry the BRIDGE-MOCKUP-003 header confirming this. The auditor compared canonical code against a non-canonical product mockup for a component family that intentionally leads Figma — there is no published library component to drift from. The variant hue mapping is itself an already-accepted divergence (code uses brand/blue/grey bg+dot vs mockup red/green/grey), so the text-color observation is downstream of a registered decision, not a new mismatch."
      }
    ],
    "notes": "Pill has NO published Figma component — the only Figma truth is the product mockup file figma-data/mockup/DtZcMkhNy6qh6jbQQnhreQ.json, which contains file-local masters Pill/On-air, Pill/Preview, Pill/Inactive (no 'Live'/'Analyzing' frames, but a legend node defines Analyzing→blue). Two divergence entries (pill-component-family-2026-05-19, msg-bg-tinted-dark-set-2026-05-19) legitimately license the code-first existence and the --msg-bg-* 0.18-tint background token approach — those are NOT flagged. The background fill in Figma is accent@0.18 opacity composited over page bg; code's --msg-bg-* tokens are the pre-composited equivalents (legal per BRIDGE-MOCKUP-001). The real drifts are: (1) variant→hue mapping inverts the mockup legend (Preview should be green not blue; On-air/red missing; 'Live' is not a Figma status name); (2) label text color is static --text-body instead of the per-status accent the mockup uses; (3) padding 2px 8px vs Figma 8/10/3/3 and font 12/500 vs 11/600. Coverage gap rolls under CANONICAL-017. Audit is READ-ONLY; no files edited. Severity-capped at the 5 most load-bearing findings."
  },
  {
    "component": "PopupBox.vue",
    "verifierCovered": true,
    "overallFidelity": "high",
    "findings": [],
    "verified": [],
    "notes": "Verified clean — no drifts found. Canonical src/canonical/PopupBox.vue is a thin pass-through wrapper over src/components/PopupBox/PopupBox.vue (base). All audit dimensions check out against figma-data/normalized/components-tokenized/popup_box__1939_43682.json (variants Theme=Dark 1939:43644, Theme=Light 1939:43606):\n\n- color-token: box fill dark #1f1f1f (grey-12) / light #f8f8f8 (grey-2) -> code background:var(--bg-layer2) (variables.css:54 #1f1f1f, :335 #f8f8f8). border dark #595959 (grey-8) / light #f0f0f0 (grey-3) -> var(--line-border) (:62 #595959, :343 #f0f0f0). title text dark #f8f8f8 / light #141414 -> color:var(--text-body) (:43 #f8f8f8, :324 #141414). All match; zero hardcoded hex in <style scoped> (PopupBox.vue:239-319) — hard rule #2 satisfied.\n\n- geometry: Figma r=4 -> border-radius:var(--r-s) (=4px, variables.css:107). strokeWeight=1 -> border 1px (:258). width=680 -> default width:680 (PopupBox.vue base:24). title font 600 16px/24px Roboto -> --text-style-pop-title:600 16px/24px (variables.css:233). All match.\n\n- composition-reuse: footer uses canonical Button (variant ghost-gray + fill-green, base:221-231); close affordance uses canonical Icon name='close' (base:211). No hand-rolled child markup — hard rule #3 satisfied.\n\n- a11y: dialog has role='dialog' aria-modal='true' aria-labelledby + tabindex='-1' (base:196-199); close is a real <button type='button' aria-label='Close'> (base:204-209); full focus trap, ESC handling, body scroll lock (base:91-180). Strong.\n\n- composite-layer: all fills/strokes/text.fills arrays are length 1 (single SOLID layer) — no multi-layer composite to flag (rule #4 N/A here).\n\n- coverage: present in COMPONENT_TARGETS as CANONICAL-014 (scripts/generate-render-verification-manifest.mjs:576-597, rootTargetSelector '.popup-box', textTargetSelector '.popup-box__title'). Not audit-invisible.\n\nNon-finding caveat: Figma extract has pV/pB/gap = null and captured no child nodes (subnodeCount=2 but children not extracted). The dialog's vertical paddings (header/body/footer via --sp-xs/--sp-l) and the 3-layer drop shadow (-> --shadow-l1 dark / --shadow-l2 light, base:266/270) therefore cannot be value-compared against Figma from this file. This is the known EXTRACT pipeline root-autolayout/child-geometry gap (same class noted for Tooltip at manifest:412, EXTRACT-007), not a code drift — code values are reasonable and use tokens. No new backlog entry warranted; the 6 previously-fixed drifts are not reintroduced."
  },
  {
    "component": "Progress (src/canonical/Progress.vue → src/components/Progress/Progress.vue)",
    "verifierCovered": true,
    "overallFidelity": "medium",
    "findings": [
      {
        "dimension": "color-token",
        "severity": "high",
        "summary": "Regression against an ACCEPTED-DOCUMENTED divergence (progress-pseudo-theme-accepted-divergence). The T1b fix deleted the prop-driven `.progress--light/.progress--dark` selectors and the `progress--${theme}` class because Figma's dark/light Progress variants are visually identical (label fills both #cccccc). The current code has reintroduced BOTH, creating a prop-driven track-bg fork (dark=var(--line-deep), light=var(--color-grey-4)) that does not exist in Figma. The decision's own verifyHint expects these tokens to be ABSENT.",
        "existingBacklogId": null,
        "suggestedFix": "Restore T1b: remove `progress--${theme}` from the :class binding and delete the `.progress--dark`/`.progress--light` selectors so the vestigial theme prop is truly visual-noop; resolve track-bg from a single theme-aware token driven by the document ThemeProvider, not the prop.",
        "codeEvidence": "src/components/Progress/Progress.vue:47 `:class=\"[`progress--${normalizedSize}`, `progress--${theme}`]\"`; :72-78 `.progress--dark { --progress-track-bg: var(--progress-track-bg-dark); } .progress--light { --progress-track-bg: var(--progress-track-bg-light); }`",
        "figmaEvidence": "all 16 variants identical at top level; only paints across whole file are #000000 (transparent container, opacity 0) and #cccccc label (--color-grey-5). No dark/light visual delta. divergences-decisions.json id=progress-pseudo-theme-accepted-divergence verifyHint: grep progress--light|progress--${theme} should return nothing."
      },
      {
        "dimension": "composite-layer",
        "severity": "medium",
        "summary": "Per-status bar fill color and the track-background color are NOT verifiable from the tokenized data: every variant reports subnodeCount=2 but children=[] (track and fill sub-nodes not extracted). Code maps success→var(--brand) (success bar = green, identical to default) and track-bg to an admitted placeholder. Whether Figma's success/error/warning bars and track really equal these values cannot be confirmed — extract-pipeline variant-child paint gap, same class as EXTRACT-007.",
        "existingBacklogId": "EXTRACT-007",
        "suggestedFix": "Keep tracking under EXTRACT-007 / T1c: extend the extract pipeline to capture variant track+fill sub-node paints, then verify success→brand and the track-bg token against the real Figma sub-node colors rather than the placeholder.",
        "codeEvidence": "src/components/Progress/Progress.vue:25-33 fillColor switch (error→var(--red), warning→var(--orange), success/default→var(--brand)); variables.css:142 `--progress-track-bg-dark: var(--line-deep);  /* visual fix (CANONICAL-004); figma sub-node 真源 pending T1c */`",
        "figmaEvidence": "progress__4915_7287.json every variant subnodeCount=2 children=[]; unique hex across entire file = [\"#000000\",\"#cccccc\"] only — no green/red/orange bar fill captured."
      },
      {
        "dimension": "geometry",
        "severity": "low",
        "summary": "Track/fill border-radius and per-size track height live in unextracted sub-nodes (root r=null; h=16 is whole component incl. label, identical for size M and S). Code uses radius 20px, track-h M=8/S=4, but these cannot be cross-checked: the size axis produces no top-level geometry delta (M and S variants are identical at root). Flagging so the size axis is not mistaken for a verified match.",
        "existingBacklogId": "EXTRACT-007",
        "suggestedFix": "Capture sub-node radius and per-size track height in the extract pipeline (T1c) so the 8/4px and 20px radius values can be verified against Figma instead of being asserted.",
        "codeEvidence": "src/components/Progress/Progress.vue:35-37 trackHeight S=var(--progress-track-h-s)/M=var(--progress-track-h-m); variables.css:183-185 --progress-track-h-m:8px; --progress-track-h-s:4px; --progress-track-radius:20px",
        "figmaEvidence": "progress__4915_7287.json variant root r=null, h=16, w=240, gap=8 for ALL variants incl. size=S; no size-axis geometry difference captured."
      }
    ],
    "verified": [
      {
        "summary": "Regression against an ACCEPTED-DOCUMENTED divergence (progress-pseudo-theme-accepted-divergence). The T1b fix deleted the prop-driven `.progress--light/.progress--dark` selectors and the `progress--${theme}` class because Figma's dark/light Progress variants are visually identical (label fills both #cccccc). The current code has reintroduced BOTH, creating a prop-driven track-bg fork (dark=var(--line-deep), light=var(--color-grey-4)) that does not exist in Figma. The decision's own verifyHint expects these tokens to be ABSENT.",
        "real": true,
        "correctedSeverity": "high",
        "reason": "Independently verified as a real regression against the registered accepted-documented divergence `progress-pseudo-theme-accepted-divergence`. CODE: src/components/Progress/Progress.vue line 47 binds `progress--${theme}` and lines 72-78 define `.progress--dark { --progress-track-bg: var(--progress-track-bg-dark) }` / `.progress--light { --progress-track-bg: var(--progress-track-bg-light) }`, exactly as cited. These resolve (src/tokens/variables.css:142-143) to dark=var(--line-deep) #353535 vs light=var(--color-grey-4) #dbdbdb — a genuine prop-driven track-bg color fork. FIGMA: progress__4915_7287.json contains exactly 16 variants (8 dark + 8 light) and only two distinct SOLID paints across the whole file — #000000 @opacity-0 (transparent container) and #cccccc (--color-grey-5, label). Recursive comparison of theme=dark vs theme=light default/size=M variants yields identical paint sets [#000000@0, #cccccc@1]; there is no dark/light track-bg delta in Figma. The decision's verifyHint (grep -rnE 'progress--light|progress--${theme}' on this file) expects EMPTY but currently returns matches on lines 47 and 76, confirming the regression. Git corroborates: commit f5941f24 'fix(Progress): remove self-invented dark/light visual divergence' (T1b) deleted exactly `progress--${theme}` from the class binding and the `.progress--light` selector; they have since been reintroduced. Escape hatches excluded: max fills-array length is 1 (no composite/fills[0] false positive), zero isParent/preview nodes (real runtime variants, not schema-gap), and it is the regression-against-a-registered-divergence case, not a mistaken flag of the divergence itself. The token comment 'figma sub-node 真源 pending T1c' itself concedes the Figma source for a track-bg distinction is unresolved, reinforcing that the fork is code-invented."
      }
    ],
    "notes": "Verified MATCHES (not findings): label gap Figma 8 → var(--sp-xs)=8px; label text Roboto 400 12/16 → var(--text-style-tips)=400 12px/16px; label color Figma --color-grey-5 (#cccccc) → --progress-label-color: var(--color-grey-5). No hardcoded hex. No composition-reuse issue (track/fill/label are primitives, no canonical child to reuse). No a11y finding within the audited contract (non-interactive display component; Figma has no interactive affordance — adding role=progressbar/aria-valuenow would be an enhancement, not a Figma drift). Render-verification coverage EXISTS (manifest lines 228-234, CANONICAL-017 Batch 1) so CANONICAL-017 does NOT apply. The canonical→Base wrapper import is a registered healthy divergence (divergences.md line 163). Dominant issue is the high-severity theme-selector regression silently reverting the T1b accepted-divergence fix; recommend re-applying T1b and wiring its verifyHint grep into a pre-commit guard to prevent recurrence."
  },
  {
    "component": "PromptMessage",
    "verifierCovered": true,
    "overallFidelity": "medium",
    "findings": [
      {
        "dimension": "color-token",
        "severity": "high",
        "summary": "Success-status background is hardcoded to the LIGHT hex and used identically in both themes, instead of binding the theme-varied --brand-match token that Figma actually maps the success fill to. The other 3 statuses correctly consume theme-aware bg tokens (--blue-bg/--red-bg/--orange-bg); only success is inconsistent. Result: success prompt renders #f1fbf3 (light pale-green) on the dark theme, whereas Figma's --brand-match resolves to #0b2b13 in dark.",
        "existingBacklogId": null,
        "suggestedFix": "Replace --prompt-success-bg with the canonical theme-aware token Figma points to (var(--brand-match), or the --green-bg alias which already = var(--brand-match) at line 261), so success bg flips with theme like the other 3 statuses.",
        "codeEvidence": "src/components/PromptMessage/PromptMessage.vue:31-34 success.background = 'var(--prompt-success-bg)'; src/tokens/variables.css:262-263 comment '状态色（固定语义，dark/light 两 theme 同值）' + '--prompt-success-bg: #f1fbf3;' defined once under :root only",
        "figmaEvidence": "variant 1408:17150 (status=success,size=L) fills[0].hex=#f1fbf3 token.cssVar='--brand-match' figmaName='UX/Brand/Match,Hover'; --brand-match is theme-varied in variables.css (line25 #0b2b13 dark / line306 #f1fbf3 light)"
      },
      {
        "dimension": "color-token",
        "severity": "high",
        "summary": "All four status text colors use single-value --prompt-*-text tokens (defined once under :root, comment says 'dark/light same value'), frozen at the dark/default hex. Figma maps the text fills to theme-varied semantic tokens (--blue/--red/--orange/brand). So in light theme the bg shifts (theme-aware) but text stays the dark-theme hex — bg/text fall out of sync. Already documented as a verifier limitation under CANONICAL-017.",
        "existingBacklogId": "CANONICAL-017",
        "suggestedFix": "Map text colors to the theme-aware semantic tokens Figma uses (var(--blue)/var(--red)/var(--orange)/success-green) instead of frozen --prompt-*-text, OR add [data-theme=light] overrides for the --prompt-*-text block. Matches the fix already noted in the render-verification manifest note.",
        "codeEvidence": "src/components/PromptMessage/PromptMessage.vue:37,41,45,33 text: 'var(--prompt-info-text)' etc.; variables.css:264-267 --prompt-info-text:#3892f3 (== --blue DARK value) etc., no [data-theme=light] override",
        "figmaEvidence": "variant 1408:17143 text.fills[0].hex=#3892f3 token.cssVar='--blue'; --blue theme-varied #3892f3 dark (line34) vs #0473d5 light (line315); same pattern --red #ea4233/#dc2717, --orange #f68512/#e26601"
      },
      {
        "dimension": "coverage",
        "severity": "low",
        "summary": "PromptMessage HAS render-verification coverage (CANONICAL-017 Batch 3, status/size axes) — not audit-invisible. Recorded for completeness; the only coverage caveat is the documented dark-theme token limitation captured in the manifest note, tracked under CANONICAL-017.",
        "existingBacklogId": "CANONICAL-017",
        "suggestedFix": "No new coverage work needed; resolve the dark-theme token note via the color-token fixes above.",
        "codeEvidence": "scripts/generate-render-verification-manifest.mjs:416-419 'CANONICAL-017 Batch 3 — PromptMessage. Figma axes: status / size.' codeComponent:'PromptMessage'",
        "figmaEvidence": "componentSetId 1408:17153, 8 variants (status x4 * size x2) all enumerated"
      }
    ],
    "verified": [
      {
        "summary": "Success-status background is hardcoded to the LIGHT hex and used identically in both themes, instead of binding the theme-varied --brand-match token that Figma actually maps the success fill to. The other 3 statuses correctly consume theme-aware bg tokens (--blue-bg/--red-bg/--orange-bg); only success is inconsistent. Result: success prompt renders #f1fbf3 (light pale-green) on the dark theme, whereas Figma's --brand-match resolves to #0b2b13 in dark.",
        "real": false,
        "correctedSeverity": "not-a-drift",
        "reason": "All cited code and Figma facts are individually accurate, but the framing as a drift is wrong: this is a registered, intentional divergence (concern b). Code verified: src/components/PromptMessage/PromptMessage.vue:31-32 binds success.background='var(--prompt-success-bg)' while the other 3 statuses use --blue-bg/--red-bg/--orange-bg; src/tokens/variables.css:263 defines --prompt-success-bg:#f1fbf3 once under the :root (dark default) block with the comment 'dark/light 两 theme 同值' and does NOT redefine it in the [data-theme=light] block (290+), so it stays #f1fbf3 in both themes; --brand-match is theme-varied (#0b2b13 dark / #f1fbf3 light) and --green-bg=var(--brand-match). Figma verified: variant 1408:17150 (status=success,size=L) is a real COMPONENT with a single solid opaque fill #f1fbf3 mapped to --brand-match (UX/Brand/Match,Hover) — single layer, so no fills[0]-only/composite false positive (a) and not a preview/parent node (c). Decisive: docs/internal/phase-6.2a-token-mapping-plan.md:41 explicitly documents the decision to introduce the fixed token --prompt-success-bg instead of --brand-match with rationale '现有 --brand-match 会随全局 theme 变化，不适合固定成功消息背景' (brand-match's theme-variance is unsuitable for a fixed success-message background); src/design-system/translation/token-aliases.ts:250 codifies it as {dark:null, light:'--brand-match'} (deliberately no dark binding); docs/internal/phase-6.2b-execution-report.md confirms it was executed as a category-C semantic token. The team deliberately chose NOT to let success bg flip with theme — the exact opposite of the auditor's suggested fix. Mechanically true observation, but a documented, accepted design divergence, not a Figma-vs-code mismatch."
      }
    ],
    "notes": "Audited src/canonical/PromptMessage.vue (thin wrapper) + its implementation src/components/PromptMessage/PromptMessage.vue against figma-data/normalized/components-tokenized/prompt_message__1408_17153.json (8 variants: status[success/info/error/warning] x size[M/L]).\n\nPASSES (no drift): (1) Geometry exact — Figma pH=16/pV=12 → padding var(--sp-s) var(--sp-m)=12px 16px; gap=8 → --sp-xs; cornerRadius r=4 → --r-s; M max-width 320px == Figma M w=320. L is HUG/content-sized, max-width 480 is a reasonable cap (Figma L w=456). (2) a11y OK — close affordance is a real <button type=button aria-label='Close'> (NOT a CANONICAL-013-class inline <span @click>). (3) Composition — uses canonical Icon.vue for status + close glyphs, not hand-rolled SVG. (4) No multi-layer composite drift — every variant fills/strokes/text.fills array is length 1, so no EXTRACT-008/CANONICAL-018-class composite issue. (5) Icon default-color cascade (color:var(--icon-default) on parent) is a REGISTERED divergence (divergences.md lines 34-35), not flagged. (6) PromptMessage.interact prop = accepted documented divergence (divergences.md §PromptMessage.interact). (7) Wrapper layering (canonical wraps legacy Base) is the accepted healthy bridge pattern (divergences.md line 163).\n\nCore remaining issue is the color-token theme story: success bg + all status text tokens are single-valued (frozen light/dark hex) where Figma points at theme-varied semantic tokens. The text-token half is already tracked under CANONICAL-017's manifest note; the success-bg inconsistency (success uses --prompt-success-bg while peers use theme-aware --*-bg) appears to be a NEW, untracked drift worth a dedicated fix.\n\nREAD-ONLY audit — no files edited, no build/verifier run, no manifest regenerated."
  },
  {
    "component": "Radio (src/canonical/Radio.vue → src/components/Radio/Radio.vue)",
    "verifierCovered": true,
    "overallFidelity": "medium",
    "findings": [
      {
        "dimension": "a11y",
        "severity": "high",
        "summary": "BaseRadio is built on a <label @click.prevent> with a decorative <span class=\"radio-circle\">; there is no native input[type=radio], no role=\"radio\", no tabindex, no aria-checked, and no keyboard handler. The control is mouse-only — not focusable or operable via keyboard, and screen readers get no role/checked state. Same affordance-without-semantics drift class as CANONICAL-013 (inline span @click, not keyboard-accessible).",
        "existingBacklogId": null,
        "suggestedFix": "Render a real role=\"radio\" element (or visually-hidden native <input type=\"radio\">) with tabindex, aria-checked bound to modelValue, aria-disabled, and Space/Arrow key handling; keep the .radio-circle/.radio-dot as the visual layer only.",
        "codeEvidence": "src/components/Radio/Radio.vue:16-27 — <label class=\"radio\" @click.prevent=\"select\"> ... <span class=\"radio-circle\"><span v-if=\"modelValue\" class=\"radio-dot\" /></span>; grep for role/tabindex/input/keydown/focus returned nothing in the file",
        "figmaEvidence": "componentSet 3242:15188 — interactive radio component (variants 374:853-860 across status=on/off, enable=yes/no); an interactive selection control implies focusable + keyboard-operable semantics"
      },
      {
        "dimension": "composite-layer",
        "severity": "medium",
        "summary": "Every variant reports subnodeCount=2 (the circle ring + selected dot), but the tokenized extract surfaces NO children/subnode fills/strokes — only the root layout and the text label paint are present (variant top-level fills/strokes are []). Consequently the code's circle border (--radio-default-border), fill, and dot (--radio-selected-dot) colors cannot be validated 1:1 against Figma; the actual ellipse paint stack is invisible to the audit. Same extract-gap class as EXTRACT-007 (variant-child geometry/paint not surfaced).",
        "existingBacklogId": "EXTRACT-007",
        "suggestedFix": "Extend the extract pipeline to surface variant child (ELLIPSE ring + dot) fills/strokes/strokeWeight so the radio circle, border-width (1.2px), and selected-dot colors become auditable; fold into the EXTRACT-007 variant-child geometry/paint schema work.",
        "codeEvidence": "src/components/Radio/Radio.vue:53 border: var(--radio-circle-border-width) solid var(--radio-default-border); :64 .radio-dot background: var(--radio-selected-dot) — these reference circle subnode colors with no Figma counterpart in the extract",
        "figmaEvidence": "radio__3242_15188.json variant 374:856 — \"subnodeCount\": 2, but jq has(\"children\")==false and root fills:[] strokes:[]; grep across file: only 8 'subnode' count keys, zero ELLIPSE/circle/dot paint data"
      },
      {
        "dimension": "state-matrix",
        "severity": "low",
        "summary": "Code defines a CSS transition for box-shadow/border on .radio-circle implying a focus ring, and a status=off+enable=no branch that fakes the ring via inset box-shadow with transparent border, yet (a) no :focus / :focus-visible rule actually exists, and (b) Figma exposes no hover/focus/active variants — only status x enable. The off+disabled border-substitute (inset shadow) is plausible but unverifiable given the missing circle subnode paint (see composite-layer finding).",
        "existingBacklogId": null,
        "suggestedFix": "Either add a real :focus-visible ring style (and back it to a token), or drop the unused box-shadow transition; confirm the disabled-off inset-border treatment once circle subnode paint is extracted.",
        "codeEvidence": "src/components/Radio/Radio.vue:58 transition: border-color ..., box-shadow ...; :73-77 [status=off][enable=no] .radio-circle { background: var(--control-disabled-bg); border-color: transparent; box-shadow: inset 0 0 0 1.2px var(--control-disabled-border) }; no :focus rule in <style>",
        "figmaEvidence": "radio__3242_15188.json — only 8 variants over axes dark theme/status/enable; no Hover/Focus/Active axis (contrast: drop-down-list-item exposes Hover=Yes/No in render-verification.report.json)"
      }
    ],
    "verified": [
      {
        "summary": "BaseRadio is built on a <label @click.prevent> with a decorative <span class=\"radio-circle\">; there is no native input[type=radio], no role=\"radio\", no tabindex, no aria-checked, and no keyboard handler. The control is mouse-only — not focusable or operable via keyboard, and screen readers get no role/checked state. Same affordance-without-semantics drift class as CANONICAL-013 (inline span @click, not keyboard-accessible).",
        "real": true,
        "correctedSeverity": "high",
        "reason": "Verified independently. CODE: src/components/Radio/Radio.vue lines 16-27 are exactly as cited — `<label class=\"radio\" :class=... @click.prevent=\"select\">` wrapping a decorative `<span class=\"radio-circle\">` with `<span v-if=\"modelValue\" class=\"radio-dot\" />`. The select() handler only emits update:modelValue. Grep for role|tabindex|type=\"radio\"|input|keydown|focus|aria- returns NOTHING in both Radio.vue and canonical/Radio.vue, and no native type=\"radio\"/role=\"radio\" exists anywhere in src/. So the control is genuinely mouse-only: not in tab order (no tabindex), no role=\"radio\", no aria-checked, no aria-disabled, no Space/Arrow handler — a real WCAG 2.1.1 (keyboard) + 4.1.2 (name/role/value) failure on a core form control. FIGMA: componentSet 3242:15188 (figmaName \"radio\") is a real interactive control with 8 variants across dark theme × status(on/off) × enable(yes/no) — the genuine runtime counterpart the canonical maps to via data-figma-status/data-figma-enable, NOT an Is-Parent/preview-only schema-gap node. Ruled out all three false-positive traps: (a) not a fills[0]-vs-composite color issue (this is semantic/a11y); (b) not a registered divergence — no backlog entry covers Radio a11y, and the cited CANONICAL-013 covers SelectBox chip/clear (a sibling of the same drift class, validating the classification but leaving this case un-registered); (c) not a schema-gap. Drift is real."
      }
    ],
    "notes": "Geometry and label color match Figma cleanly: root w=66/h=21, gap=8 → code height:21px + gap:var(--sp-xs)=8px; circle 16px / dot 6px / border 1.2px are tokenized (--radio-circle-size/-selected-dot-size/-circle-border-width). Text label token mapping is correct: dark variants map to --text-body (#f8f8f8 dark / #141414 light), disabled to --text-disabled — Figma's dark-off variants normalize the label to --color-grey-13 (#141414) which equals --text-body's light value, so no real drift. COVERAGE: Radio IS in scripts/generate-render-verification-manifest.mjs COMPONENT_TARGETS (CANONICAL-017 Batch 2, lines 320-335, rootTargetSelector '.radio') — NOT a CANONICAL-017 coverage gap. COMPOSITION-REUSE: the Radio.vue→BaseRadio wrapper is a registered healthy bridge layer (divergences.md:163) and the inline .radio-circle/.radio-dot is the leaf radio affordance itself (no lower canonical to reuse), so the inline-markup pattern is NOT a CANONICAL-012-style drift here. The dark theme / enable axes are registered divergences (divergences.md:175,183). Net: medium fidelity — the dominant real issue is the missing keyboard/ARIA semantics; the color fidelity simply cannot be fully confirmed because the circle subnode paint is absent from the extract."
  },
  {
    "component": "Rating.vue (src/canonical/Rating.vue → base src/components/Rating/Rating.vue)",
    "verifierCovered": true,
    "overallFidelity": "high",
    "findings": [
      {
        "dimension": "composite-layer",
        "severity": "medium",
        "summary": "Figma source does not extract the per-star vector fills, so the star colors code uses (--orange for on, --icon-placeholder for off) have NO Figma ground truth to validate against. The tokenized file's only paint is the container fill (transparent #000000 @ opacity 0). subnodeCount=5 with 5 vectorNodeIds, but children/vector fills are not captured by the tokenizer (tokenizationStrategy='variable-id-first-then-hex-fallback'). This is an extract-pipeline gap: the star on/off colors are unverifiable code assumptions, not confirmed 1:1 reproductions.",
        "existingBacklogId": null,
        "suggestedFix": "Extend the tokenizer to capture vector-node fills for icon-bearing variants (or add a Rating entry to the extract backlog) so the star on/off colors can be verified against Figma instead of being a code-side guess.",
        "codeEvidence": "src/components/Rating/Rating.vue:104-105 `--rating-star-on: var(--orange); --rating-star-off: var(--icon-placeholder);` — colors chosen in code, not derived from extracted Figma fills",
        "figmaEvidence": "rating__4935_7294.json variant value=5 (4935:7228): subnodeCount=5, vectorNodeIds=[I4935:7229;1198:3334 ...], but jq '[..|objects|select(has(\"hex\"))|.hex]|unique' returns only [\"#000000\"] (container, opacity 0). No star fill colors extracted."
      },
      {
        "dimension": "coverage",
        "severity": "low",
        "summary": "Rating IS in COMPONENT_TARGETS (CANONICAL-017 Batch 2), so it is render-verified for geometry, but the manifest itself documents that color is NOT actually verified: the verifier reads the .rating root (no text/color node), so the star fill colors pass through unchecked. Coverage exists but is color-blind for this component.",
        "existingBacklogId": "CANONICAL-017",
        "suggestedFix": "Add a textTargetSelector / icon-color probe targeting .rating__star--on .rating__icon svg fill so the verifier asserts the orange star color, closing the color-verification hole noted in the manifest warning.",
        "codeEvidence": "scripts/generate-render-verification-manifest.mjs:360 mapWarnings 'Rating has no text node in Figma; harness limitation — verifier reads .rating root which inherits browser default colour.'",
        "figmaEvidence": "rating__4935_7294.json: variants have text:null and only transparent container fill; verifier rootTargetSelector '.rating' has no color to assert against."
      },
      {
        "dimension": "composition-reuse",
        "severity": "low",
        "summary": "Each star is a hand-rolled native <button> + <Icon> rather than a canonical child. Normally R2/composition-reuse would flag native <button> over Button/ButtonBridge, but here it is intentional and explicitly whitelisted for keyboard a11y, and the affordance (a rating star) has no canonical equivalent. Implementation is a11y-correct (type=button, aria-pressed reflecting committedValue, aria-label, focus-visible ring, mouse+focus handlers). Not a drift — recorded only to show it was reviewed.",
        "existingBacklogId": null,
        "suggestedFix": "No change — keep the whitelisted native-button-per-star pattern; it is the correct a11y affordance for a rating control.",
        "codeEvidence": "src/components/Rating/Rating.vue:1 `<!-- audit-canonical-compliance: allow R2 file — each star is intentionally a native button for kbd a11y -->`; lines 69-94 native <button> per star with :aria-pressed and :aria-label",
        "figmaEvidence": "rating__4935_7294.json variant value=5: 5 vector star subnodes, no button/canonical-child semantics in Figma to map to."
      }
    ],
    "verified": [],
    "notes": "Rating is a thin canonical wrapper (registered wrapper-layer pattern in divergences.md:163, so the wrapper itself is not drift) over base src/components/Rating/Rating.vue. Geometry matches Figma 1:1: gap=4 → --sp-xxs (4px), star size 24 → --rating-star-size (24px), value=5 width 136 = 5×24 + 4×4. Figma r=null; code applies --r-s radius only on focus ring (acceptable, not a visible-state drift). No hardcoded hex — all colors are tokens (--orange, --icon-placeholder, color-mix focus ring), theme-aware via :root/[data-theme=light]. Icons correctly use TVU library icons mark/star-on and mark/star (confirmed present in dist/icons/svg/mark/). State matrix (readonly/disabled/hover/focus) is implemented and matches the single Figma axis (value=1..5; Figma has no separate hover/disabled variants). Overall fidelity high; the two real concerns are (1) star colors are unverifiable because the tokenizer does not extract vector-node fills, and (2) the existing render-verification coverage explicitly does not assert color. No new visual drift found."
  },
  {
    "component": "SelectBoxBase.vue",
    "verifierCovered": true,
    "overallFidelity": "medium",
    "findings": [
      {
        "dimension": "state-matrix",
        "severity": "high",
        "summary": "Disabled state applies a global opacity:0.4 fade to the entire trigger, but Figma's disabled variants use per-token full-opacity colors (stroke #595959 opacity 1, text #9e9e9e opacity 1, filled bg #353535 opacity 1) with NO global transparency. The 0.4 fade dims border/text/bg/icons uniformly, diverging from the designed disabled palette.",
        "existingBacklogId": null,
        "suggestedFix": "Remove opacity:0.4; rely on the already-correct disabled tokens (--select-disabled-border for stroke, --text-tips for text). Let Figma's disabled colors carry the affordance instead of a blanket fade.",
        "codeEvidence": "src/canonical/SelectBoxBase.vue:234-239 .select-trigger:disabled { border-color: var(--select-disabled-border); color: var(--text-tips); cursor: not-allowed; opacity: 0.4; }",
        "figmaEvidence": "select_box_line variant 'dark theme=on, status=multi select, enable=off, UX=default, size=M' strokes[0].hex=#595959 opacity=1, text.fills[0].hex=#9e9e9e opacity=1; filled disabled fills[0]=#353535 opacity=1 — no node-level opacity reduction"
      },
      {
        "dimension": "state-matrix",
        "severity": "medium",
        "summary": "Filled variant disabled state shows a grey border that Figma's filled-disabled variant does not have. .select-wrap--filled sets border-color:transparent, but the unconditional :disabled rule overrides it with --select-disabled-border (grey-8 #595959), painting a visible border on a variant whose Figma strokes array is empty.",
        "existingBacklogId": null,
        "suggestedFix": "Scope the disabled border-color to line variants only (e.g. .select-wrap--line .select-trigger:disabled), keeping filled-disabled border transparent to match Figma.",
        "codeEvidence": "src/canonical/SelectBoxBase.vue:263-266 .select-wrap--filled .select-trigger { border-color: transparent } vs :234-235 .select-trigger:disabled { border-color: var(--select-disabled-border) } (applies to filled too)",
        "figmaEvidence": "select_box_filled variant 'dark theme=on, status=multi select, enable=off, UX=default, size=M' strokes: [] (no border), fills[0]=#353535"
      },
      {
        "dimension": "a11y",
        "severity": "high",
        "summary": "Multi-select chip remove (.select-chip__close) and single clear (.select-clear) are inline <span @click.stop> with no role/tabindex/keyboard handler — not focusable or operable via keyboard. Already tracked.",
        "existingBacklogId": "CANONICAL-013",
        "suggestedFix": "Replace inline spans with real <button type=\"button\"> (or Button/ButtonBridge) with aria-label; add keyboard activation. Tracked under CANONICAL-013.",
        "codeEvidence": "src/canonical/SelectBoxBase.vue:181-186 <span class=\"select-chip__close\" @click.stop=\"removeSelected(...)\"> and :192-194 <span class=\"select-clear\" @click.stop=\"clearSingleValue\">",
        "figmaEvidence": "select_box_line/filled multi select & feature variants expose interactive close/clear affordances (status=multi select, UX=click variants present)"
      },
      {
        "dimension": "color-token",
        "severity": "low",
        "summary": "Disabled placeholder text uses --text-disabled (#595959 dark) while Figma's disabled text token is --text-tips (#9e9e9e). Figma does not differentiate placeholder vs value color in the disabled state; code introduces a darker placeholder not present in the source.",
        "existingBacklogId": null,
        "suggestedFix": "Drop the placeholder-specific disabled override so disabled text consistently uses --text-tips, matching Figma's single disabled text token.",
        "codeEvidence": "src/canonical/SelectBoxBase.vue:245-247 .select-trigger:disabled .select-value--placeholder { color: var(--text-disabled); }",
        "figmaEvidence": "select_box_line disabled variant text.fills[0].hex=#9e9e9e token=--text-tips (single text token for disabled, no placeholder split)"
      },
      {
        "dimension": "composition-reuse",
        "severity": "low",
        "summary": "Trigger uses a native <button> and inline <Icon> markup rather than a canonical Button/ButtonBridge. For a select trigger this is acceptable (it is a custom combobox affordance, not a Button instance), and no Figma Button component maps here — noting for completeness, not a hard drift.",
        "existingBacklogId": null,
        "suggestedFix": "No action required; native button is appropriate for the combobox trigger. Ensure aria-haspopup=\"listbox\" is added for completeness.",
        "codeEvidence": "src/canonical/SelectBoxBase.vue:166-172 <button type=\"button\" class=\"select-trigger\" :disabled=\"isDisabled\" :aria-expanded=\"isOpen\" @click=\"toggle\">",
        "figmaEvidence": "select box/line + select box/filled are standalone select components (no embedded Button/ component instance in variants)"
      }
    ],
    "verified": [
      {
        "summary": "Disabled state applies a global opacity:0.4 fade to the entire trigger, but Figma's disabled variants use per-token full-opacity colors (stroke #595959 opacity 1, text #9e9e9e opacity 1, filled bg #353535 opacity 1) with NO global transparency. The 0.4 fade dims border/text/bg/icons uniformly, diverging from the designed disabled palette.",
        "real": true,
        "correctedSeverity": "medium",
        "reason": "Confirmed on both sides. CODE: src/canonical/SelectBoxBase.vue:234-239 contains exactly `.select-trigger:disabled { border-color: var(--select-disabled-border); color: var(--text-tips); cursor: not-allowed; opacity: 0.4; }`. FIGMA: every disabled (enable=off) variant in figma-data/normalized/components-tokenized/select_box_line__1804_26921.json (a real 144-variant COMPONENT_SET, not Is-Parent/preview) has nodeOpacity:1 with per-token full-opacity colors — dark-on disabled stroke #595959 opacity 1, text #9e9e9e opacity 1; dark-off stroke #cccccc opacity 1, text #595959 opacity 1; the filled disabled variant (1436_35387) has bg fill #353535 opacity 1, text #9e9e9e opacity 1. No node-level transparency anywhere. Token resolution confirms the designed palette is already carried correctly: --select-disabled-border = --color-grey-8 (#595959 dark) / --color-grey-5 (#cccccc light), --text-tips = #9e9e9e (dark) / #595959 (light) — all opacity 1. So the code's opacity:0.4 is an extra blanket fade layered on top of an already-correct palette, which Figma does not specify. False-positive guards cleared: (a) no composite trap — single full-opacity fills/strokes, all opacity 1; (b) not a registered divergence — no entry in published-vs-code.audit.json or the audit doc (component sets only listed as 'approved' mappings); (c) not a schema-gap preview node — real COMPONENT variants with a live runtime disabled state. Suggested fix (remove opacity:0.4, rely on disabled tokens) is sound."
      }
    ],
    "notes": "SelectBoxBase is a legitimate INTERNAL base, correctly registered: divergences.md (Select ↔ select box/filled + select box/line, id select-dual-family-single-component) and figma-to-code-mapping.json maps the public wrappers SelectBoxFilled/SelectBoxLine. Both wrappers ARE in COMPONENT_TARGETS (scripts/generate-render-verification-manifest.mjs:115,125, rootTargetSelector .select-trigger), so the base IS covered indirectly — NOT a CANONICAL-017 coverage gap. Composite-layer (rule 4): verified clean — every fills/strokes/text.fills array across all line + filled variants has length<=1, so no multi-layer composite to mis-render. Geometry (padding/gap/radius/height): variant containers have layout=null/padding=null/size=null in both tokenized and raw data (geometry lives in uncaptured child frames — same extract pipeline limitation as EXTRACT-007); height 32/40px in code could not be confirmed or refuted from data, so NOT flagged. Color tokens verified resolving correctly: line border grey-8 #595959 (dark) / grey-5 (light) matches Figma stroke; brand #2fb54e for hover/click/editable matches; error --red #ea4233 matches; filled bg --input-filled-bg=--bg-layer4=#353535=grey-10 matches Figma. Note CANONICAL-016 (listbox/option role + keyboard nav) lives in DropDownListSelect which this delegates to, not re-flagged here."
  },
  {
    "component": "SelectBoxFilled.vue (thin wrapper over SelectBoxBase.vue — all markup/style lives in base)",
    "verifierCovered": true,
    "overallFidelity": "medium",
    "findings": [
      {
        "dimension": "state-matrix",
        "severity": "high",
        "summary": "Disabled state applies a blanket opacity:0.4 that Figma never specifies. Every enable=off variant in Figma has opacity=1 and instead encodes the dimmed look purely via token-swapped text color (and unchanged bg fill #353535/#ffffff). The 0.4 alpha multiplies over the precise disabled colors, producing a washed-out result that does not match any Figma disabled variant.",
        "existingBacklogId": null,
        "suggestedFix": "Remove opacity:0.4 from .select-trigger:disabled; reproduce the disabled appearance via the exact Figma text/bg tokens per theme+status instead of a global alpha.",
        "codeEvidence": "SelectBoxBase.vue:234-239 `.select-trigger:disabled { border-color: var(--select-disabled-border); color: var(--text-tips); cursor: not-allowed; opacity: 0.4; }`",
        "figmaEvidence": "All enable=off variants (e.g. 'dark theme=on, status=multi select, enable=off, UX=default, size=M' and 'dark theme=off, status=default, enable=off, ...') report opacity=1; fill stays #353535 / #ffffff; only text.fills token changes."
      },
      {
        "dimension": "color-token",
        "severity": "high",
        "summary": "Disabled text color is not status-aware. Figma uses distinct tokens for disabled text: status=default → --color-grey-8 (#595959 dark) / --color-grey-5 (#cccccc light); status=normal & multi select → --text-tips (#9e9e9e dark / #595959 light). Code hardcodes a single --text-tips for the value and --text-disabled for placeholder regardless of status/theme, so the default-status disabled grey-8 / grey-5 is never reproduced.",
        "existingBacklogId": null,
        "suggestedFix": "Branch disabled text color on status (and theme): default-status uses grey-8/grey-5, normal/multi uses --text-tips. Use the registered theme tokens, no hardcoded hex.",
        "codeEvidence": "SelectBoxBase.vue:241-247 `.select-trigger:disabled .select-value { color: var(--text-tips); } .select-trigger:disabled .select-value--placeholder { color: var(--text-disabled); }`",
        "figmaEvidence": "enable=off text.fills: status=default dark=#595959(--color-grey-8) light=#cccccc(--color-grey-5); status=normal/multi dark=#9e9e9e light=#595959 (both --text-tips)."
      },
      {
        "dimension": "a11y",
        "severity": "high",
        "summary": "Multi-select chip remove affordance and the time/date clear affordance are non-keyboard-accessible inline <span @click.stop>, not real buttons. They are nested inside the trigger <button> (invalid interactive nesting) and unreachable via Tab/Enter.",
        "existingBacklogId": "CANONICAL-013",
        "suggestedFix": "Per CANONICAL-013, replace inline spans with real <button type=button> (or canonical Button/icon-button) carrying aria-label, and move them out of the outer trigger button to avoid nested interactive elements.",
        "codeEvidence": "SelectBoxBase.vue:181-186 `<span class=\"select-chip__close\" @click.stop=\"removeSelected(...)\">` and 192-194 `<span class=\"select-clear\" @click.stop=\"clearSingleValue\">`, both inside <button class=\"select-trigger\"> (166).",
        "figmaEvidence": "multi select variants (status=multi select, UX=click/editable) and feature=time/date UX=click variants present chip-close / clear affordances as interactive sub-elements."
      },
      {
        "dimension": "composition-reuse",
        "severity": "medium",
        "summary": "Multi-select dropdown rows render their check affordance via DropDownListSelect's inline span rather than the canonical CheckBox component, surfacing through SelectBoxBase's listType='Multi' path.",
        "existingBacklogId": "CANONICAL-012",
        "suggestedFix": "Track under CANONICAL-012 — DropDownListSelect Multi rows should reuse CheckBox.vue.",
        "codeEvidence": "SelectBoxBase.vue:55 `listType = isMultiSelect ? 'Multi' : 'Radio'` and 198-205 delegates to <DropDownListSelect :type=\"listType\"> whose Multi rows hand-roll the check.",
        "figmaEvidence": "status=multi select variants imply checkbox option rows in the open list; check affordance is a design-system Checkbox."
      },
      {
        "dimension": "color-token",
        "severity": "low",
        "summary": "Multi-select chip styling may not match Figma chip tokens. Figma multi-select text fill is --color-grey-2 (#f8f8f8 dark), while code chips use background var(--input-filled-bg) (= same #353535 as the field, giving near-zero contrast in dark filled) and color var(--text-body). Low confidence because the chip is a Figma subnode (subnodeCount=2) not fully resolvable from this top-level variant data.",
        "existingBacklogId": null,
        "suggestedFix": "Resolve chip subnode paints from Figma (extract child geometry) and confirm chip bg/text contrast; filled chip on a same-color field likely needs a distinct layer token, not --input-filled-bg.",
        "codeEvidence": "SelectBoxBase.vue:340-346 `.select-chip { background: var(--bg-layer4); ... } .select-wrap--filled .select-chip { background: var(--input-filled-bg); }`",
        "figmaEvidence": "status=multi select, enable=on, UX=default, size=M: top-level text.fills hex=#f8f8f8 token=--color-grey-2; field fill=#353535(--color-grey-10). Chip subnode paints not in top-level extract."
      }
    ],
    "verified": [
      {
        "summary": "Disabled state applies a blanket opacity:0.4 that Figma never specifies. Every enable=off variant in Figma has opacity=1 and instead encodes the dimmed look purely via token-swapped text color (and unchanged bg fill #353535/#ffffff). The 0.4 alpha multiplies over the precise disabled colors, producing a washed-out result that does not match any Figma disabled variant.",
        "real": true,
        "correctedSeverity": "high",
        "reason": "Independently confirmed. CODE: SelectBoxBase.vue:234-239 reads exactly as cited, including `opacity: 0.4;` on `.select-trigger:disabled`; SelectBoxFilled.vue imports and renders SelectBoxBase so the rule applies at runtime. FIGMA: probed every enable=off variant under figma-data/normalized/components-tokenized/ (80+ files) — all report root opacity=1, and a full node-tree opacity scan returned exactly [1] with no exceptions (rules out the fills[0]-only composite false-positive: composite agrees). Backgrounds stay #353535 (dark theme=on) / #ffffff (dark theme=off), identical to enabled; the dimmed look is encoded solely via text.fills token swap (#595959 / #9e9e9e / #cccccc). No registered divergence, no intentional-deviation comment, and no audit/whitelist entry for this opacity (grep on SelectBoxBase.vue, published-vs-code-audit.md, and the audit JSON found nothing). The disabled nodes are real COMPONENT variants with runtime counterparts, not Is-Parent/preview-only. The blanket 0.4 alpha multiplies over the already-correct disabled tokens, yielding a washed-out result that matches no Figma disabled variant. Genuine code-only drift."
      },
      {
        "summary": "Disabled text color is not status-aware. Figma uses distinct tokens for disabled text: status=default → --color-grey-8 (#595959 dark) / --color-grey-5 (#cccccc light); status=normal & multi select → --text-tips (#9e9e9e dark / #595959 light). Code hardcodes a single --text-tips for the value and --text-disabled for placeholder regardless of status/theme, so the default-status disabled grey-8 / grey-5 is never reproduced.",
        "real": false,
        "correctedSeverity": "not-a-drift",
        "reason": "The claim is a false positive caused by not resolving the --text-disabled token. CODE (SelectBoxBase.vue): line 242 sets disabled value text to var(--text-tips); line 246 sets disabled placeholder text to var(--text-disabled). So the code does NOT use \"a single --text-tips regardless of status\" — it already branches value vs placeholder. The placeholder/value split is the code's equivalent of Figma's status dimension because the placeholder class is applied on !displayLabel (no value selected) and Figma status=default is exactly the placeholder state (chars \"Select\", enabled=#7b7b7b=--text-placeholder) while status=normal/multi are value states (chars \"Option 1\"). Token resolution (src/tokens/variables.css + token-aliases.ts:264) shows --text-disabled = #595959 dark / #cccccc light = --color-grey-8 / --color-grey-5 — exactly the values the claim says are \"never reproduced.\" And --text-tips = #9e9e9e dark / #595959 light (variables.css:45,326) — exactly the normal/multi disabled values. FIGMA (jq verified, single fill each, no composite issue): status=default disabled dark=#595959(--color-grey-8) light=#cccccc(--color-grey-5); status=normal & multi disabled dark=#9e9e9e light=#595959(--text-tips). Both code branches therefore match Figma in both themes. The only discrepancy is token-naming (Figma authors disabled placeholder as a raw grey-8/grey-5 primitive while code uses the semantic alias --text-disabled that resolves to those same values) — a registered token-level divergence, not a visual/color drift. Cited code line numbers (241-247) and text are accurate, but the conclusion is wrong because the verifier did not resolve --text-disabled."
      }
    ],
    "notes": "SelectBoxFilled.vue is a pure pass-through wrapper that fixes variant='filled' and forwards all props to SelectBoxBase.vue (lines 41-55); zero own markup/style, so all audited drift lives in SelectBoxBase.vue. Coverage: render-verification PRESENT — scripts/generate-render-verification-manifest.mjs:115 `codeComponent: 'SelectBoxFilled'` and 144 hits in figma-data/normalized/render-verification.report.json; so NOT a CANONICAL-017 audit-invisible case.\\n\\nVerified MATCHES (no finding): geometry — Figma M h=32 pH=12 pV=8 gap=8 r=4, L h=40 pH=12 pV=8; code uses padding var(--sp-xs)=8 / var(--sp-s)=12, gap 8px, radius var(--r-s)=4, heights 32/40 (lines 229,231,250,256,223). Multi-select pV=4 reproduced via padding-block: var(--sp-xxs)=4 (line 273), and the dark-on-L pV=8 quirk reproduced by the targeted selector at line 276. Filled bg token chain checks out: dark --input-filled-bg→--bg-layer4→#353535 == Figma --color-grey-10 #353535; light →--bg-layer1→#ffffff == Figma --color-white #ffffff. Error stroke --red (#ea4233) and interactive/click stroke --brand (#2fb54e) match Figma error/click variant strokes. No hardcoded hex found in component CSS — all colors are tokens. divergences.md (DateTime↔Select.feature, Input↔input box family) confirms feature=date/time topology is a registered divergence, not drift.\\n\\nAll fills/strokes/text.fills arrays in this extract are length 1 (single-layer) — no multi-layer composite (CANONICAL-018/EXTRACT-008) drift class applies here. EXTRACT-007 (InputBox rootPadding) does not apply: select padding extracted cleanly."
  },
  {
    "component": "SelectBoxLine.vue (delegates to SelectBoxBase.vue)",
    "verifierCovered": true,
    "overallFidelity": "medium",
    "findings": [
      {
        "dimension": "geometry",
        "severity": "high",
        "summary": "Size=M font-size hardcoded to 13px but Figma specifies 14px for EVERY variant (M and L, all themes/statuses). Code only matches Figma at size=L. The M text renders one pixel too small across the entire matrix.",
        "existingBacklogId": null,
        "suggestedFix": "Set .select-wrap--m .select-trigger font-size to 14px (or drop the per-size font-size override entirely since both sizes are 14px and the base rule already sets 14px). Note base rule line 225 also sets 14px then is overridden to 13/14.",
        "codeEvidence": "SelectBoxBase.vue:249-252 `.select-wrap--m .select-trigger { height: 32px; font-size: 13px; }` vs L:255 `font-size: 14px`",
        "figmaEvidence": "select_box_line__1804_26921.json — text.size=14 for all 72 variants; e.g. id 1804:26940 (multi M) size=14, default M size=14. uniq -c confirms every M/L variant = 14."
      },
      {
        "dimension": "color-token",
        "severity": "high",
        "summary": "Disabled (enable=off) trigger applies a blanket opacity:0.4 that Figma does NOT have. Figma disabled variants keep stroke at opacity 1 (grey-8 dark / grey-5 light) and use a distinct text token (--text-tips #9e9e9e at opacity 1), not a 40%-dimmed version of the enabled colors. The 0.4 multiplier fabricates colors absent from the source.",
        "existingBacklogId": null,
        "suggestedFix": "Remove opacity:0.4 from .select-trigger:disabled. The border/text token swaps already encode the disabled appearance per Figma; the 0.4 over-dims and double-applies on top of correct tokens.",
        "codeEvidence": "SelectBoxBase.vue:234-239 `.select-trigger:disabled { border-color: var(--select-disabled-border); color: var(--text-tips); cursor: not-allowed; opacity: 0.4; }`",
        "figmaEvidence": "id 1804 multi-select enable=off (dark): stroke #595959 opacity:1 (--color-grey-8), text #9e9e9e opacity:1 (--text-tips). No element opacity < 1 anywhere in the disabled variants."
      },
      {
        "dimension": "a11y",
        "severity": "high",
        "summary": "Multi-select chip remove affordance and the date/time clear affordance are non-interactive inline <span @click.stop>, not real buttons — no tabindex, role, or keyboard activation. Keyboard users cannot remove chips or clear the value.",
        "existingBacklogId": "CANONICAL-013",
        "suggestedFix": "Replace inline spans with a real <button type=\"button\"> (or Button/ButtonBridge canonical) carrying aria-label, so close/clear are keyboard-focusable and activatable. Same drift class as CANONICAL-013.",
        "codeEvidence": "SelectBoxBase.vue:181-186 `<span class=\"select-chip__close\" @click.stop=\"removeSelected(...)\"><Icon name=\"close\" .../></span>` and 192-194 `<span class=\"select-clear\" @click.stop=\"clearSingleValue\">`",
        "figmaEvidence": "id 1804:26940 multi-select variant has subnodeCount=2 with close vectorNodeIds (I1804:26944;1155:24637 etc.) — interactive remove affordance is part of the design."
      },
      {
        "dimension": "composition-reuse",
        "severity": "medium",
        "summary": "Multi-select chips are hand-rolled <span class=\"select-chip\"> markup inside the trigger rather than reusing a canonical Chip/Tag component, and the embedded DropDownListSelect carries the multi-check + listbox-role drift already tracked. Surfaced here because SelectBoxLine routes its entire multi/list rendering through SelectBoxBase + DropDownListSelect.",
        "existingBacklogId": "CANONICAL-012",
        "suggestedFix": "Route check affordance through CheckBox canonical and add listbox/option roles in DropDownListSelect (already tracked). Consider a canonical Chip for the trigger chips.",
        "codeEvidence": "SelectBoxBase.vue:174-188 inline `.select-chips`/`.select-chip` markup; line 198-205 `<DropDownListSelect :type=\"listType\" ...>`",
        "figmaEvidence": "select_box_line multi-select variants (id 1804:26940 family) render chips/checked options; check affordance + option role drift lives in the consumed DropDownListSelect."
      },
      {
        "dimension": "state-matrix",
        "severity": "low",
        "summary": "feature=time and feature=date variants exist in the Figma data and SelectBoxLine forwards a `feature` prop, but the registered Select divergence explicitly scopes audit to exclude feature=date|time (moved to DateTime page). Noted for traceability — not counted as drift. Core states (default/error/hover→brand/click→brand/editable→brand/disabled) are all present and the brand-on-interactive mapping matches Figma.",
        "existingBacklogId": null,
        "suggestedFix": "No action — registered divergence. Keep DateTime feature variants audited on the DateTime surface.",
        "codeEvidence": "SelectBoxBase.vue:60-66 feature icon/clear logic; 284-298 interactive/hover/focus → var(--brand)",
        "figmaEvidence": "divergences.md:81 'Select audit ... 不含 feature=date | time（已拆分到 DateTime 的展示页）'; Figma hover/click/editable multi variants all stroke=--brand (matches code)."
      }
    ],
    "verified": [
      {
        "summary": "Size=M font-size hardcoded to 13px but Figma specifies 14px for EVERY variant (M and L, all themes/statuses). Code only matches Figma at size=L. The M text renders one pixel too small across the entire matrix.",
        "real": true,
        "correctedSeverity": "medium",
        "reason": "Verified independently. Code: SelectBoxBase.vue:249-252 sets `.select-wrap--m .select-trigger { height:32px; font-size:13px }`, L (254-256) is 14px, base rule (225) is 14px — exactly as cited. SelectBoxLine.vue imports/wraps SelectBoxBase (lines 2, 41), so this CSS governs it. Figma select_box_line__1804_26921.json: text.size=14 for ALL 72 size=M and ALL 72 size=L variants (jq uniq -c confirmed); cited node 1804:26940 (multi M) = size 14. So size=M code (13px) is genuinely 1px below Figma's 14px across the entire M matrix, while L matches. Not a composite false-positive (scalar font-size, not fills/stroke). No registered divergence/whitelist (audit 'approved' row is just a component-mapping/variant-count registry, no per-property font-size note). No Is-Parent/preview-only M variants. Minor: claim says '72 variants' but file has 144 (72 M + 72 L) — understates the matrix but doesn't change the M-side drift. Suggested fix (set M to 14px or drop the per-size override since both are 14px) is correct."
      },
      {
        "summary": "Disabled (enable=off) trigger applies a blanket opacity:0.4 that Figma does NOT have. Figma disabled variants keep stroke at opacity 1 (grey-8 dark / grey-5 light) and use a distinct text token (--text-tips #9e9e9e at opacity 1), not a 40%-dimmed version of the enabled colors. The 0.4 multiplier fabricates colors absent from the source.",
        "real": true,
        "correctedSeverity": "high",
        "reason": "Confirmed genuine drift. CODE: src/canonical/SelectBoxLine.vue wraps SelectBoxBase.vue (variant=\"line\"), and SelectBoxBase.vue:234-239 contains the cited rule verbatim: `.select-trigger:disabled { border-color: var(--select-disabled-border); color: var(--text-tips); cursor: not-allowed; opacity: 0.4; }`. FIGMA: dark enable=off (1804:27088) is a real COMPONENT runtime variant (not Is-Parent/preview), root opacity 1, single-layer stroke #595959 = --color-grey-8 @ opacity 1, text #9e9e9e = --text-tips @ opacity 1; light enable=off (1804:27106) stroke #cccccc = --color-grey-5, text --text-tips, all opacity 1. A recursive scan for any opacity<1 returned empty across the disabled variants — no element dimming exists in source. Not a fills[0] composite false-positive (single-layer fills/strokes). The token map in variables.css resolves --select-disabled-border to grey-8 (dark)/grey-5 (light), exactly the Figma strokes, and the divergences registry only authorizes the --text-tips/--text-disabled color TARGETS — it does NOT register the opacity:0.4. So the code already encodes the correct Figma tokens at opacity 1 and then the 0.4 multiplier double-applies on top, fabricating dimmed colors (grey-8/grey-5/text-tips at 40%) that Figma never specifies. Suggested fix (remove opacity:0.4) is correct."
      }
    ],
    "notes": "SelectBoxLine.vue is a 1:1 prop-forwarding wrapper over SelectBoxBase.vue (variant=\\\"line\\\" hardcoded); all real markup/style lives in SelectBoxBase, so findings are reported against that file. The Select dual-family single-component split (line+filled) is a registered divergence (divergences.md:77-82) and is NOT flagged. Coverage: SelectBoxLine IS in COMPONENT_TARGETS (manifest line 125) and present in render-verification.report.json (multiple entries) — so verifierCovered=true, no CANONICAL-017 finding. Geometry that MATCHES Figma and was verified: height M=32px/L=40px (Figma h=32/40), gap 8px (Figma gap=8), radius --r-s=4px (Figma r=4), border 1px (Figma strokeWeight=1), padding H=12px=--sp-s (Figma pH=12), multi-select padding-block --sp-xxs=4px (Figma multi pV=4), error stroke --red (Figma #ea4233), multi-select-line-border token split justified (Figma light multi=grey-4 vs default grey-5). The two NEW high-severity drifts (M font-size 13px≠14px, disabled opacity:0.4 fabrication) are unregistered and not covered by any existing backlog ID. fills are empty arrays and strokes/text.fills are all single-layer (length 1) — no composite-layer drift here."
  },
  {
    "component": "src/canonical/Slider.vue (wraps src/components/Slider/Slider.vue)",
    "verifierCovered": true,
    "overallFidelity": "medium",
    "findings": [
      {
        "dimension": "color-token",
        "severity": "high",
        "summary": "Slider value text color is theme-aware in code but STATIC in Figma. Figma text fill token is --color-grey-5 (#cccccc) identically across ALL four variants (dark+light, M+S). Code maps --slider-value-color to var(--text-2), which is #cccccc in dark but #434343 in light theme. On light theme the value reads #434343 vs Figma #cccccc — a real unregistered color drift.",
        "existingBacklogId": "CANONICAL-019",
        "suggestedFix": "Bind --slider-value-color to var(--color-grey-5) (static) instead of var(--text-2), so light theme keeps #cccccc per Figma. Or register a divergence in divergences.md if intentional.",
        "codeEvidence": "src/components/Slider/Slider.vue:87 `--slider-value-color: var(--text-2);` and :215 `color: var(--slider-value-color);`. variables.css:44 --text-2:#cccccc (dark) / :325 --text-2:#434343 (light).",
        "figmaEvidence": "slider__4934_7206.json all 4 variants text.fills[0]: hex #cccccc token --color-grey-5 (id 4934:7194 / 4934:7200 light variants also #cccccc)."
      },
      {
        "dimension": "geometry",
        "severity": "medium",
        "summary": "Slider rendered interactive width does not reliably match Figma 240px. Figma component-set frame w=240 (FIXED) for all variants. The .slider wrapper sets width:240px (with value) / 196px (value-hidden), but the actual <input type=range> falls back to its UA-default width inside the grid, producing the documented ~192px effective render width. No explicit width:240px on .slider__input.",
        "existingBacklogId": "CANONICAL-019",
        "suggestedFix": "Add explicit width:240px (or min-width:0 on the grid input cell) to .slider__input so the range fills the frame; verify rendered width matches Figma 240.",
        "codeEvidence": "src/components/Slider/Slider.vue:84 `width: 240px;` on .slider; :100 width:196px on --value-hidden; .slider__input (:119-134) has no explicit fixed width beyond width:100%/flex:1 which is subject to grid/UA min-width.",
        "figmaEvidence": "slider__4934_7206.json variants w=240 h=16 (M) / h=12 (S), layoutSizingHorizontal FIXED, all four."
      },
      {
        "dimension": "a11y",
        "severity": "low",
        "summary": "Slider relies on aria-label defaulting to literal string 'slider' when no host label is provided. Native input[type=range] is keyboard-accessible (good), but a generic 'slider' label is not meaningful for screen readers when showValue/context is absent. Minor — not a structural a11y defect.",
        "existingBacklogId": null,
        "suggestedFix": "Prefer aria-valuetext/aria-labelledby tied to a real label, or require host to pass aria-label; avoid silent 'slider' fallback.",
        "codeEvidence": "src/components/Slider/Slider.vue:71 `:aria-label=\"($attrs['aria-label'] as string | undefined) ?? 'slider'\"`",
        "figmaEvidence": "slider__4934_7206.json has no label child; value text characters='60' is the only text node — no accessible name source."
      }
    ],
    "verified": [],
    "notes": "Canonical wraps BaseSlider (legitimate wrapper layer per divergences.md:163, NOT a composition-reuse drift). Composition-reuse R3 is explicitly whitelisted: BaseSlider carries `audit-canonical-compliance: allow R3 file` comment (line 1) because slider has no canonical child to reuse (native input[type=range] is the correct primitive). Coverage: PRESENT — Slider is in COMPONENT_TARGETS (generate-render-verification-manifest.mjs:378-392, added CANONICAL-017 Batch 3) and appears in render-verification.report.json. Geometry that MATCHES Figma: column-gap var(--sp-xs)=8px == Figma gap=8; track height tokens --slider-track-h-m=8px / -s=4px and thumb sizes are Figma-sourced (variables.css:176-181, commented 'figma 真源'). No hardcoded hex in either file — all colors via tokens. No multi-layer composite stacks (all fills/strokes/text.fills length 1; root fill opacity 0 transparent placeholder, correctly not rendered). Both real drifts (light-theme value text color, render width) are documented ONLY in the manifest note under CANONICAL-019, NOT registered in divergences.md, so they remain genuine open drifts. Figma variant JSON lacks per-subnode track/thumb geometry (extract carries only root frame w/h/gap), so track-fill exact pixel match could not be independently verified against Figma — limited to root-frame evidence."
  },
  {
    "component": "StepItem.vue (canonical wrapper over src/components/Steps/StepItem.vue)",
    "verifierCovered": true,
    "overallFidelity": "medium",
    "findings": [
      {
        "dimension": "color-token",
        "severity": "high",
        "summary": "Active-state title text uses --text-heading, but Figma's active title text fill is #ffffff mapped to --text-primary-btn. In dark theme both = #ffffff (match), but in light theme --text-heading = #000000 while Figma stays #ffffff. Active title is wrong color in light theme.",
        "existingBacklogId": null,
        "suggestedFix": "Change active title/number color from var(--text-heading) to var(--text-primary-btn) so light theme keeps white text per Figma.",
        "codeEvidence": "src/components/Steps/StepItem.vue:287-290 .step-item--active .step-title { color: var(--text-heading); font-weight: 600; }  // --text-heading: dark #ffffff / light #000000 (variables.css:42,323)",
        "figmaEvidence": "variant 4943:7288 (direction=horizontal, style=icon, state=active) text.fills[0].hex=#ffffff token.cssVar=--text-primary-btn (variables.css:71,352 = #ffffff in BOTH themes)"
      },
      {
        "dimension": "color-token",
        "severity": "high",
        "summary": "Active number marker text color uses --text-heading, but Figma active number ('2') text fill is #ffffff → --text-primary-btn. Same light-theme divergence: code renders #000000 number in light theme, Figma renders white.",
        "existingBacklogId": null,
        "suggestedFix": "Use var(--text-primary-btn) for the active number color (keep border as --text-heading only if Figma stroke confirms; the number glyph must follow --text-primary-btn).",
        "codeEvidence": "src/components/Steps/StepItem.vue:201-204 .step-item--active .step-marker--number { border: 2px solid var(--text-heading); color: var(--text-heading); }",
        "figmaEvidence": "variant 4943:7237 (direction=horizontal, style=number, state=active) text.characters='2' fills[0].hex=#ffffff token.cssVar=--text-primary-btn"
      },
      {
        "dimension": "composition-reuse",
        "severity": "medium",
        "summary": "Completed-state marker hand-rolls a check affordance via inline <Icon name=\"selected\"/> inside a custom .step-marker circle rather than reusing a canonical child. Same hand-rolled-affordance drift class as CANONICAL-007/012/013 (no shared check/badge component reused). Low certainty whether a canonical primitive exists for a step bullet, so flagged medium.",
        "existingBacklogId": null,
        "suggestedFix": "Confirm whether a canonical bullet/check primitive should back the completed marker; if so reuse it instead of inline Icon. Otherwise document as legitimate internal markup. Lower priority than the color drifts.",
        "codeEvidence": "src/components/Steps/StepItem.vue:97-100 <Icon v-if=\"resolvedState === 'completed'\" name=\"selected\" class=\"step-check\" /> inside .step-marker--number circle",
        "figmaEvidence": "variant 4943:7244 (style=number, state=completed) marker shows brand-filled circle with check glyph; title fill #2fb54e/--brand"
      },
      {
        "dimension": "state-matrix",
        "severity": "low",
        "summary": "Verifier coverage exists but its textTargetSelector (.step-num) cannot follow the active-vs-completed text swap: completed renders <Icon name='selected'/> not .step-num, so verifier falls back to root #000 and never validates completed/active title or number color. The two high-severity color drifts above are exactly what this blind spot hides.",
        "existingBacklogId": "CANONICAL-017",
        "suggestedFix": "Add state-conditional textTargetSelector (e.g. .step-title for completed/active title color, .step-num/.step-check for marker) so the verifier actually catches the --text-heading vs --text-primary-btn light-theme drift.",
        "codeEvidence": "scripts/generate-render-verification-manifest.mjs:447 textTargetSelector: '.step-num' + mapWarnings note at line ~450 acknowledging the miss",
        "figmaEvidence": "variants 4943:7244 (completed, text=title #brand) vs 4943:7237 (active, text=number #ffffff) require state-conditional text selectors"
      }
    ],
    "verified": [
      {
        "summary": "Active-state title text uses --text-heading, but Figma's active title text fill is #ffffff mapped to --text-primary-btn. In dark theme both = #ffffff (match), but in light theme --text-heading = #000000 while Figma stays #ffffff. Active title is wrong color in light theme.",
        "real": true,
        "correctedSeverity": "high",
        "reason": "All cited evidence verified independently. CODE: src/components/Steps/StepItem.vue:287-290 reads `.step-item--active .step-title { color: var(--text-heading); font-weight: 600; }` exactly as claimed (note: file is under src/components/Steps/, not src/canonical/; src/canonical/ has no StepItem). CSS tokens confirmed in variables.css: --text-heading = #ffffff (dark, L42) / #000000 (light, L323); --text-primary-btn = #ffffff in BOTH themes (L71, L352). FIGMA: variant 4943:7288 (direction=horizontal, style=icon, state=active) exists in step_item__4943_7310.json; its title text (\"Step Title\") has fills[0].hex=#ffffff, token.cssVar=--text-primary-btn. Ruled out all three false-positive traps: (a) NOT a fills[0]-only composite issue — single SOLID fill, opacity 1, compositeToken=null; (b) NOT a registered divergence — grep of published-vs-code.audit.json and the audit md found no accepted exception for StepItem active title color; (c) NOT a preview/Is-Parent node — type=COMPONENT, a real variant in set 4943:7310 with real text + vector subnodes. Cross-checked sibling active variants (4943:7237 number, 4943:7261 vertical) — all use --text-primary-btn, confirming Figma intent is consistent white. Net: code resolves active title to #000000 in light theme while Figma specifies #ffffff; dark theme matches (#fff=#fff) so the bug is light-theme-only but genuine."
      },
      {
        "summary": "Active number marker text color uses --text-heading, but Figma active number ('2') text fill is #ffffff → --text-primary-btn. Same light-theme divergence: code renders #000000 number in light theme, Figma renders white.",
        "real": true,
        "correctedSeverity": "medium",
        "reason": "Verified independently. CODE: src/components/Steps/StepItem.vue:201-204 (the canonical wraps this base) literally reads `.step-item--active .step-marker--number { border: 2px solid var(--text-heading); color: var(--text-heading); }` — exactly as cited. FIGMA: figma-data/normalized/components-tokenized/step_item__4943_7310.json variant 4943:7237 (direction=horizontal, style=number, state=active) and its vertical twin 4943:7261 both have text.characters='2' with a SINGLE fill (no composite) hex=#ffffff, token.cssVar=--text-primary-btn, strategy=direct-variable-id-map. These are real COMPONENT variants (isParent=null, type=COMPONENT), not preview/parent-only — no schema-gap. No registered divergence/whitelist exists for this case (grep of audit docs empty). Token resolution confirms the real impact: --text-heading = #ffffff in dark (:root, line 42) but #000000 in light theme (line 323); --text-primary-btn = #ffffff in both themes (lines 71, 352). So in dark theme code and Figma both render white (semantic-token-only mismatch), but in LIGHT theme code renders a #000000 number while Figma renders a #ffffff number — a genuine visible divergence, exactly as the claim's light-theme note states. Corroboration: the pending number variant (#7b7b7b / --text-placeholder) matches code's --text-placeholder, showing code normally tracks the Figma glyph token; active is the true outlier. Suggested fix direction (use --text-primary-btn for the number glyph) is sound. Caveat: the white glyph implies Figma's active marker is a filled circle while code renders a transparent bordered circle, so a token swap alone may need a paired background review — but the cited color-token drift itself is real."
      }
    ],
    "notes": "Data schema is flat per-variant (no children tree); geometry/paints live on each variant node. All fills/strokes/text.fills arrays are length 1 — NO multi-layer composite present, so no composite-layer (EXTRACT-008/CANONICAL-018) finding applies here. Geometry checks PASS: horizontal w=120 (code width:120px), vertical w=140 (code 140px), horizontal gap=6 (code gap:6px), vertical gap=12 (code --sp-s=12px). Title font: Figma size14/lh21 weight 400(completed/pending)/600(active) matches code weights. Pending color --text-placeholder and completed --brand both MATCH Figma. The single real defect is the active-state #ffffff → code uses --text-heading instead of --text-primary-btn; correct in dark, wrong (#000000) in light theme — affects both active title (line 288) and active number marker (line 203). divergences.md only covers Steps↔Step/Item container topology (steps-item-container-topology) and the wrapper-layer pattern; it does NOT register a color-form divergence, so the active-color mismatch is unregistered drift. Component IS in COMPONENT_TARGETS (CANONICAL-017 Batch 3) so not audit-invisible, but its textTargetSelector blind spot is why these color drifts were never caught."
  },
  {
    "component": "Steps.vue (canonical wrapper) → BaseSteps (src/components/Steps/Steps.vue) + StepItem (src/components/Steps/StepItem.vue)",
    "verifierCovered": true,
    "overallFidelity": "medium",
    "findings": [
      {
        "dimension": "color-token",
        "severity": "high",
        "summary": "Active step title uses --text-heading but Figma active variants resolve to --text-primary-btn. Both are #ffffff in dark (default) so no visual drift there, but in light theme --text-heading=#000000 while --text-primary-btn=#ffffff — so the active step title (and active number-marker, which also uses --text-heading) renders BLACK in light theme where Figma specifies WHITE. Unregistered token substitution = drift; not covered in divergences.md.",
        "existingBacklogId": null,
        "suggestedFix": "Change active title/marker color from var(--text-heading) to var(--text-primary-btn) to match Figma token and stay white across both themes; or register the substitution in divergences.md if intentional.",
        "codeEvidence": "src/components/Steps/StepItem.vue:287-290 `.step-item--active .step-title { color: var(--text-heading); font-weight: 600; }` and :201-204 `.step-item--active .step-marker--number { border: 2px solid var(--text-heading); color: var(--text-heading); }`; variables.css:42 --text-heading:#ffffff (root/dark) vs :323 --text-heading:#000000 (light), :71/:352 --text-primary-btn:#ffffff (both themes)",
        "figmaEvidence": "variant 4943:7237 (direction=horizontal,style=number,state=active) text.fills[0].token.cssVar='--text-primary-btn' hex #ffffff; same for 4943:7261 (vertical) and 4943:7288 (icon active)"
      },
      {
        "dimension": "state-matrix",
        "severity": "medium",
        "summary": "Pending step title font-weight hardcoded to 400, but Figma number-style pending variants specify fontWeight 600. (Icon-style pending is 400 in Figma and would match, but the code applies a single 400 rule to ALL pending titles regardless of style, so number-pending is under-weight.) Active code weight 600 matches; completed 400 matches.",
        "existingBacklogId": null,
        "suggestedFix": "Set pending title font-weight to 600 for number style (matching active), keeping 400 only for icon style — i.e. make weight style-conditional, e.g. add .step-item--pending.step-item--number .step-title { font-weight: 600 }.",
        "codeEvidence": "src/components/Steps/StepItem.vue:292-295 `.step-item--pending .step-title { color: var(--text-placeholder); font-weight: 400; }`",
        "figmaEvidence": "variant 4943:7230 (horizontal,number,pending) text.fontWeight=600 and 4943:7255 (vertical,number,pending) fontWeight=600; contrast 4943:7277 (horizontal,icon,pending) fontWeight=400"
      }
    ],
    "verified": [
      {
        "summary": "Active step title uses --text-heading but Figma active variants resolve to --text-primary-btn. Both are #ffffff in dark (default) so no visual drift there, but in light theme --text-heading=#000000 while --text-primary-btn=#ffffff — so the active step title (and active number-marker, which also uses --text-heading) renders BLACK in light theme where Figma specifies WHITE. Unregistered token substitution = drift; not covered in divergences.md.",
        "real": true,
        "correctedSeverity": "medium",
        "reason": "Verified independently and the drift holds. CODE (operative styling lives in base src/components/Steps/StepItem.vue, which canonical Steps.vue wraps): line 287-290 `.step-item--active .step-title { color: var(--text-heading); font-weight:600; }` and 201-204 `.step-item--active .step-marker--number { border: 2px solid var(--text-heading); color: var(--text-heading); }` — exactly as cited. TOKENS (src/tokens/variables.css): --text-heading = #ffffff (root/dark, L42) / #000000 (light, L323); --text-primary-btn = #ffffff both themes (L71/L352). FIGMA (figma-data/normalized/components-tokenized/step_item__4943_7310.json): active variants 4943:7237 / 4943:7261 / 4943:7288 are real COMPONENT nodes (not preview/Is-Parent schema gaps), each with a single-SOLID text fill, compositeToken:null, resolving to --text-primary-btn #ffffff — so NOT a fills[0]-vs-composite false positive. Direct Figma evidence: active number-style marker text (\"2\") in 7237/7261 -> --text-primary-btn; active icon-style title text (\"Step Title\") in 7288 -> --text-primary-btn (the extractor captures only one of the 2 subnodes per variant, so the number-style title is inferred from the icon-style title which is confirmed --text-primary-btn). Net: code's --text-heading flips to #000000 (black) in light theme on the active marker and active title, where Figma specifies #ffffff (white) via --text-primary-btn. Dark/default theme is visually identical (both #ffffff), but light theme renders black-on-active = genuine mismatch. divergences.md only registers steps-item-container-topology for Steps, NOT this color-token substitution, so it is unregistered. Suggested fix (switch active title/marker to var(--text-primary-btn)) is valid. Severity corrected to medium rather than high: the mismatch is real and visible but only in the non-default light theme, affects color not layout/function, and the default dark theme is unaffected."
      }
    ],
    "notes": "Steps.vue is a thin wrapper (delegates active/current/direction/stepStyle to BaseSteps via provide/inject). All real markup + styling lives in src/components/Steps/StepItem.vue; the audited Figma file (Step/Item 4943:7310) maps to StepItem, so the substantive comparison is against StepItem. Coverage: StepItem IS in COMPONENT_TARGETS (figmaName 'Step/Item', files step_item__4943_7310.json) as CANONICAL-017 Batch 3 — NOT audit-invisible (note the known harness limitation: completed state swaps .step-num for <Icon name=\"selected\">, so textTargetSelector falls back to root #000; this is a verifier gap not a code drift). Root geometry verified clean: horizontal w=120/gap=6/layoutMode VERTICAL and vertical w=140/gap=12/layoutMode HORIZONTAL all match code exactly (.step-item--horizontal width:120px gap:6px; .step-item--vertical width:140px gap:var(--sp-s)=12px). Marker diameter / connector-line dimensions could NOT be verified — the tokenized variant flattens subnodes (subnodeCount=2, children=0, no per-node fills/sizes extracted), so .step-marker--number 28px, .step-line 40x2px etc. are unverifiable against this file (extract-pipeline limitation, not asserted as drift). Composition-reuse: StepItem uses canonical Icon.vue for check/feature glyphs — no hand-rolled SVG drift. No hardcoded hex anywhere; all colors are tokens. The two findings below are state-matrix color/weight drifts."
  },
  {
    "component": "Switch (src/canonical/Switch.vue → base src/components/Switch/Switch.vue)",
    "verifierCovered": true,
    "overallFidelity": "high",
    "findings": [
      {
        "dimension": "composite-layer",
        "severity": "low",
        "summary": "Figma extract for this component captured root-level fills only for 4 of 18 variants (on/off + enable=yes). All `live` variants and all `enable=no` (disabled) variants have empty root `fills:[]` because the track paint lives on a nested child node the tokenizer did not flatten. Consequently the code's live-track color (--red #ea4233/#dc2717), disabled-on color (--brand-disable #1a652c/#8fcc9d) and disabled-off color (--switch-bg-disabled-off) cannot be 1:1 verified against the Figma source from this file. The code values are architecturally consistent (status=live is a registered runtime divergence) but unverifiable here.",
        "existingBacklogId": "EXTRACT-007",
        "suggestedFix": "Track under EXTRACT pipeline gap (variant-child geometry/paint flattening, same class as EXTRACT-007): tokenizer should composite/flatten the nested track child node's fills onto the root variant so live/disabled track colors become auditable. No code change.",
        "codeEvidence": "src/components/Switch/Switch.vue:75 `.switch--live.switch--on { background: var(--red); }`; :84 `.switch--disabled.switch--on { background: var(--brand-disable); }`; :82 disabled-off uses var(--switch-bg-disabled-off)",
        "figmaEvidence": "variants 337:18249/18248/18247 (status=live) fills=[]; 337:18076/18084 (on,enable=no) fills=[] — only 337:18075(on #2fb54e), 337:18083(on light #299f45), off variants #595959/#9e9e9e captured"
      },
      {
        "dimension": "state-matrix",
        "severity": "low",
        "summary": "State matrix is correctly differentiated and matches the Figma opacity signal: non-live disabled variants carry opacity:1 in Figma (disabled is conveyed by a track COLOR shift, not transparency), while only live+disabled variants use opacity:0.4. Code mirrors this exactly — disabled-on/off shift background color with no opacity, and only `.switch--live.switch--disabled` applies opacity:0.4. This is a positive confirmation, not a drift; recorded for completeness.",
        "existingBacklogId": null,
        "suggestedFix": "No fix needed — code matches Figma opacity/color semantics.",
        "codeEvidence": "src/components/Switch/Switch.vue:81-89 color-only disabled handling; :90-92 `.switch--live.switch--disabled { opacity: 0.4; }`",
        "figmaEvidence": "337:18076/18084/18081/18086 (enable=no, non-live) op=1; 337:18248/18247 (live, enable=no) op=0.4"
      }
    ],
    "verified": [],
    "notes": "High fidelity. Geometry verified 1:1: Figma w=40/h=20/r=100 → tokens --switch-track-w:40px / --switch-track-h:20px / border-radius var(--r-xxl)=100px (variables.css:189-191,111). Thumb travel math checks out: track 40 - thumb 16 - inset 2*2 = 20px → --switch-thumb-travel:20px. Color-token: NO hardcoded hex anywhere; all paints are CSS vars and the captured Figma fills resolve cleanly to the same tokens (#2fb54e/#299f45 → --brand; #595959 → grey-8 dark; #9e9e9e → grey-6 light), theme-aware via .switch--dark/.switch--light var remap (variables.css:145-148). Composition-reuse: GOOD — base is a native <button role=switch aria-checked> with proper :disabled and focus-visible outline; NOT a hand-rolled span affordance. File carries an explicit `audit-canonical-compliance: allow R2` annotation justifying the native button (correct a11y, not the CANONICAL-007/012/013 inline-span drift class). a11y: GOOD — real button, role=switch, aria-checked bound, aria-label fallback, :disabled on disabled||loading, focus-visible outline. Coverage: PRESENT — Switch is in COMPONENT_TARGETS (generate-render-verification-manifest.mjs:302-316, CANONICAL-017 Batch 2) and appears in render-verification.report.json; verifier notes a known harness limitation (native button has no expected text/fill, thumb positioned via padding+transform vs Figma absolute) — that is documented, not a new finding. Registered divergences cover this component (divergences.md:163 wrapper layer, :175 dark theme attr, :183 enable attr, :194 status=live runtime-addition) — none flagged as drift. The two findings are low-severity (extract pipeline gap + a positive state-matrix confirmation); no critical/high drift found."
  },
  {
    "component": "src/canonical/Tab.vue",
    "verifierCovered": true,
    "overallFidelity": "high",
    "findings": [
      {
        "dimension": "coverage",
        "severity": "low",
        "summary": "The canonical Tab.vue container itself has no direct render-verification target, but this is an intentional, documented decision — the verifier covers the TabItem visual unit (figmaName 'Tab/Item') and explicitly skips the container because Figma 'Tab/Item' is 1:1 with the TabItem visual unit. The supplied Figma file (tab_item__4265_16082.json) is item-level data, not container data, so it correctly maps to TabItem coverage. Not a true gap; noted for completeness.",
        "existingBacklogId": "CANONICAL-017",
        "suggestedFix": "No action required; the container's visual unit is already covered via TabItem under CANONICAL-017. Optionally add a one-line note in the manifest cross-referencing the canonical Tab wrapper.",
        "codeEvidence": "scripts/generate-render-verification-manifest.mjs:491 '// Skip Tab (container wrapper) — Tab/Item Figma 1:1 with TabItem visual unit.'; line 494 codeComponent: 'TabItem'",
        "figmaEvidence": "tab_item__4265_16082.json figmaName 'Tab/Item'; covered via manifest entry lines 490-505 and present in render-verification.report.json ~line 82016"
      },
      {
        "dimension": "color-token",
        "severity": "low",
        "summary": "The Line-type container bottom divider in BaseTab uses primitive scale token --color-grey-10 (#353535), whereas the Figma Tab/Item Line active stroke maps to semantic --line-light (#434343 = Color Type/Line/Light Divider) — different value and intent. TabItem's active indicator border correctly uses --line-light, so the discrepancy is only on the static container divider. The provided Figma file is item-level (no container stroke), so this is a low-confidence note, not asserted drift; confirm against the Tab List / container Figma node before acting.",
        "existingBacklogId": null,
        "suggestedFix": "Verify the container divider against the Tab List Figma node; if it is the Light Divider token, swap BaseTab .tab--line/.tab--filled borders from primitive --color-grey-10/--color-grey-12 to the semantic --line-light token for consistency with TabItem.",
        "codeEvidence": "src/components/Tab/Tab.vue:45 '.tab--line { border-bottom: 1px solid var(--color-grey-10); }' vs TabItem.vue:64 'border-bottom-color: var(--line-light)'",
        "figmaEvidence": "tab_item__4265_16082.json variant 'Property 1=Active, Property 2=White, Type=Line' strokes[0].token.cssVar = '--line-light' (#434343); no container-stroke data in this item-level file"
      }
    ],
    "verified": [],
    "notes": "Tab.vue (canonical) is a thin Figma-aligned wrapper over src/components/Tab/Tab.vue (BaseTab), registered as a healthy wrapper layer in divergences.md:163 (Tab listed) — not drift. The supplied Figma file tab_item__4265_16082.json describes the TabItem visual unit (per-state text/stroke/fill colors), implemented in src/components/Tab/TabItem.vue, not the container Tab.vue. Audited TabItem against all 6 variants.\\n\\nColor tokens — all 1:1 and theme-aware, no hardcoded hex:\\n- Line White Active: stroke --line-light, text --text-body (#f8f8f8) -> TabItem.vue:64 matches.\\n- Line White Normal: text --text-tips (#9e9e9e) -> base .tab-item color matches.\\n- Line/Filled Green Active: --brand (#2fb54e) -> :65/:74 matches.\\n- Text White Active: --text-body -> :68 matches.\\n- Filled White Normal: bg --bg-layer4 (#353535), text --text-2 (#cccccc) -> :72 matches.\\n- Filled Green Active: bg --brand, text --text-primary-btn (#ffffff) -> :74 matches.\\n\\nGeometry — all match: Figma h=32 -> height:32px (:48); pH=16 -> padding:0 var(--sp-m), --sp-m=16px; Filled r=4 -> --r-s=4px (:71, variables.css:107).\\n\\nComposite-layer — every fills/strokes/text.fills array in all 6 variants has length 1; no multi-layer stack, no composite drift (EXTRACT-008 class N/A).\\n\\nComposition-reuse — Tab items are plain text labels via <slot/>; no checkbox/radio/button affordance expected, so no hand-rolled-child violation.\\n\\nState matrix — normal/active x white/green x line/text/filled all present and correct (:62-74). Disabled handled (:57-60, --text-disabled) though no disabled variant exists in this Figma file.\\n\\na11y — minor: TabItem uses <div @click> with no role=tab/tabindex/keyboard handler. Not flagged as a top finding because the provided Figma source carries no role/interaction spec and this is the container audit; worth a separate a11y pass on TabItem. Overall fidelity high — no real color/geometry/composite drift in the audited surface."
  },
  {
    "component": "TabItem (src/canonical/TabItem.vue → src/components/Tab/TabItem.vue)",
    "verifierCovered": true,
    "overallFidelity": "medium",
    "findings": [
      {
        "dimension": "geometry",
        "severity": "high",
        "summary": "Code bolds active tabs (font-weight:700) on every active state, but ALL 6 Figma variants — including Active ones — are fontWeight:400. Figma distinguishes active purely by color (and a bottom border for Line). The 700 weight is unbacked typography drift.",
        "existingBacklogId": null,
        "suggestedFix": "Remove `font-weight: 700` from the four active-state rules; keep active differentiation by color/border only, matching Figma. If a bold-active look is a deliberate product decision, register it in divergences.md.",
        "codeEvidence": "src/components/Tab/TabItem.vue:64-74 — `.tab-item--line.tab-item--active-white {... font-weight: 700; }`, `.tab-item--line.tab-item--active-green {... font-weight: 700; }`, `.tab-item--text.tab-item--active { color: var(--text-body); font-weight: 700; }`, `.tab-item--filled.tab-item--active-white {... font-weight: 700; }`",
        "figmaEvidence": "All variants fontWeight=400. e.g. id 4605:7204 (Active,White,Text) text.fontWeight=400; id 4265:16087 (Active,White,Line) fontWeight=400; id 4452:7116 (Active,Green,Filled) fontWeight=400. Base text-style-body token = 400 14px/21px."
      },
      {
        "dimension": "geometry",
        "severity": "medium",
        "summary": "Figma sets itemSpacing gap=8 on the HORIZONTAL auto-layout of every variant (icon↔label spacing), but the code's inline-flex container has no `gap`. Tabs with an icon + text slot will render with 0px spacing instead of 8px.",
        "existingBacklogId": null,
        "suggestedFix": "Add `gap: var(--sp-s)` (8px) to `.tab-item` so multi-child (icon + label) slots match Figma's 8px item spacing.",
        "codeEvidence": "src/components/Tab/TabItem.vue:45-49 — `.tab-item { display: inline-flex; align-items: center; height: 32px; padding: 0 var(--sp-m); ... }` (no gap declared)",
        "figmaEvidence": "Every variant gap=8, layoutMode=HORIZONTAL, counterAxisAlignItems=CENTER (e.g. id 4265:16083, 4452:7118)."
      },
      {
        "dimension": "a11y",
        "severity": "medium",
        "summary": "The tab is a clickable <div @click> with no role=\"tab\", tabindex, or keyboard (Enter/Space/arrow) handling. Interactive element is not keyboard-operable — same a11y drift class as CANONICAL-013/016.",
        "existingBacklogId": "CANONICAL-016",
        "suggestedFix": "Add role=\"tab\", aria-selected, tabindex, and keydown (Enter/Space + arrow nav) — ideally coordinated at the TabList level for roving tabindex.",
        "codeEvidence": "src/components/Tab/TabItem.vue:30-39 — `<div class=\"tab-item\" :class=\"[...]\" @click=\"onClick\">` with cursor:pointer; no role/tabindex/keydown.",
        "figmaEvidence": "Component is an interactive Tab/Item (componentSetId 4265:16082) with Active/Normal selection states implying a tab control; design intent is a selectable tab."
      },
      {
        "dimension": "state-matrix",
        "severity": "low",
        "summary": "Code defines a `.tab-item--filled.tab-item--active-white` state (bg-layer4 + text-body) that has NO corresponding Figma variant. The Figma Filled axis only ships Normal-White and Active-Green; an active-white Filled tab is invented by code.",
        "existingBacklogId": null,
        "suggestedFix": "Confirm whether active-white Filled is a real product state; if not in Figma, either remove it or register it as an intentional extension in divergences.md.",
        "codeEvidence": "src/components/Tab/TabItem.vue:73 — `.tab-item--filled.tab-item--active-white { background: var(--bg-layer4); color: var(--text-body); font-weight: 700; }`",
        "figmaEvidence": "Filled variants present: only 4452:7118 (Normal,White) and 4452:7116 (Active,Green). No Active+White+Filled variant exists in set 4265:16082."
      }
    ],
    "verified": [
      {
        "summary": "Code bolds active tabs (font-weight:700) on every active state, but ALL 6 Figma variants — including Active ones — are fontWeight:400. Figma distinguishes active purely by color (and a bottom border for Line). The 700 weight is unbacked typography drift.",
        "real": false,
        "correctedSeverity": "not-a-drift",
        "reason": "The cited code lines are accurate: src/components/Tab/TabItem.vue (the legacy impl wrapped by src/canonical/TabItem.vue) carries font-weight:700 on exactly 4 active-state rules — line 64 (.line.active-white), 65 (.line.active-green), 68 (.text.active), 73 (.filled.active-white). Filled/active-green (line 74) has no bold, matching Figma. So the geometry/typography claim is faithfully described AGAINST the tokenized JSON.\n\nBUT the drift is NOT real — it is an extraction-gap false positive. Two Figma sources disagree:\n1. figma-data/normalized/components-tokenized/tab_item__4265_16082.json reports fontWeight:400 on all 6 variants' text nodes (this is what the auditor cited).\n2. The authoritative live Figma MCP render cache, figma-data/normalized/figma-mcp-cache/tabitem.tsx:16, explicitly applies font-[\"Roboto:Bold\"] font-bold to: Active/Green/Line, Active/White/Text, and Active/White/Line — while keeping Roboto:Regular/font-normal on Active/Green/Filled and all Normal variants.\n\nThe MCP cache (real rendered design context, with node ids 4265:16088/4265:16086/4605:7205) is the source the implementation was deliberately built from. This is documented in docs/internal/_prompts/x4-2-batch/tabitem-fix.md §c (typography) and blocker #2: \"figma Roboto:Bold weight 700 has no matching canonical Text Style token... keep partial-override font-weight:700 on active items.\" It is also re-affirmed in docs/internal/retrospection/2026-05-08-phase-x4-2-and-badge-rename.md:30 noting the Filled/Active-Green case correctly does NOT get 700 (\"spec-correct\"). \n\nThe mapping of bold-to-variants in code matches the MCP cache 1:1 (bold on the three White-Line/Text/Green-Line active states, no bold on Filled/Green-active). The tokenized JSON's flat fontWeight:400 is the base text-style-body metadata; the tokenizer dropped the per-variant Roboto:Bold font-family override that the MCP cache preserves. So Figma DOES distinguish active by weight, not \"purely by color.\" The 700 is Figma-backed and was a documented, deliberate Phase X.4.2 decision — not unbacked drift. Suggested fix (remove the 700s) would introduce a real regression against the rendered Figma design."
      }
    ],
    "notes": "Color fidelity is 1:1: every variant's fills/strokes/text.fills resolve to a single SOLID layer (no multi-layer composite stacks present — composite-layer dimension N/A), and each maps to the correct CSS var verified in src/tokens/variables.css (text-tips #9e9e9e, text-2 #cccccc, bg-layer4 #353535, brand #2fb54e, text-body #f8f8f8, line-light #434343, text-primary-btn #ffffff). Geometry h=32→height:32px, pH=16→--sp-m(16px), r=4(Filled)→--r-s(4px), strokeWeight=1→border 1px all verified correct. Coverage: TabItem IS in COMPONENT_TARGETS (CANONICAL-017 Batch 4, manifest line ~490-497) and present in render-verification.report.json — so CANONICAL-017 does NOT apply. The canonical→Base wrapper layer is an explicitly registered healthy divergence (divergences.md line 163, Tab listed). Strongest finding is the unbacked font-weight:700 on active states (4 rules) — all 6 Figma variants are weight 400."
  },
  {
    "component": "TabList (src/canonical/TabList.vue → src/components/Tab/TabList.vue)",
    "verifierCovered": true,
    "overallFidelity": "high",
    "findings": [
      {
        "dimension": "geometry",
        "severity": "medium",
        "summary": "Line-type container bottom divider is 2px in code but Figma strokeWeight is 1. The base BaseTabList.vue renders 'border-bottom: 2px solid var(--line-deep)', double the Figma spec. This is unregistered drift: there is no divergences.md entry and the manifest mapWarnings only excuses the per-SIDE placement of the border (verifier resolution limitation), not the WIDTH discrepancy.",
        "existingBacklogId": null,
        "suggestedFix": "Change the Line container divider to 1px to match Figma strokeWeight=1, OR register the intentional 2px (with the -1px TabItem margin overlap rationale) in src/design-system/translation/divergences.md so it is a sanctioned mapping rather than silent drift.",
        "codeEvidence": "src/components/Tab/TabList.vue:52 '.tab-list--line { border-bottom: 2px solid var(--line-deep); }' (canonical wrapper TabList.vue:3 delegates to this BaseTabList)",
        "figmaEvidence": "tab_list__4452_7148.json variant id=4605:7196 Type=Line: strokeWeight=1, strokes[0].token.cssVar=--line-deep (#353535)"
      },
      {
        "dimension": "geometry",
        "severity": "low",
        "summary": "Active-tab indicator overlap geometry is internally inconsistent with the 2px base track. TabItem Line uses 'border-bottom: 1px ... margin-bottom: -1px' intended to sit flush over the container divider, but the container divider is 2px (see finding above). A 1px active indicator pulled up by -1px cannot fully mask a 2px base divider, leaving a residual base-color sliver under the active tab vs Figma's clean active indicator. Resolving the 2px→1px width above also fixes this.",
        "existingBacklogId": null,
        "suggestedFix": "Unify divider/indicator weight at 1px so the active TabItem border fully replaces the base track (the standard underline-tab pattern).",
        "codeEvidence": "src/components/Tab/TabItem.vue:63 '.tab-item--line { border-bottom: 1px solid transparent; margin-bottom: -1px; }' vs container 2px at TabList.vue:52",
        "figmaEvidence": "tab_list__4452_7148.json id=4605:7196 Type=Line strokeWeight=1 (single 1px track shared by base + active indicator)"
      }
    ],
    "verified": [],
    "notes": "Audited canonical wrapper TabList.vue (thin pass-through, no own markup/style — delegates type/items/modelValue to src/components/Tab/TabList.vue), so all geometry/color/composition lives in the BaseTabList + TabItem children which were inspected fully.\n\nVerified CORRECT (no drift):\n- Coverage: TabList IS in COMPONENT_TARGETS (manifest line 245-265, CANONICAL-017 Batch 1, doubleTheme) and present in render-verification.report.json — NOT audit-invisible, so no coverage finding.\n- Color tokens: all paints use CSS vars, zero hardcoded hex. Line/Text text=--text-body (#f8f8f8 ✓), Filled bg=--bg-layer2 (#1f1f1f ✓), Filled stroke=--line-deep, Line stroke=--line-deep — all match Figma token cssVars 1:1.\n- Composite layers: every fills/strokes/text.fills array is length<=1 (single SOLID layer) across all 3 variants — no multi-layer stack, so no EXTRACT-008/CANONICAL-018-class composite drift.\n- Geometry gap: Figma gap=24 (Line/Text) == code --sp-l:24px ✓; Filled gap=null == code gap:0 ✓.\n- Geometry radius: Figma Filled r=4 == code --r-s:4px ✓; Filled border strokeWeight=1 == code 'border: 1px solid var(--line-deep)' ✓.\n- Composition-reuse / a11y: tab items are delegated to canonical TabItem.vue child (proper reuse, not hand-rolled) — no CANONICAL-007/012/013-class drift here; a11y/keyboard would belong to a TabItem audit, not this container.\n\nOnly real divergence is the Line container 2px vs Figma 1px strokeWeight, unregistered. Severity medium because it is a genuine 2x geometry deviation but visually subtle (single divider line). overallFidelity=high overall."
  },
  {
    "component": "src/canonical/Table.vue (delegates to src/components/Table/Table.vue)",
    "verifierCovered": true,
    "overallFidelity": "medium",
    "findings": [
      {
        "dimension": "geometry",
        "severity": "high",
        "summary": "Cell horizontal padding is 16px (--sp-m) but Figma cell padding is 8px on all sides (pR=8, pV=8, pB=8). Vertical 8px matches; horizontal doubles the Figma value, contributing to the rendered cell/column width overshoot (Figma w=120 vs code 141.95). This is the padding+width drift CANONICAL-019 already tracks.",
        "existingBacklogId": "CANONICAL-019",
        "suggestedFix": "Change cell horizontal padding from var(--sp-m) (16px) to var(--sp-xs) (8px) to match Figma 8px symmetric padding; re-check rendered column width against Figma w=120.",
        "codeEvidence": "src/components/Table/Table.vue:70 & :91 — .tbl-head .tbl-cell and .tbl-body .tbl-cell both `padding: var(--sp-xs) var(--sp-m);` (= 8px 16px); --sp-m=16px per tokens/variables.css:97",
        "figmaEvidence": "table__4265_16131 all 6 variants: pV=8 pR=8 pB=8 pH=null, w=120 (e.g. id 4265:16132 Type=Header,Align=Left)"
      },
      {
        "dimension": "geometry",
        "severity": "medium",
        "summary": "Cell content inline gap (between text and left/right icons) is 8px but Figma itemSpacing is 4px. A correct 4px token (--sp-xxs) exists and is unused here, so this is a straightforward 2x gap drift not covered by CANONICAL-019.",
        "existingBacklogId": null,
        "suggestedFix": "Change .tbl-cell__content gap from var(--sp-xs) (8px) to var(--sp-xxs) (4px) to match Figma itemSpacing=4.",
        "codeEvidence": "src/components/Table/Table.vue:103 — .tbl-cell__content `gap: var(--sp-xs);` (=8px). 4px token --sp-xxs exists at tokens/variables.css:94 but is not used.",
        "figmaEvidence": "table__4265_16131 all variants gap=4 (layoutMode=HORIZONTAL)"
      },
      {
        "dimension": "composite-layer",
        "severity": "low",
        "summary": "No composite-layer risk: all text.fills are single-layer SOLID paints (length 1) and fills/strokes arrays are empty on every variant, so the EXTRACT-008/CANONICAL-018 multi-layer-stack drift class does not apply to Table. Reported for completeness/coverage confidence.",
        "existingBacklogId": null,
        "suggestedFix": "No change needed; color tokens map 1:1 to Figma single-layer paints.",
        "codeEvidence": "src/components/Table/Table.vue:73 header color: var(--text-tips); :94 body color: var(--text-body) — single token each, no layering",
        "figmaEvidence": "Header text.fills=[#9e9e9e/--text-tips] len1; Tbody text.fills=[#f8f8f8/--text-body] len1; variant fills=[] strokes=[] on all 6"
      },
      {
        "dimension": "color-token",
        "severity": "low",
        "summary": "Row/header separator borders (border-bottom 1px --line-deep / --line-light) have no supporting stroke in the Figma variant data (strokes=[] on every variant, strokeWeight=1 but no paint). The separators likely belong to a parent table frame not captured in this component-set extract, so this is unverifiable rather than confirmed drift — but the code asserts a border color with no extracted Figma source to validate against.",
        "existingBacklogId": null,
        "suggestedFix": "Confirm separator stroke source from the parent Table frame (not in this cell-level component set); if absent in Figma, treat as legacy addition and document, otherwise align color/weight to the real stroke node.",
        "codeEvidence": "src/components/Table/Table.vue:75 border-bottom: 1px solid var(--line-deep); :80 border-bottom: 1px solid var(--line-light)",
        "figmaEvidence": "table__4265_16131 every variant strokes=[] (e.g. Header,Left id 4265:16132)"
      }
    ],
    "verified": [],
    "notes": "Canonical Table.vue is a thin Figma-aligned wrapper that delegates to legacy BaseTable (src/components/Table/Table.vue) — registered healthy wrapper pattern in divergences.md:163, so no composition-reuse flag. Composition is clean: icons use the Icon canonical (no hand-rolled SVG), no native buttons, no hardcoded hex (all colors via CSS var tokens). Render-verification coverage EXISTS (generate-render-verification-manifest.mjs:509-515, CANONICAL-017 Batch 4) so this is NOT audit-invisible. State-matrix: Figma only varies Type (Header/Tbody) x Align (L/C/R); code handles type via striped+font-weight and align via justify-content correctly; code adds :hover (bg-layer3) and striped zebra which Figma variants do not specify (additive product behavior, not drift). Main real drifts are geometric: horizontal cell padding 16px vs Figma 8px (CANONICAL-019, also drives the w=120 vs 141.95 width overshoot) and content gap 8px vs Figma 4px (NEW, not in CANONICAL-019). The CANONICAL-019 backlog note about \"rootPadding 8/8/8/8 vs code 0/0/0/0\" is a verifier-selector artifact (it reads the bare <table> element which has UA zero padding; the 8px actually lives in cells) — the genuine padding issue is the horizontal 16px vs 8px mismatch documented above."
  },
  {
    "component": "Tooltip (src/canonical/Tooltip.vue → src/components/Tooltip/Tooltip.vue)",
    "verifierCovered": true,
    "overallFidelity": "high",
    "findings": [
      {
        "dimension": "composite-layer",
        "severity": "low",
        "summary": "Figma drop-shadow is a 3-layer effect stack; code maps it to --shadow-l3. I verified all 3 layers composite 1:1 (radius/spread/offset/alpha all match), so this is NOT a drift — recorded only as positive evidence that the composite is correctly reproduced rather than collapsed to one layer.",
        "existingBacklogId": null,
        "suggestedFix": "No change. Composite is faithful. Listed for transparency.",
        "codeEvidence": "src/tokens/variables.css:218-221 --shadow-l3: 0 12px 48px 16px #00000008, 0 9px 28px 0 #0000000d, 0 6px 16px -8px #00000014; consumed at Tooltip.vue:84 box-shadow: var(--shadow-l3)",
        "figmaEvidence": "tooltips__1408_17152 variant 2514:63798 effects[]: DROP_SHADOW r48/spread16/off(0,12)/#000@0.03, r28/spread0/off(0,9)/#000@0.05, r16/spread-8/off(0,6)/#000@0.08 — matches 0x08/0x0d/0x14 alphas"
      },
      {
        "dimension": "color-token",
        "severity": "low",
        "summary": "Text color is the only root-level color Figma actually exports for this component, and it matches per-theme: light=#141414 (--color-grey-13 / --tooltip-text-light), dark=#f8f8f8 (--color-grey-2 / --tooltip-text-dark). No hardcoded hex anywhere; all values are tokens. No drift.",
        "existingBacklogId": null,
        "suggestedFix": "No change.",
        "codeEvidence": "src/components/Tooltip/Tooltip.vue:91-101 .tooltip-box--light{--tooltip-text:var(--tooltip-text-light)} / --dark{--tooltip-text:var(--tooltip-text-dark)}; variables.css:139-140 --tooltip-text-dark:var(--color-grey-2); --tooltip-text-light:var(--color-grey-13)",
        "figmaEvidence": "tooltips__1408_17152 all 12 variants text.fills[0]: dark theme=off → #141414 (--color-grey-13), dark theme=on → #f8f8f8 (--color-grey-2)"
      },
      {
        "dimension": "geometry",
        "severity": "low",
        "summary": "Root fills/strokes/padding/size/radius are all null in the Figma extract for every Tooltip variant (extract pipeline drops root autolayout + bg/border, same class as PopupBox). Code's bg #353535-dark / #fff-light, border, padding 4/8, radius --r-s(4px) therefore cannot be confirmed against Figma and rely on the manifest's documented 'real visual matches Figma rendering' note. This is an extract-data gap, not verifiable code drift.",
        "existingBacklogId": "EXTRACT-007",
        "suggestedFix": "Track under existing EXTRACT pipeline gap; do not invent a value-drift finding without Figma root geometry. Consider EXTRACT-007/008-class follow-up to recover root autolayout padding/fill so Tooltip bg/border/padding become verifiable.",
        "codeEvidence": "Tooltip.vue:77-80 padding: var(--sp-xxs) var(--sp-xs); border-radius: var(--r-s); background: var(--tooltip-bg); border: 1px solid var(--tooltip-border)",
        "figmaEvidence": "tooltips__1408_17152 variant 2514:63798 {fills:[],strokes:[],padding:null,size:null,radius:null}; manifest scripts/generate-render-verification-manifest.mjs:412 documents the extract gap"
      }
    ],
    "verified": [],
    "notes": "Tooltip canonical is a thin Figma-aligned wrapper (registered healthy pattern, divergences.md:163) delegating to legacy BaseTooltip. Verifier coverage: PRESENT (CANONICAL-017 Batch 3, manifest line 396-412), so no coverage finding. Both axes are registered accepted divergences: `dark theme` design-state (divergences.md:175, mapped to theme prop) and `content` dual-form prop/slot (divergences.md:253). No composition-reuse issue — Tooltip renders text + arrow, no canonical child (CheckBox/Button/Icon) is applicable. a11y is reasonable (role=\"tooltip\" on box). state-matrix: Figma only varies dark-theme × pointing (12 variants, all covered by theme + placement map); no hover/focus/disabled variants exist in Figma to mismatch. The ONLY substantive limitation is the EXTRACT pipeline dropping root fills/strokes/padding/radius (null across all 12 variants), which prevents verifying bg/border/padding/radius against Figma — already acknowledged in the manifest and EXTRACT-class backlog. Everything verifiable (text color per theme, 3-layer shadow composite, all tokenized — zero hardcoded hex) matches 1:1. Overall fidelity HIGH; no NEW backlog entry warranted."
  },
  {
    "component": "TopBar (src/canonical/TopBar.vue → src/components/TopBar/TopBar.vue)",
    "verifierCovered": true,
    "overallFidelity": "high",
    "findings": [
      {
        "dimension": "geometry",
        "severity": "medium",
        "summary": "Inner section gaps and child geometry are not verifiable against Figma: the tokenized extract has layout/padding/size=null at the tokenized level and provides only root-level h/gap/pH/pV; the variant declares subnodeCount:3 with 38 vectorNodeIds (logo, search box, menu items, right avatars/icons) but no child gap/padding was extracted. Code hand-sets inner gaps (search/menu gap var(--sp-xxl)=40px; right gap var(--sp-xs)=8px, before-login right var(--sp-l)=24px) that cannot be confirmed against any Figma value. Same variant-child geometry extract gap class as EXTRACT-007.",
        "existingBacklogId": "EXTRACT-007",
        "suggestedFix": "Track under EXTRACT-007 (variant-child geometry schema gap). Once child geometry is extractable, verify search/menu inner gap (40px) and right-content gaps (8px/24px) against the Figma frame children rather than asserting them blind.",
        "codeEvidence": "src/components/TopBar/TopBar.vue:62-77 — .topbar-search,.topbar-menu { gap: var(--sp-xxl); flex:1 } and .topbar-right { gap: var(--sp-xs) } / .topbar--before-login .topbar-right { gap: var(--sp-l) }",
        "figmaEvidence": "variant 4771:7174 (Tag=After Login) subnodeCount=3, vectorNodeIds length 38; root gap=80 only; per-child gap not present in tokenized data; layout/padding/size keys null"
      },
      {
        "dimension": "state-matrix",
        "severity": "low",
        "summary": "Figma only exposes a single Tag axis (After Login / Before Login) with no hover/focus/active/disabled/checked states — the TopBar root is a container, not an interactive control. Code mirrors exactly: tagClass maps the two tag values to height-only differences (56px vs 64px) plus a before-login right-gap bump. No missing state variant; noted only to confirm the state matrix is complete.",
        "existingBacklogId": null,
        "suggestedFix": "No action; state matrix matches Figma. Confirms height-per-tag and root gap (80px) are 1:1.",
        "codeEvidence": "src/components/TopBar/TopBar.vue:34 tagClass computed; :49-50 .topbar--after-login height var(--sp-xxxl)=56px / .topbar--before-login height var(--topbar-height-before-login)=64px",
        "figmaEvidence": "components-tokenized top_bar__4771_7173.json variants: only Tag=After Login (4771:7174, h=56) and Tag=Before Login (4771:7226, h=64); no state axis"
      }
    ],
    "verified": [],
    "notes": "Root-level fidelity is HIGH and fully token-clean. All root paints are single-layer (no composite-layer drift): fills hex #000000 → token --bg-topbar; strokes #353535 → --line-deep; title text #ffffff → --text-heading with size 16/weight 600/lineHeight 24 → --text-style-pop-title (600 16px/24px). No hardcoded hex anywhere in the SFC. Geometry confirmed 1:1: gap=80 → --topbar-section-gap:80px; pH=16/pV=8 → padding var(--sp-xs) var(--sp-m) (8px 16px); strokeWeight=1 → border 1px; h 56/64 → --sp-xxxl / --topbar-height-before-login; counterAxisAlignItems=CENTER → align-items:center. Coverage: TopBar IS in COMPONENT_TARGETS (generate-render-verification-manifest.mjs:211-215, CANONICAL-017 Batch 1) with 4 manifest entries in render-verification.report.json (after/before-login x dark/light) — so CANONICAL-017 coverage finding is RESOLVED for this component, not open. The canonical→Base wrapper layering is a registered divergence (src/design-system/translation/divergences.md:163), so it is NOT flagged as drift. Composition-reuse is not auditable here because all inner content (logo/search/menu/right) is consumer-supplied via slots — TopBar itself hand-rolls no canonical child markup. No color-token, composite-layer, or a11y drift found at the layer this data exposes. The only real residual risk is the un-extracted child geometry (folded into EXTRACT-007)."
  }
]
