Buckets:
| <!-- Copyright 2026 Anthropic PBC · SPDX-License-Identifier: Apache-2.0 --> | |
| <html lang="en"> | |
| <head> | |
| <meta charset="utf-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1"> | |
| <title>Rendering checker pipeline — module explainer</title> | |
| <style data-birch-system> | |
| /* | |
| Birch HTML Design System | |
| Opinionated single-option stylesheet for reliable LLM-generated artifacts. | |
| Model: | |
| 1. Design tokens as CSS variables. | |
| 2. Layout primitives as classes. | |
| 3. Semantic components as classes with data-* variants. | |
| */ | |
| /* ==================== 1. TOKENS ==================== */ | |
| :root { | |
| color-scheme: light; | |
| /* Palette */ | |
| --color-ivory: #FAF9F5; | |
| --color-slate: #141413; | |
| --color-clay: #D97757; | |
| --color-clay-dark: #B85C3E; | |
| --color-oat: #E3DACC; | |
| --color-olive: #788C5D; | |
| --color-rust: #B04A3F; | |
| --color-sky: #6A8CAF; | |
| --color-white: #FFFFFF; | |
| --color-gray-50: #F7F5EE; | |
| --color-gray-100: #F0EEE6; | |
| --color-gray-150: #E8E4DA; | |
| --color-gray-200: #DED9CD; | |
| --color-gray-300: #D1CFC5; | |
| --color-gray-500: #87867F; | |
| --color-gray-700: #3D3D3A; | |
| --color-gray-800: #242421; | |
| /* Semantic colors */ | |
| --bg: var(--color-ivory); | |
| --surface: var(--color-white); | |
| --surface-tint: var(--color-gray-100); | |
| --surface-warm: var(--color-oat); | |
| --text: var(--color-slate); | |
| --text-muted: var(--color-gray-500); | |
| --text-soft: var(--color-gray-700); | |
| --muted: var(--text-muted); | |
| --border-color: var(--color-gray-300); | |
| --accent: var(--color-clay); | |
| --accent-strong: var(--color-clay-dark); | |
| --success: var(--color-olive); | |
| --warning: #C78E3F; | |
| --danger: var(--color-rust); | |
| --info: var(--color-sky); | |
| /* Typography */ | |
| --font-serif: ui-serif, Georgia, "Times New Roman", serif; | |
| --font-sans: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif; | |
| --font-mono: ui-monospace, "SF Mono", Menlo, Consolas, monospace; | |
| --text-xs: 11px; | |
| --text-sm: 12px; | |
| --text-md: 14px; | |
| --text-base: 15px; | |
| --text-lg: 17px; | |
| --text-xl: 21px; | |
| --text-2xl: 26px; | |
| --text-3xl: 36px; | |
| --text-4xl: 44px; | |
| --leading-tight: 1.15; | |
| --leading-title: 1.25; | |
| --leading-body: 1.55; | |
| --leading-loose: 1.7; | |
| /* Spacing */ | |
| --space-1: 4px; | |
| --space-2: 8px; | |
| --space-3: 12px; | |
| --space-4: 16px; | |
| --space-5: 24px; | |
| --space-6: 32px; | |
| --space-7: 48px; | |
| --space-8: 64px; | |
| --space-9: 96px; | |
| /* Shape */ | |
| --radius-xs: 4px; | |
| --radius-sm: 8px; | |
| --radius-md: 12px; | |
| --radius-lg: 16px; | |
| --radius-xl: 20px; | |
| --radius-pill: 999px; | |
| --border: 1.5px solid var(--border-color); | |
| --border-thin: 1px solid var(--border-color); | |
| --shadow-sm: 0 1px 2px rgba(20, 20, 19, 0.06); | |
| --shadow-md: 0 4px 14px rgba(20, 20, 19, 0.08); | |
| --shadow-lg: 0 12px 28px rgba(20, 20, 19, 0.12); | |
| /* Motion */ | |
| --ease: cubic-bezier(0.2, 0, 0, 1); | |
| --ease-spring: cubic-bezier(0.34, 1.56, 0.64, 1); | |
| --dur-fast: 120ms; | |
| --dur: 180ms; | |
| --hover-y: -2px; | |
| /* Page sizing */ | |
| --page-max: 1100px; | |
| --page-pad: 28px; | |
| --page-pad-block: 48px; | |
| /* Legacy aliases used by source examples */ | |
| --ivory: var(--color-ivory); | |
| --slate: var(--color-slate); | |
| --clay: var(--color-clay); | |
| --clay-d: var(--color-clay-dark); | |
| --oat: var(--color-oat); | |
| --olive: var(--color-olive); | |
| --rust: var(--color-rust); | |
| --sky: var(--color-sky); | |
| --white: var(--color-white); | |
| --gray-50: var(--color-gray-50); | |
| --gray-100: var(--color-gray-100); | |
| --gray-150: var(--color-gray-150); | |
| --gray-200: var(--color-gray-200); | |
| --gray-300: var(--color-gray-300); | |
| --gray-500: var(--color-gray-500); | |
| --gray-700: var(--color-gray-700); | |
| --gray-800: var(--color-gray-800); | |
| --serif: var(--font-serif); | |
| --sans: var(--font-sans); | |
| --mono: var(--font-mono); | |
| } | |
| /* ==================== BASE ==================== */ | |
| *, | |
| *::before, | |
| *::after { | |
| box-sizing: border-box; | |
| } | |
| html { | |
| background: var(--bg); | |
| color: var(--text); | |
| font-family: var(--font-sans); | |
| -webkit-text-size-adjust: 100%; | |
| } | |
| body { | |
| margin: 0; | |
| background: var(--bg); | |
| color: var(--text); | |
| font-family: var(--font-sans); | |
| font-size: var(--text-base); | |
| line-height: var(--leading-body); | |
| -webkit-font-smoothing: antialiased; | |
| text-rendering: optimizeLegibility; | |
| } | |
| img, | |
| svg { | |
| max-width: 100%; | |
| } | |
| a { | |
| color: inherit; | |
| text-decoration-color: rgba(217, 119, 87, 0.45); | |
| text-underline-offset: 3px; | |
| } | |
| a:hover { | |
| color: var(--accent); | |
| } | |
| h1, | |
| h2, | |
| h3, | |
| p { | |
| margin-block: 0; | |
| } | |
| h1, | |
| h2, | |
| h3 { | |
| font-family: var(--font-serif); | |
| font-weight: 500; | |
| letter-spacing: -0.01em; | |
| line-height: var(--leading-title); | |
| } | |
| h1 { | |
| font-size: clamp(32px, 5vw, var(--text-4xl)); | |
| } | |
| h2 { | |
| font-size: var(--text-2xl); | |
| } | |
| h3 { | |
| font-size: var(--text-xl); | |
| } | |
| code, | |
| kbd, | |
| pre { | |
| font-family: var(--font-mono); | |
| } | |
| code { | |
| font-size: 0.92em; | |
| white-space: normal; | |
| word-break: normal; | |
| } | |
| h1 code, | |
| h2 code, | |
| h3 code { | |
| overflow-wrap: anywhere; | |
| word-break: break-word; | |
| } | |
| button, | |
| input, | |
| textarea, | |
| select { | |
| font: inherit; | |
| } | |
| button { | |
| cursor: pointer; | |
| } | |
| ::selection { | |
| background: rgba(217, 119, 87, 0.24); | |
| } | |
| /* ==================== 2. LAYOUT PRIMITIVES ==================== */ | |
| .page { | |
| width: min(100% - (var(--page-pad) * 2), var(--page-max)); | |
| margin-inline: auto; | |
| padding-block: var(--page-pad-block) var(--space-9); | |
| } | |
| .page[data-size="narrow"] { | |
| --page-max: 820px; | |
| } | |
| .page[data-size="wide"] { | |
| --page-max: 1280px; | |
| } | |
| .page[data-size="full"] { | |
| --page-max: 1440px; | |
| } | |
| .section { | |
| margin-block: var(--section-gap, var(--space-5)); | |
| } | |
| .section[data-gap="lg"] { | |
| --section-gap: var(--space-6); | |
| } | |
| .section[data-gap="xl"] { | |
| --section-gap: var(--space-7); | |
| } | |
| .section:first-child { | |
| margin-block-start: 0; | |
| } | |
| .stack > .section { | |
| margin-block: 0; | |
| } | |
| .rule { | |
| border: 0; | |
| border-top: var(--border-thin); | |
| margin: var(--space-3) 0 var(--space-5); | |
| } | |
| .stack { | |
| display: flex; | |
| flex-direction: column; | |
| gap: var(--stack-gap, var(--space-4)); | |
| } | |
| .stack[data-gap="xs"] { --stack-gap: var(--space-2); } | |
| .stack[data-gap="sm"] { --stack-gap: var(--space-3); } | |
| .stack[data-gap="md"] { --stack-gap: var(--space-4); } | |
| .stack[data-gap="lg"] { --stack-gap: var(--space-6); } | |
| .stack[data-gap="xl"] { --stack-gap: var(--space-8); } | |
| .stack > :is(.button, .btn, .chip, .badge) { | |
| align-self: flex-start; | |
| } | |
| .cluster { | |
| display: flex; | |
| flex-wrap: wrap; | |
| align-items: center; | |
| gap: var(--cluster-gap, var(--space-3)); | |
| } | |
| .cluster[data-align="start"] { align-items: flex-start; } | |
| .cluster[data-align="end"] { align-items: flex-end; } | |
| .cluster[data-justify="between"] { justify-content: space-between; } | |
| .cluster[data-justify="end"] { justify-content: flex-end; } | |
| .grid { | |
| display: grid; | |
| gap: var(--grid-gap, var(--space-5)); | |
| } | |
| .grid[data-cols="2"] { | |
| grid-template-columns: repeat(2, minmax(0, 1fr)); | |
| } | |
| .grid[data-cols="3"] { | |
| grid-template-columns: repeat(3, minmax(0, 1fr)); | |
| } | |
| .grid[data-cols="4"] { | |
| grid-template-columns: repeat(4, minmax(0, 1fr)); | |
| } | |
| .auto-grid { | |
| display: grid; | |
| grid-template-columns: repeat(auto-fit, minmax(min(100%, var(--grid-min, 240px)), 1fr)); | |
| gap: var(--grid-gap, var(--space-5)); | |
| } | |
| .auto-grid > * { | |
| min-width: 0; | |
| } | |
| .split { | |
| display: grid; | |
| grid-template-columns: minmax(0, 1fr) minmax(280px, var(--split-side, 360px)); | |
| gap: var(--split-gap, var(--space-6)); | |
| align-items: start; | |
| } | |
| .split > * { | |
| min-width: 0; | |
| } | |
| .section-head { | |
| min-width: 0; | |
| } | |
| .section-rail { | |
| display: grid; | |
| grid-template-columns: minmax(0, 1fr) minmax(280px, var(--rail-width, 360px)); | |
| column-gap: var(--rail-gap, var(--space-6)); | |
| row-gap: var(--space-5); | |
| align-items: start; | |
| } | |
| .section-rail > .section-head { | |
| grid-column: 1 / -1; | |
| } | |
| .section-rail > .reference-panel, | |
| .section-rail > aside { | |
| align-self: start; | |
| } | |
| .sidebar-layout { | |
| display: grid; | |
| grid-template-columns: var(--sidebar-width, 240px) minmax(0, 1fr); | |
| gap: var(--sidebar-gap, var(--space-7)); | |
| align-items: start; | |
| } | |
| .sidebar-layout > :first-child, | |
| .sticky { | |
| position: sticky; | |
| top: var(--sticky-top, var(--space-5)); | |
| } | |
| .bleed { | |
| margin-inline: calc(var(--page-pad) * -1); | |
| } | |
| .scroll-x { | |
| overflow-x: auto; | |
| overscroll-behavior-inline: contain; | |
| } | |
| .center { | |
| display: grid; | |
| place-items: center; | |
| } | |
| .spacer { | |
| flex: 1; | |
| } | |
| @media (max-width: 860px) { | |
| :root { | |
| --page-pad: 20px; | |
| --page-pad-block: 40px; | |
| } | |
| .grid[data-cols], | |
| .split, | |
| .section-rail, | |
| .sidebar-layout { | |
| grid-template-columns: 1fr; | |
| } | |
| .sidebar-layout > :first-child, | |
| .sticky { | |
| position: static; | |
| } | |
| } | |
| /* ==================== TYPOGRAPHY UTILITIES ==================== */ | |
| .eyebrow { | |
| display: inline-flex; | |
| align-items: center; | |
| gap: var(--space-2); | |
| color: var(--accent); | |
| font-family: var(--font-mono); | |
| font-size: var(--text-xs); | |
| font-weight: 700; | |
| letter-spacing: 0.08em; | |
| text-transform: uppercase; | |
| } | |
| .eyebrow::before { | |
| content: ""; | |
| width: 24px; | |
| height: 1.5px; | |
| background: currentColor; | |
| } | |
| .lede { | |
| max-width: 720px; | |
| color: var(--text-soft); | |
| font-size: var(--text-lg); | |
| line-height: 1.6; | |
| } | |
| .muted { | |
| color: var(--text-muted); | |
| } | |
| .caption { | |
| color: var(--text-muted); | |
| font-family: var(--font-mono); | |
| font-size: var(--text-sm); | |
| } | |
| .stat-value { | |
| display: block; | |
| color: var(--text); | |
| font-family: var(--font-serif); | |
| font-size: clamp(30px, 3.2vw, 42px); | |
| font-variant-numeric: tabular-nums; | |
| font-weight: 550; | |
| letter-spacing: -0.025em; | |
| line-height: 1; | |
| } | |
| .stat-card { | |
| gap: var(--space-2); | |
| } | |
| .stat-card .caption { | |
| letter-spacing: 0.08em; | |
| text-transform: uppercase; | |
| } | |
| .stat-card .muted { | |
| max-width: 34ch; | |
| font-size: var(--text-sm); | |
| } | |
| .mono { | |
| font-family: var(--font-mono); | |
| } | |
| /* ==================== 3. SEMANTIC COMPONENTS ==================== */ | |
| .panel, | |
| .card { | |
| background: var(--surface); | |
| border: var(--border); | |
| border-radius: var(--radius-md); | |
| } | |
| .panel { | |
| padding: var(--panel-pad, var(--space-5)); | |
| } | |
| .card { | |
| padding: var(--card-pad, var(--space-5)); | |
| transition: | |
| transform var(--dur-fast) var(--ease), | |
| border-color var(--dur-fast) var(--ease), | |
| box-shadow var(--dur-fast) var(--ease), | |
| background-color var(--dur-fast) var(--ease); | |
| } | |
| .card[data-hover="lift"]:hover, | |
| .card[data-clickable]:hover { | |
| transform: translateY(var(--hover-y)); | |
| border-color: rgba(217, 119, 87, 0.55); | |
| box-shadow: var(--shadow-md); | |
| } | |
| .card[data-clickable] { | |
| cursor: pointer; | |
| } | |
| .card[data-variant="flat"] { | |
| background: transparent; | |
| border-color: transparent; | |
| box-shadow: none; | |
| } | |
| .card[data-variant="outlined"] { | |
| background: var(--surface); | |
| border: var(--border); | |
| } | |
| .card[data-variant="elevated"] { | |
| border-color: transparent; | |
| box-shadow: var(--shadow-md); | |
| } | |
| .card[data-variant="filled"], | |
| .card[data-tone="oat"] { | |
| background: var(--surface-warm); | |
| } | |
| .card[data-tone], | |
| .panel[data-tone], | |
| .callout[data-tone] { | |
| background: var(--surface); | |
| } | |
| .card[data-tone="danger"], | |
| .panel[data-tone="danger"], | |
| .callout[data-tone="danger"] { | |
| border-color: rgba(176, 74, 63, 0.36); | |
| } | |
| .card[data-tone="warning"], | |
| .panel[data-tone="warning"], | |
| .callout[data-tone="warning"] { | |
| border-color: rgba(199, 142, 63, 0.38); | |
| } | |
| .card[data-tone="success"], | |
| .panel[data-tone="success"], | |
| .callout[data-tone="success"] { | |
| border-color: rgba(120, 140, 93, 0.38); | |
| } | |
| .card[data-tone="info"], | |
| .panel[data-tone="info"], | |
| .callout[data-tone="info"] { | |
| border-color: rgba(106, 140, 175, 0.36); | |
| } | |
| .card[data-accent] { | |
| position: relative; | |
| overflow: hidden; | |
| } | |
| .card[data-accent]::before { | |
| content: ""; | |
| position: absolute; | |
| inset: 0 auto 0 0; | |
| width: 5px; | |
| background: var(--accent); | |
| } | |
| .card-head { | |
| display: flex; | |
| align-items: center; | |
| gap: var(--space-3); | |
| min-width: 0; | |
| max-width: 100%; | |
| } | |
| .card-head > :first-child { | |
| flex: 0 0 auto; | |
| } | |
| .card-titles { | |
| flex: 1 1 0; | |
| min-width: 0; | |
| max-width: 100%; | |
| } | |
| .card-title { | |
| max-width: 100%; | |
| margin: 0; | |
| font-family: var(--font-serif); | |
| font-size: var(--text-xl); | |
| font-weight: 550; | |
| line-height: var(--leading-title); | |
| overflow-wrap: anywhere; | |
| } | |
| .card-sub { | |
| margin: 2px 0 0; | |
| color: var(--text-muted); | |
| font-size: var(--text-sm); | |
| overflow-wrap: anywhere; | |
| } | |
| .toolbar { | |
| display: flex; | |
| flex-wrap: wrap; | |
| align-items: center; | |
| gap: var(--space-4); | |
| padding: var(--space-4) var(--space-5); | |
| background: var(--surface); | |
| border: var(--border); | |
| border-radius: var(--radius-md); | |
| } | |
| .toolbar[data-sticky] { | |
| position: sticky; | |
| top: 0; | |
| z-index: 10; | |
| } | |
| .chip, | |
| .badge { | |
| display: inline-flex; | |
| align-items: center; | |
| justify-content: center; | |
| gap: 6px; | |
| border-radius: var(--radius-pill); | |
| white-space: nowrap; | |
| font-family: var(--font-mono); | |
| font-size: var(--text-xs); | |
| font-weight: 650; | |
| line-height: 1; | |
| } | |
| .chip { | |
| min-height: 24px; | |
| padding: 0 10px; | |
| color: var(--text-soft); | |
| background: var(--surface-tint); | |
| border: 1px solid transparent; | |
| } | |
| .badge { | |
| min-height: 22px; | |
| padding: 0 9px; | |
| color: var(--text-muted); | |
| background: var(--surface); | |
| border: var(--border-thin); | |
| text-transform: uppercase; | |
| letter-spacing: 0.06em; | |
| } | |
| .chip[data-tone="clay"], | |
| .badge[data-tone="clay"] { | |
| color: var(--accent); | |
| background: rgba(217, 119, 87, 0.14); | |
| } | |
| .chip[data-tone="olive"], | |
| .badge[data-tone="olive"], | |
| .chip[data-tone="success"], | |
| .badge[data-tone="success"] { | |
| color: var(--success); | |
| background: rgba(120, 140, 93, 0.15); | |
| } | |
| .chip[data-tone="warning"], | |
| .badge[data-tone="warning"] { | |
| color: var(--warning); | |
| background: rgba(199, 142, 63, 0.16); | |
| } | |
| .chip[data-tone="rust"], | |
| .badge[data-tone="rust"], | |
| .chip[data-tone="danger"], | |
| .badge[data-tone="danger"] { | |
| color: var(--danger); | |
| background: rgba(176, 74, 63, 0.13); | |
| } | |
| .chip[data-tone="sky"], | |
| .badge[data-tone="sky"], | |
| .chip[data-tone="info"], | |
| .badge[data-tone="info"] { | |
| color: var(--info); | |
| background: rgba(106, 140, 175, 0.14); | |
| } | |
| .finding { | |
| border-left: 6px solid var(--border-color); | |
| } | |
| .finding[data-severity="blocker"], | |
| .finding[data-severity="critical"], | |
| .finding[data-severity="danger"], | |
| .finding[data-tone="danger"] { | |
| border-left-color: var(--danger); | |
| } | |
| .finding[data-severity="high"], | |
| .finding[data-severity="warning"], | |
| .finding[data-tone="warning"] { | |
| border-left-color: var(--warning); | |
| } | |
| .finding[data-severity="medium"], | |
| .finding[data-severity="info"], | |
| .finding[data-tone="info"] { | |
| border-left-color: var(--info); | |
| } | |
| .finding[data-severity="low"], | |
| .finding[data-severity="success"], | |
| .finding[data-tone="success"] { | |
| border-left-color: var(--success); | |
| } | |
| .button, | |
| .btn { | |
| appearance: none; | |
| display: inline-flex; | |
| align-items: center; | |
| justify-content: center; | |
| min-height: 36px; | |
| padding: 0 14px; | |
| border: 1.5px solid transparent; | |
| border-radius: var(--radius-sm); | |
| font-family: var(--font-sans); | |
| font-size: var(--text-md); | |
| font-weight: 650; | |
| line-height: 1; | |
| text-decoration: none; | |
| transition: | |
| transform var(--dur-fast) var(--ease), | |
| background-color var(--dur-fast) var(--ease), | |
| border-color var(--dur-fast) var(--ease), | |
| box-shadow var(--dur-fast) var(--ease); | |
| } | |
| .button:hover, | |
| .btn:hover { | |
| transform: translateY(-1px); | |
| } | |
| .button[data-variant="primary"], | |
| .btn-primary { | |
| color: var(--color-white); | |
| background: var(--color-slate); | |
| } | |
| .button[data-variant="primary"]:hover, | |
| .btn-primary:hover { | |
| background: var(--color-gray-700); | |
| } | |
| .button[data-variant="secondary"], | |
| .btn-secondary { | |
| color: var(--text); | |
| background: var(--surface-tint); | |
| border-color: var(--border-color); | |
| } | |
| .button[data-variant="ghost"], | |
| .btn-ghost { | |
| color: var(--text-soft); | |
| background: transparent; | |
| } | |
| .button[data-variant="ghost"]:hover, | |
| .btn-ghost:hover { | |
| color: var(--text); | |
| background: var(--surface-tint); | |
| } | |
| .button[data-variant="danger"], | |
| .btn-danger { | |
| color: var(--color-white); | |
| background: var(--danger); | |
| } | |
| .input { | |
| width: 100%; | |
| min-height: 38px; | |
| padding: 0 12px; | |
| color: var(--text); | |
| background: var(--surface); | |
| border: var(--border); | |
| border-radius: var(--radius-sm); | |
| outline: none; | |
| } | |
| .input:focus { | |
| border-color: var(--accent); | |
| box-shadow: 0 0 0 3px rgba(217, 119, 87, 0.16); | |
| } | |
| .avatar { | |
| display: inline-flex; | |
| align-items: center; | |
| justify-content: center; | |
| width: var(--avatar-size, 38px); | |
| height: var(--avatar-size, 38px); | |
| border-radius: 50%; | |
| color: var(--text-soft); | |
| background: var(--surface-warm); | |
| font-family: var(--font-mono); | |
| font-size: var(--text-sm); | |
| font-weight: 700; | |
| letter-spacing: 0.02em; | |
| flex: 0 0 auto; | |
| } | |
| .code-block { | |
| margin: 0; | |
| padding: var(--space-4) var(--space-5); | |
| overflow-x: auto; | |
| color: #E8E6DC; | |
| background: var(--color-slate); | |
| border-radius: var(--radius-md); | |
| font-family: var(--font-mono); | |
| font-size: var(--text-sm); | |
| line-height: var(--leading-loose); | |
| } | |
| .code-block[data-kind="command"], | |
| .code-block[data-wrap="true"], | |
| .command-block { | |
| max-width: 100%; | |
| min-width: 0; | |
| box-sizing: border-box; | |
| white-space: pre-wrap; | |
| overflow-wrap: anywhere; | |
| word-break: break-word; | |
| overflow-x: hidden; | |
| } | |
| .code-block[data-wrap="true"] code, | |
| .code-block[data-kind="command"] code { | |
| display: block; | |
| max-width: 100%; | |
| white-space: pre-wrap; | |
| overflow-wrap: anywhere; | |
| word-break: break-word; | |
| } | |
| .copyable { | |
| position: relative; | |
| } | |
| .copyable > .code-block { | |
| padding-inline-end: 88px; | |
| } | |
| .copy-button { | |
| appearance: none; | |
| position: absolute; | |
| inset-block-start: var(--space-2); | |
| inset-inline-end: var(--space-2); | |
| display: inline-flex; | |
| align-items: center; | |
| justify-content: center; | |
| min-height: 26px; | |
| padding: 0 9px; | |
| border: 1px solid rgba(250, 249, 245, 0.18); | |
| border-radius: var(--radius-sm); | |
| color: var(--color-gray-100); | |
| background: rgba(255, 255, 255, 0.08); | |
| font-family: var(--font-mono); | |
| font-size: var(--text-xs); | |
| font-weight: 700; | |
| letter-spacing: 0.04em; | |
| text-transform: uppercase; | |
| transition: | |
| background-color var(--dur-fast) var(--ease), | |
| border-color var(--dur-fast) var(--ease), | |
| transform var(--dur-fast) var(--ease); | |
| } | |
| .copy-button:hover { | |
| transform: translateY(-1px); | |
| border-color: rgba(250, 249, 245, 0.35); | |
| background: rgba(255, 255, 255, 0.14); | |
| } | |
| .copy-button[data-copied="true"] { | |
| color: var(--color-white); | |
| background: rgba(120, 140, 93, 0.55); | |
| border-color: rgba(120, 140, 93, 0.75); | |
| } | |
| .reference-panel { | |
| --panel-pad: var(--space-5); | |
| } | |
| .callout { | |
| padding: var(--space-5); | |
| color: var(--text-soft); | |
| background: var(--surface-tint); | |
| border: var(--border); | |
| border-inline-start: 4px solid var(--accent); | |
| border-radius: var(--radius-md); | |
| } | |
| .callout[data-tone="success"] { | |
| border-inline-start-color: var(--success); | |
| background: rgba(120, 140, 93, 0.10); | |
| } | |
| .callout[data-tone="warning"] { | |
| border-inline-start-color: var(--warning); | |
| background: rgba(199, 142, 63, 0.11); | |
| } | |
| .callout[data-tone="danger"] { | |
| border-inline-start-color: var(--danger); | |
| background: rgba(176, 74, 63, 0.10); | |
| } | |
| .callout[data-tone="info"] { | |
| border-inline-start-color: var(--info); | |
| background: rgba(106, 140, 175, 0.11); | |
| } | |
| .callout-label { | |
| display: block; | |
| margin-bottom: var(--space-2); | |
| color: var(--text-muted); | |
| font-family: var(--font-mono); | |
| font-size: var(--text-xs); | |
| font-weight: 700; | |
| letter-spacing: 0.09em; | |
| text-transform: uppercase; | |
| } | |
| .callout > :last-child { | |
| margin-bottom: 0; | |
| } | |
| .checklist { | |
| list-style: none; | |
| margin: 0; | |
| padding: 0; | |
| display: grid; | |
| gap: var(--space-3); | |
| } | |
| .checklist li { | |
| display: block ; | |
| position: relative ; | |
| min-width: 0; | |
| padding-inline-start: calc(18px + var(--space-3)); | |
| overflow-wrap: anywhere; | |
| } | |
| .checklist li::before { | |
| content: "✓"; | |
| position: absolute ; | |
| inset-block-start: 2px; | |
| inset-inline-start: 0; | |
| display: inline-flex; | |
| align-items: center; | |
| justify-content: center; | |
| width: 18px; | |
| height: 18px; | |
| border-radius: 50%; | |
| color: var(--success); | |
| background: rgba(120, 140, 93, 0.12); | |
| font-family: var(--font-mono); | |
| font-size: 12px; | |
| font-weight: 700; | |
| line-height: 1; | |
| } | |
| .checklist code { | |
| white-space: normal; | |
| overflow-wrap: anywhere; | |
| word-break: break-word; | |
| } | |
| .plain-list { | |
| margin: 0; | |
| padding-inline-start: 1.15em; | |
| color: var(--text-soft); | |
| } | |
| .plain-list li { | |
| overflow-wrap: anywhere; | |
| } | |
| .plain-list li + li { | |
| margin-top: var(--space-2); | |
| } | |
| .plain-list li::marker { | |
| color: var(--text-muted); | |
| } | |
| .insight-list, | |
| .takeaway-list { | |
| list-style: none; | |
| margin: 0; | |
| padding: 0; | |
| display: grid; | |
| gap: var(--space-3); | |
| } | |
| .insight-list li, | |
| .takeaway-list li { | |
| position: relative; | |
| display: block; | |
| padding-inline-start: calc(10px + var(--space-3)); | |
| color: var(--text-soft); | |
| } | |
| .insight-list li::before, | |
| .takeaway-list li::before { | |
| content: ""; | |
| position: absolute; | |
| inset-block-start: 0.65em; | |
| inset-inline-start: 0; | |
| width: 7px; | |
| height: 7px; | |
| border-radius: 50%; | |
| background: var(--accent); | |
| } | |
| .insight-list li > *, | |
| .takeaway-list li > * { | |
| min-width: 0; | |
| } | |
| .insight-list[data-tone="success"] li::before, | |
| .takeaway-list[data-tone="success"] li::before { | |
| background: var(--success); | |
| } | |
| .insight-list[data-tone="info"] li::before, | |
| .takeaway-list[data-tone="info"] li::before { | |
| background: var(--info); | |
| } | |
| .metric-list { | |
| --metric-label: 132px; | |
| --metric-value: 64px; | |
| display: grid; | |
| gap: var(--space-3); | |
| } | |
| .metric-row { | |
| display: grid; | |
| grid-template-columns: var(--metric-label) minmax(120px, 1fr) var(--metric-value); | |
| gap: var(--space-3); | |
| align-items: center; | |
| } | |
| .metric-row > :first-child { | |
| min-width: 0; | |
| } | |
| .metric-row > :last-child { | |
| justify-self: end; | |
| font-family: var(--font-mono); | |
| font-size: var(--text-sm); | |
| } | |
| .meter { | |
| height: 9px; | |
| overflow: hidden; | |
| border-radius: var(--radius-pill); | |
| background: var(--surface-tint); | |
| } | |
| .meter span { | |
| display: block; | |
| width: var(--value); | |
| height: 100%; | |
| background: var(--tone, var(--accent)); | |
| } | |
| .flow-list { | |
| list-style: none; | |
| margin: 0; | |
| padding: 0; | |
| display: grid; | |
| gap: var(--space-3); | |
| } | |
| .flow-step { | |
| position: relative; | |
| display: grid; | |
| grid-template-columns: 42px minmax(0, 1fr); | |
| gap: var(--space-3); | |
| align-items: start; | |
| padding: var(--space-4); | |
| background: var(--surface); | |
| border: var(--border); | |
| border-radius: var(--radius-md); | |
| } | |
| .flow-step > .flow-num { | |
| grid-column: 1; | |
| } | |
| .flow-step > :not(.flow-num) { | |
| grid-column: 2; | |
| min-width: 0; | |
| } | |
| .flow-step::after { | |
| content: ""; | |
| position: absolute; | |
| inset-block-start: calc(100% + 1px); | |
| inset-inline-start: 36px; | |
| width: 1.5px; | |
| height: var(--space-3); | |
| background: var(--border-color); | |
| } | |
| .flow-step:last-child::after { | |
| display: none; | |
| } | |
| .flow-num { | |
| display: inline-flex; | |
| align-items: center; | |
| justify-content: center; | |
| width: 34px; | |
| height: 34px; | |
| border-radius: var(--radius-pill); | |
| color: var(--text); | |
| background: var(--surface-warm); | |
| box-shadow: inset 0 0 0 1px rgba(20, 20, 19, 0.10); | |
| font-family: var(--font-mono); | |
| font-size: var(--text-sm); | |
| font-weight: 700; | |
| } | |
| .flow-title { | |
| margin: 0 0 var(--space-1); | |
| font-family: var(--font-serif); | |
| font-size: var(--text-xl); | |
| font-weight: 550; | |
| line-height: var(--leading-title); | |
| } | |
| .flow-detail { | |
| margin: 0; | |
| color: var(--text-soft); | |
| } | |
| .flow-branch { | |
| display: grid; | |
| grid-template-columns: repeat(2, minmax(0, 1fr)); | |
| gap: var(--space-3); | |
| } | |
| .flow-branch .flow-step::after { | |
| display: none; | |
| } | |
| .flow-step[data-tone="success"] { | |
| border-color: rgba(120, 140, 93, 0.38); | |
| background: rgba(120, 140, 93, 0.08); | |
| } | |
| .flow-step[data-tone="warning"] { | |
| border-color: rgba(199, 142, 63, 0.42); | |
| background: rgba(199, 142, 63, 0.09); | |
| } | |
| @media (max-width: 620px) { | |
| .metric-row { | |
| grid-template-columns: 1fr max-content; | |
| } | |
| .metric-row .meter { | |
| grid-column: 1 / -1; | |
| order: 3; | |
| } | |
| .flow-branch { | |
| grid-template-columns: 1fr; | |
| } | |
| } | |
| /* ---------- Charts and numeric data ---------- */ | |
| .chart-panel { | |
| max-width: 100%; | |
| min-width: 0; | |
| overflow: hidden; | |
| } | |
| .chart-panel > * { | |
| min-width: 0; | |
| } | |
| .chart-panel svg, | |
| svg.chart-svg { | |
| display: block; | |
| width: 100%; | |
| height: auto; | |
| } | |
| .chart-caption { | |
| color: var(--text-muted); | |
| font-size: var(--text-sm); | |
| } | |
| .numeric-table-wrap { | |
| overflow-x: auto; | |
| background: var(--surface); | |
| border: var(--border); | |
| border-radius: var(--radius-md); | |
| } | |
| .numeric-table { | |
| width: 100%; | |
| min-width: 720px; | |
| border-collapse: collapse; | |
| } | |
| .numeric-table th, | |
| .numeric-table td { | |
| padding: var(--space-3) var(--space-4); | |
| border-bottom: 1px solid var(--color-gray-200); | |
| vertical-align: middle; | |
| } | |
| .numeric-table th { | |
| color: var(--text-muted); | |
| background: var(--surface-tint); | |
| font-family: var(--font-mono); | |
| font-size: var(--text-xs); | |
| font-weight: 700; | |
| letter-spacing: 0.08em; | |
| text-align: left; | |
| text-transform: uppercase; | |
| } | |
| .numeric-table tr:last-child td { | |
| border-bottom: 0; | |
| } | |
| .numeric-table .metric, | |
| .numeric-table .num { | |
| text-align: right; | |
| font-variant-numeric: tabular-nums; | |
| white-space: nowrap; | |
| } | |
| .numeric-table .entity, | |
| .numeric-table .label-cell { | |
| font-weight: 650; | |
| } | |
| .numeric-table .note { | |
| color: var(--text-soft); | |
| } | |
| .numeric-table code { | |
| white-space: normal; | |
| overflow-wrap: anywhere; | |
| word-break: break-word; | |
| } | |
| .numeric-table .subtle { | |
| display: block; | |
| margin-top: 2px; | |
| color: var(--text-muted); | |
| font-family: var(--font-mono); | |
| font-size: var(--text-xs); | |
| font-weight: 400; | |
| } | |
| @media (max-width: 620px) { | |
| .numeric-table { | |
| min-width: 0; | |
| } | |
| .numeric-table thead { | |
| display: none; | |
| } | |
| .numeric-table tbody, | |
| .numeric-table tr, | |
| .numeric-table td { | |
| display: block; | |
| } | |
| .numeric-table tr { | |
| padding: var(--space-3) var(--space-4); | |
| border-bottom: 1px solid var(--color-gray-200); | |
| } | |
| .numeric-table tr:last-child { | |
| border-bottom: 0; | |
| } | |
| .numeric-table td { | |
| padding: var(--space-1) 0; | |
| border-bottom: 0; | |
| } | |
| .numeric-table td[data-label] { | |
| display: flex; | |
| justify-content: space-between; | |
| gap: var(--space-4); | |
| } | |
| .numeric-table td[data-label]::before { | |
| content: attr(data-label); | |
| color: var(--text-muted); | |
| font-family: var(--font-mono); | |
| font-size: var(--text-xs); | |
| text-transform: uppercase; | |
| } | |
| } | |
| /* ---------- Diff ---------- */ | |
| .diff { | |
| overflow-x: auto; | |
| color: #E8E6DC; | |
| background: var(--color-slate); | |
| border-radius: var(--radius-md); | |
| font-family: var(--font-mono); | |
| font-size: 12.5px; | |
| line-height: var(--leading-loose); | |
| } | |
| .diff-row { | |
| display: grid; | |
| grid-template-columns: 48px 18px minmax(max-content, 1fr); | |
| align-items: baseline; | |
| min-width: max-content; | |
| padding-inline-end: var(--space-4); | |
| white-space: pre; | |
| } | |
| .diff-row .ln { | |
| padding-inline-end: 14px; | |
| color: var(--color-gray-500); | |
| text-align: right; | |
| user-select: none; | |
| } | |
| .diff-row .mark { | |
| color: var(--color-gray-500); | |
| text-align: center; | |
| } | |
| .diff-row .code { | |
| color: #E8E6DC; | |
| } | |
| .diff-row.ctx .code, | |
| .diff-row[data-kind="ctx"] .code { | |
| color: #B8B6AC; | |
| } | |
| .diff-row.add, | |
| .diff-row[data-kind="add"] { | |
| background: rgba(120, 140, 93, 0.24); | |
| box-shadow: inset 3px 0 0 rgba(120, 140, 93, 0.78); | |
| } | |
| .diff-row.add .mark, | |
| .diff-row[data-kind="add"] .mark { | |
| color: #B9D394; | |
| font-weight: 800; | |
| } | |
| .diff-row.del, | |
| .diff-row[data-kind="del"] { | |
| background: rgba(176, 74, 63, 0.24); | |
| box-shadow: inset 3px 0 0 rgba(176, 74, 63, 0.82); | |
| } | |
| .diff-row.del .mark, | |
| .diff-row[data-kind="del"] .mark { | |
| color: #F19A8D; | |
| font-weight: 800; | |
| } | |
| .diff-row.hunk, | |
| .diff-row[data-kind="hunk"] { | |
| background: rgba(255, 255, 255, 0.045); | |
| } | |
| .diff-row.hunk .code, | |
| .diff-row[data-kind="hunk"] .code { | |
| color: var(--color-gray-500); | |
| } | |
| .diff[data-wrap="true"] { | |
| overflow-x: hidden; | |
| } | |
| .diff[data-wrap="true"] .diff-row { | |
| grid-template-columns: 42px 18px minmax(0, 1fr); | |
| min-width: 0; | |
| white-space: normal; | |
| } | |
| .diff[data-wrap="true"] .code { | |
| white-space: pre-wrap; | |
| overflow-wrap: anywhere; | |
| } | |
| /* ---------- Timeline ---------- */ | |
| .timeline { | |
| position: relative; | |
| display: grid; | |
| gap: 0; | |
| padding-inline-start: var(--space-6); | |
| } | |
| .timeline:is(ol, ul) { | |
| margin: 0; | |
| list-style: none; | |
| } | |
| .timeline::before { | |
| content: ""; | |
| position: absolute; | |
| inset-block: 4px 4px; | |
| inset-inline-start: 9px; | |
| width: 1.5px; | |
| background: var(--border-color); | |
| } | |
| .timeline-item, | |
| .tl-entry { | |
| position: relative; | |
| display: grid; | |
| grid-template-columns: minmax(84px, max-content) minmax(0, 1fr); | |
| gap: var(--space-4); | |
| padding-block: 0 var(--space-5); | |
| } | |
| .timeline-item:last-child, | |
| .tl-entry:last-child { | |
| padding-block-end: 0; | |
| } | |
| .timeline-item::before, | |
| .tl-entry::before { | |
| content: ""; | |
| position: absolute; | |
| inset-block-start: 4px; | |
| inset-inline-start: calc(4.25px - var(--space-6)); | |
| width: 11px; | |
| height: 11px; | |
| border: 2px solid var(--surface); | |
| border-radius: 50%; | |
| background: var(--accent); | |
| box-shadow: 0 0 0 1.5px var(--accent); | |
| } | |
| .timeline-item:not(:has(> .timeline-time, > .tl-time)), | |
| .tl-entry:not(:has(> .timeline-time, > .tl-time)) { | |
| display: block; | |
| } | |
| .timeline-time, | |
| .tl-time { | |
| color: var(--text-muted); | |
| font-family: var(--font-mono); | |
| font-size: var(--text-sm); | |
| white-space: nowrap; | |
| } | |
| .timeline-body, | |
| .tl-body { | |
| min-width: 0; | |
| color: var(--text-soft); | |
| } | |
| .timeline-body strong, | |
| .tl-body strong { | |
| color: var(--text); | |
| } | |
| @media (max-width: 620px) { | |
| .timeline-item, | |
| .tl-entry { | |
| grid-template-columns: 1fr; | |
| gap: var(--space-1); | |
| } | |
| } | |
| /* ---------- Flowchart ---------- */ | |
| .flowchart { | |
| display: block; | |
| width: 100%; | |
| height: auto; | |
| } | |
| svg.flow, | |
| svg.flowchart { | |
| display: block; | |
| width: 100%; | |
| height: auto; | |
| } | |
| .flow text, | |
| .flowchart text { | |
| fill: var(--text); | |
| font-family: var(--font-sans); | |
| font-size: 12px; | |
| } | |
| .flow .sub, | |
| .flowchart .sub { | |
| fill: var(--text-muted); | |
| font-size: 10px; | |
| } | |
| .flow-edge, | |
| .edge { | |
| fill: none; | |
| stroke: var(--text-muted); | |
| stroke-width: 1.5; | |
| } | |
| .flow-edge[data-kind="yes"], | |
| .edge.yes { | |
| stroke: var(--success); | |
| } | |
| .flow-edge[data-kind="no"], | |
| .edge.no { | |
| stroke: var(--danger); | |
| stroke-dasharray: 4 4; | |
| } | |
| /* SVG flow nodes */ | |
| .flow-node, | |
| .flow .node { | |
| cursor: pointer; | |
| transition: transform var(--dur-fast) var(--ease); | |
| } | |
| .flow-node:hover, | |
| .flow .node:hover { | |
| transform: translateY(-1px); | |
| } | |
| .flow-node rect, | |
| .flow .node rect { | |
| fill: var(--surface); | |
| stroke: var(--border-color); | |
| stroke-width: 1.5; | |
| rx: 8; | |
| } | |
| .flow-node path, | |
| .flow .node.gate path { | |
| fill: var(--surface); | |
| stroke: var(--border-color); | |
| stroke-width: 1.5; | |
| } | |
| .flow-node[data-shape="term"] rect, | |
| .flow .node.term rect { | |
| fill: var(--surface-tint); | |
| rx: 22; | |
| } | |
| .flow-node[data-kind="ok"] rect, | |
| .flow .node.ok rect { | |
| fill: rgba(120, 140, 93, 0.12); | |
| stroke: var(--success); | |
| } | |
| .flow-node[data-kind="bad"] rect, | |
| .flow .node.bad rect { | |
| fill: rgba(176, 74, 63, 0.10); | |
| stroke: var(--danger); | |
| } | |
| .flow-node.active rect, | |
| .flow-node.active path, | |
| .flow .node.active rect, | |
| .flow .node.active path { | |
| stroke: var(--accent); | |
| stroke-width: 2; | |
| } | |
| /* HTML flow nodes, for non-SVG diagrams */ | |
| div.flow-node { | |
| padding: var(--space-3) var(--space-4); | |
| background: var(--surface); | |
| border: var(--border); | |
| border-radius: var(--radius-sm); | |
| transition: | |
| transform var(--dur-fast) var(--ease), | |
| border-color var(--dur-fast) var(--ease), | |
| box-shadow var(--dur-fast) var(--ease); | |
| } | |
| div.flow-node:hover { | |
| transform: translateY(var(--hover-y)); | |
| border-color: rgba(217, 119, 87, 0.55); | |
| box-shadow: var(--shadow-sm); | |
| } | |
| div.flow-node[data-shape="term"] { | |
| border-radius: var(--radius-pill); | |
| background: var(--surface-tint); | |
| } | |
| div.flow-node[data-kind="ok"] { | |
| border-color: var(--success); | |
| background: rgba(120, 140, 93, 0.12); | |
| } | |
| div.flow-node[data-kind="bad"] { | |
| border-color: var(--danger); | |
| background: rgba(176, 74, 63, 0.10); | |
| } | |
| @media (prefers-reduced-motion: reduce) { | |
| *, | |
| *::before, | |
| *::after { | |
| scroll-behavior: auto ; | |
| transition-duration: 0.01ms ; | |
| animation-duration: 0.01ms ; | |
| animation-iteration-count: 1 ; | |
| } | |
| } | |
| /* Responsive safety net for generated artifacts. */ | |
| p, | |
| li { | |
| overflow-wrap: anywhere; | |
| } | |
| @media (max-width: 860px) { | |
| .split, | |
| .section-rail, | |
| .sidebar-layout { | |
| grid-template-columns: minmax(0, 1fr) ; | |
| } | |
| .split > *, | |
| .section-rail > *, | |
| .sidebar-layout > *, | |
| .chart-panel { | |
| width: 100%; | |
| max-width: 100%; | |
| min-width: 0; | |
| } | |
| } | |
| </style> | |
| </head> | |
| <body> | |
| <main class="page stack" data-gap="lg"> | |
| <header class="stack" data-gap="sm"> | |
| <div class="eyebrow">Module explainer</div> | |
| <h1>The rendering checker is a deterministic HTML/visual smoke pipeline that catches Birch contract violations before they ship.</h1> | |
| <p class="lede">A three-stage pipeline — static parsing, headless screenshot capture, and browser geometry audit — turns a single HTML artifact into a structured JSON/Markdown report. Source-grounded from <code>scripts/check_birch_renderings.py</code>, <code>scripts/birch_mpl.py</code>, <code>evals/charts/</code>, and the Birch CSS contracts in <code>styles/birch-system.css</code>.</p> | |
| <div class="cluster"> | |
| <span class="chip">Python</span> | |
| <span class="chip" data-tone="clay">Chrome headless</span> | |
| <span class="chip" data-tone="olive">Pillow</span> | |
| <span class="chip" data-tone="sky">Static HTML parsing</span> | |
| </div> | |
| </header> | |
| <section class="section stack" data-gap="lg"> | |
| <div class="section-head"> | |
| <span class="eyebrow">Mental model</span> | |
| </div> | |
| <div class="panel chart-panel stack" data-gap="sm"> | |
| <svg class="chart-svg" viewBox="0 0 680 340" role="img" aria-label="Rendering checker pipeline: artifact/HTML input flows through static checks, browser capture, and geometry audit to produce findings and reports"> | |
| <defs> | |
| <marker id="arrow" viewBox="0 0 10 7" refX="10" refY="3.5" markerWidth="8" markerHeight="6" orient="auto"><polygon points="0 0, 10 3.5, 0 7" fill="#3D3D3A"/></marker> | |
| </defs> | |
| <!-- Stage 1: Input --> | |
| <g class="flow-node" data-shape="term"> | |
| <rect x="30" y="20" width="140" height="48" rx="22"/> | |
| <text x="100" y="42" text-anchor="middle" fill="#141413" font-family="system-ui,sans-serif" font-size="13" font-weight="600">HTML artifact</text> | |
| <text x="100" y="57" text-anchor="middle" fill="#87867F" font-family="ui-monospace,monospace" font-size="10">--artifact or --pair</text> | |
| </g> | |
| <!-- Stage 2: Static checks --> | |
| <g class="flow-node"> | |
| <rect x="230" y="12" width="180" height="64" rx="8"/> | |
| <text x="320" y="36" text-anchor="middle" fill="#141413" font-family="system-ui,sans-serif" font-size="13" font-weight="600">Static HTML/CSS checks</text> | |
| <text x="320" y="54" text-anchor="middle" fill="#87867F" font-family="ui-monospace,monospace" font-size="10">PageStats + contract_findings</text> | |
| <text x="320" y="68" text-anchor="middle" fill="#87867F" font-family="ui-monospace,monospace" font-size="10">Component parsers</text> | |
| </g> | |
| <!-- Stage 3: Browser capture --> | |
| <g class="flow-node"> | |
| <rect x="460" y="12" width="180" height="64" rx="8"/> | |
| <text x="550" y="36" text-anchor="middle" fill="#141413" font-family="system-ui,sans-serif" font-size="13" font-weight="600">Browser capture</text> | |
| <text x="550" y="54" text-anchor="middle" fill="#87867F" font-family="ui-monospace,monospace" font-size="10">Chrome --headless=new</text> | |
| <text x="550" y="68" text-anchor="middle" fill="#87867F" font-family="ui-monospace,monospace" font-size="10">--screenshot + --dump-dom</text> | |
| </g> | |
| <!-- Stage 4: Screenshot analysis --> | |
| <g class="flow-node"> | |
| <rect x="260" y="120" width="180" height="64" rx="8"/> | |
| <text x="350" y="144" text-anchor="middle" fill="#141413" font-family="system-ui,sans-serif" font-size="13" font-weight="600">Screenshot analysis</text> | |
| <text x="350" y="162" text-anchor="middle" fill="#87867F" font-family="ui-monospace,monospace" font-size="10">Pillow palette/diff metrics</text> | |
| <text x="350" y="176" text-anchor="middle" fill="#87867F" font-family="ui-monospace,monospace" font-size="10">Blank render detection</text> | |
| </g> | |
| <!-- Stage 5: Geometry audit --> | |
| <g class="flow-node"> | |
| <rect x="460" y="120" width="180" height="64" rx="8"/> | |
| <text x="550" y="144" text-anchor="middle" fill="#141413" font-family="system-ui,sans-serif" font-size="13" font-weight="600">Geometry audit</text> | |
| <text x="550" y="162" text-anchor="middle" fill="#87867F" font-family="ui-monospace,monospace" font-size="10">Injected JS layout probes</text> | |
| <text x="550" y="176" text-anchor="middle" fill="#87867F" font-family="ui-monospace,monospace" font-size="10">Overflow/wrap detection</text> | |
| </g> | |
| <!-- Stage 6: Output --> | |
| <g class="flow-node" data-shape="term"> | |
| <rect x="360" y="240" width="140" height="48" rx="22"/> | |
| <text x="430" y="262" text-anchor="middle" fill="#141413" font-family="system-ui,sans-serif" font-size="13" font-weight="600">Reports</text> | |
| <text x="430" y="277" text-anchor="middle" fill="#87867F" font-family="ui-monospace,monospace" font-size="10">JSON + Markdown</text> | |
| </g> | |
| <!-- Edges --> | |
| <line x1="170" y1="44" x2="222" y2="44" stroke="#87867F" stroke-width="1.5" marker-end="url(#arrow)"/> | |
| <line x1="410" y1="44" x2="452" y2="44" stroke="#87867F" stroke-width="1.5" marker-end="url(#arrow)"/> | |
| <path d="M550,76 L550,112" stroke="#87867F" stroke-width="1.5" marker-end="url(#arrow)"/> | |
| <line x1="550" y1="76" x2="550" y2="96"/> | |
| <path d="M550,76 L350,76 L350,112" stroke="#87867F" stroke-width="1.5" fill="none" marker-end="url(#arrow)"/> | |
| <line x1="350" y1="184" x2="350" y2="204" stroke="#87867F" stroke-width="1.5"/> | |
| <path d="M350,204 L350,234 L430,234" stroke="#87867F" stroke-width="1.5" fill="none" marker-end="url(#arrow)"/> | |
| <line x1="550" y1="184" x2="550" y2="204" stroke="#87867F" stroke-width="1.5"/> | |
| <path d="M550,204 L550,234 L430,234" stroke="#87867F" stroke-width="1.5" fill="none" marker-end="url(#arrow)"/> | |
| </svg> | |
| <p class="chart-caption">Pipeline flow from <code>main()</code> in <code>scripts/check_birch_renderings.py</code>. In --artifact mode (preferred for generated eval outputs), the screenshot analysis and geometry audit run against a single file; in --pair mode, they compare reference and candidate.</p> | |
| </div> | |
| <div class="card stack" data-variant="outlined"> | |
| <h3>What the checker actually does</h3> | |
| <p>At its core, <code>check_birch_renderings.py</code> is a <strong>deterministic, parse-first, browser-augmented</strong> validator. It does not use vision models, ML, or heuristics trained on prior artifacts. It reads the HTML file as text, parses it with specialized <code>HTMLParser</code> subclasses, then optionally launches Chrome to capture a screenshot and run a geometry audit script. Every finding is a structured (level, name, evidence) triple produced by a named check function.</p> | |
| <p>The checker was designed to be <strong>simpler and more deterministic</strong> than the neighboring Birchline tooling. Its static checks are pure Python <code>html.parser.HTMLParser</code> subclasses — no DOM, no layout engine, no heuristic thresholds beyond explicit CSS minimums. The browser stage adds visual smoke detection that static parsing cannot see: blank renders, overflowing text, misaligned metric bars, and wrapping pathology.</p> | |
| </div> | |
| </section> | |
| <section class="section stack" data-gap="lg"> | |
| <div class="section-head"> | |
| <span class="eyebrow">Runtime path</span> | |
| <h2>From input paths to findings</h2> | |
| </div> | |
| <ol class="flow-list"> | |
| <li class="flow-step"> | |
| <span class="flow-num">1</span> | |
| <div class="stack" data-gap="xs"> | |
| <h3 class="flow-title">Parse CLI args and resolve inputs</h3> | |
| <p class="flow-detail"><code>main()</code> in <code>scripts/check_birch_renderings.py</code> resolves <code>--artifact</code> (single-file) or <code>--pair</code> (reference:candidate) paths relative to the repo root. In artifact mode, each path is checked independently; pair mode compares stats and screenshots between original and candidate. The two modes are mutually exclusive.</p> | |
| </div> | |
| </li> | |
| <li class="flow-step"> | |
| <span class="flow-num">2</span> | |
| <div class="stack" data-gap="xs"> | |
| <h3 class="flow-title">Run static HTML/CSS contract checks</h3> | |
| <p class="flow-detail"><code>page_stats()</code> feeds the HTML through <code>StatsParser</code> to count tags, classes, CSS vars, words, and style bytes. Then <code>contract_findings()</code> runs a battery of checks: doctype, viewport meta, Birch CSS embedding (≥10 KB with all five signatures), <code>.page</code> shell, layout/semantic primitive counts, unknown CSS variables, patch marker lines, gradient prohibition, palette color purity, and SVG chart mark correctness.</p> | |
| </div> | |
| </li> | |
| <li class="flow-step"> | |
| <span class="flow-num">3</span> | |
| <div class="stack" data-gap="xs"> | |
| <h3 class="flow-title">Run component-specific contract parsers</h3> | |
| <p class="flow-detail">Seven focused <code>HTMLParser</code> subclasses validate child-count contracts for Birch components: <code>GridListParser</code> (insight/takeaway list children), <code>ChecklistParser</code> (inline markup in checklist rows), <code>MetricRowParser</code> (caption + meter + code), <code>DiffRowParser</code> (ln + mark + code columns), <code>DiffPolarityParser</code> (add/del class or data-kind), <code>FlowStepParser</code> (flow-num + one wrapper), and <code>TimelineParser</code> (timeline-time + timeline-body).</p> | |
| </div> | |
| </li> | |
| <li class="flow-step"> | |
| <span class="flow-num">4</span> | |
| <div class="stack" data-gap="xs"> | |
| <h3 class="flow-title">Launch headless Chrome for screenshot capture</h3> | |
| <p class="flow-detail"><code>capture()</code> opens the HTML file via <code>file://</code> URI in Chrome <code>--headless=new</code> with <code>--no-sandbox</code>. For deep viewports, <code>capture_height_for_viewport()</code> measures the document height first via an injected script that sets <code>data-birch-doc-height</code>, then captures at the measured height (capped at the viewport max). Screenshots land in <code>reports/birch-screenshots/</code>.</p> | |
| </div> | |
| </li> | |
| <li class="flow-step"> | |
| <span class="flow-num">5</span> | |
| <div class="stack" data-gap="xs"> | |
| <h3 class="flow-title">Analyze screenshots with Pillow</h3> | |
| <p class="flow-detail">In artifact mode, <code>artifact_screenshot_metrics()</code> sub-samples the PNG, computes background/non-background/blackish fractions, and checks for blank renders (file <2 KB or <2.5% non-background). In pair mode, <code>screenshot_metrics()</code> computes per-pixel RGB difference, generates an amplified diff PNG and a contact sheet.</p> | |
| </div> | |
| </li> | |
| <li class="flow-step"> | |
| <span class="flow-num">6</span> | |
| <div class="stack" data-gap="xs"> | |
| <h3 class="flow-title">Run browser geometry audit</h3> | |
| <p class="flow-detail"><code>geometry_audit()</code> injects a ~500-line JS script that probes the live layout: overflow detection, container text spill, stat-card squeeze, metric bar alignment, timeline marker position, code-block wrapping pathology, and prose text underfill. Results are serialized into <code>data-birch-audit</code> on the body and extracted from Chrome's <code>--dump-dom</code> output.</p> | |
| </div> | |
| </li> | |
| <li class="flow-step"> | |
| <span class="flow-num">7</span> | |
| <div class="stack" data-gap="xs"> | |
| <h3 class="flow-title">Emit JSON and Markdown reports</h3> | |
| <p class="flow-detail">All findings are collected into a payload with a summary hash (mode, artifact/pair count, failures, warnings, notes). <code>render_markdown()</code> produces a human-readable Markdown file with per-artifact tables; the raw JSON is written to the <code>--out</code> path. The script exits with code 1 on failures (or on warnings when <code>--fail-on-warn</code>).</p> | |
| </div> | |
| </li> | |
| </ol> | |
| </section> | |
| <section class="section stack" data-gap="lg"> | |
| <div class="section-head"> | |
| <div> | |
| <span class="eyebrow">File tour</span> | |
| <h2>Reading order for new contributors</h2> | |
| </div> | |
| </div> | |
| <p class="muted">Each file is described with its role in the checker pipeline, the key functions/classes to read first, and how it connects to the others. Start at the top.</p> | |
| <div class="stack" data-gap="md"> | |
| <article class="card stack" data-variant="outlined" data-accent="clay"> | |
| <div class="card-head"> | |
| <div class="avatar">1</div> | |
| <div class="card-titles"> | |
| <h3 class="card-title"><code>scripts/check_birch_renderings.py</code></h3> | |
| <p class="card-sub">~1,400 lines · The main checker</p> | |
| </div> | |
| </div> | |
| <p>This is the heart of the pipeline. Start with <code>main()</code> to see the top-level flow, then read <code>check_artifact()</code> (the artifact-mode entry point) and <code>contract_findings()</code> (the static check battery). The <code>HTMLParser</code> subclasses — <code>StatsParser</code>, <code>GridListParser</code>, <code>ChecklistParser</code>, <code>MetricRowParser</code>, <code>DiffRowParser</code>, <code>DiffPolarityParser</code>, <code>FlowStepParser</code>, <code>TimelineParser</code> — are each ~40–80 lines and validate a single component contract. The browser integration lives in <code>find_chrome()</code>, <code>capture()</code>, <code>geometry_audit()</code>, and <code>geometry_findings()</code>.</p> | |
| <p class="muted">Key functions: <code>main</code>, <code>check_artifact</code>, <code>contract_findings</code>, <code>page_stats</code>, <code>geometry_audit</code>, <code>geometry_findings</code>, <code>svg_visual_findings</code>.</p> | |
| </article> | |
| <article class="card stack" data-variant="outlined"> | |
| <div class="card-head"> | |
| <div class="avatar">2</div> | |
| <div class="card-titles"> | |
| <h3 class="card-title"><code>scripts/birch_mpl.py</code></h3> | |
| <p class="card-sub">~120 lines · Matplotlib helpers</p> | |
| </div> | |
| </div> | |
| <p>Provides the Birch Matplotlib theme used by artifact generators like <code>build_chart_brief.py</code>. Read <code>rc_params()</code> for the token-to-Matplotlib color mapping, <code>birch_theme()</code> (a context manager that applies rcParams), <code>polish_axes()</code> for grid/spine cleanup, and <code>svg_string()</code> for serializing a figure as inlineable SVG. This file is not called by the checker; it is used during artifact generation.</p> | |
| <p class="muted">Key functions: <code>rc_params</code>, <code>birch_theme</code>, <code>polish_axes</code>, <code>svg_string</code>, <code>close</code>.</p> | |
| </article> | |
| <article class="card stack" data-variant="outlined"> | |
| <div class="card-head"> | |
| <div class="avatar">3</div> | |
| <div class="card-titles"> | |
| <h3 class="card-title"><code>evals/charts/build_chart_brief.py</code></h3> | |
| <p class="card-sub">~200 lines · Example artifact generator</p> | |
| </div> | |
| </div> | |
| <p>Generates <code>24-birch-chart-brief.html</code> from <code>evals/charts/sample-data.csv</code>. This is the best example of what a checked artifact looks like: it loads CSV rows, builds a Matplotlib SVG via <code>birch_mpl</code>, assembles KPI cards, metric rows, and a numeric table, then writes the complete Birch HTML. Read <code>main()</code> and <code>build_svg()</code> first; the HTML template at the end shows the canonical Birch structure the checker expects.</p> | |
| <p class="muted">Key functions: <code>main</code>, <code>build_svg</code>, <code>metric_rows</code>, <code>table_rows</code>.</p> | |
| </article> | |
| <article class="card stack" data-variant="outlined"> | |
| <div class="card-head"> | |
| <div class="avatar">4</div> | |
| <div class="card-titles"> | |
| <h3 class="card-title"><code>evals/charts/run_eval.py</code></h3> | |
| <p class="card-sub">~50 lines · Eval runner</p> | |
| </div> | |
| </div> | |
| <p>Ties generation and checking together. Runs <code>build_chart_brief.py</code> first, then calls <code>check_birch_renderings.py --artifact</code> at four viewports (desktop, mobile, deep, mobile-deep). Each viewport produces its own JSON and Markdown report. This is the pattern to follow when adding new eval artifacts.</p> | |
| <p class="muted">Key: the <code>VIEWPORTS</code> dict and the <code>run()</code> loop.</p> | |
| </article> | |
| <article class="card stack" data-variant="outlined"> | |
| <div class="card-head"> | |
| <div class="avatar">5</div> | |
| <div class="card-titles"> | |
| <h3 class="card-title"><code>docs/birch-llm-style-guide.md</code></h3> | |
| <p class="card-sub">~460 lines · The contract being checked</p> | |
| </div> | |
| </div> | |
| <p>This is the authoritative LLM contract that the checker enforces. It defines required shell structure, layout primitives, semantic components, CSS variable tokens, and strict child-count contracts for diff rows, flow steps, metric rows, and timeline items. When you add a new check to the checker, it should correspond to a rule in this guide.</p> | |
| <p class="muted">Key sections: Required page shell, quick primitive index, diff, timeline, flow steps, metric rows, charts and numeric data, rules for LLM generation.</p> | |
| </article> | |
| <article class="card stack" data-variant="outlined"> | |
| <div class="card-head"> | |
| <div class="avatar">6</div> | |
| <div class="card-titles"> | |
| <h3 class="card-title"><code>styles/birch-system.css</code></h3> | |
| <p class="card-sub">~1,100 lines · The CSS that implements the contracts</p> | |
| </div> | |
| </div> | |
| <p>The canonical stylesheet that the checker verifies is embedded (or linked). The checker asserts the embedded Birch CSS block is ≥10 KB and contains the five signature strings: <code>--color-ivory</code>, <code>--font-serif</code>, <code>.page</code>, <code>.section</code>, <code>.card</code>. When geometry audit probes measure overflow or wrapping, they are testing against the layout defined here.</p> | |
| <p class="muted">Key: the CSS variable tokens section, the layout primitives responsive breakpoints (860px, 620px), and the component styles for diff, timeline, flow-step, metric-row.</p> | |
| </article> | |
| </div> | |
| </section> | |
| <section class="section stack" data-gap="lg"> | |
| <div class="section-head"> | |
| <span class="eyebrow">Gotchas</span> | |
| <h2>Things that will surprise you</h2> | |
| </div> | |
| <div class="grid" data-cols="2"> | |
| <article class="card stack" data-variant="outlined" data-tone="warning"> | |
| <h3>HTMLParser is not a DOM</h3> | |
| <p>Every parser subclass implements its own depth-tracking stack. There is no shared tree, no CSS cascade, and no computed style. The <code>handle_starttag</code> / <code>handle_endtag</code> / <code>handle_data</code> callbacks are streaming callbacks — you must track nesting state manually. This is why every parser has its own <code>self.depth</code>, <code>self.in_*</code> flag, and <code>self.*_stack</code>.</p> | |
| </article> | |
| <article class="card stack" data-variant="outlined" data-tone="warning"> | |
| <h3>Chrome needs the real file path</h3> | |
| <p>The checker opens the HTML via <code>file://</code> URI pointing at the actual repo path so that relative <code>styles/birch-system.css</code> links resolve. The geometry audit injects a <code><base href="..."></code> element into a temp copy to preserve these relative links. If you move the repo or rename directories, screenshots will capture unstyled HTML.</p> | |
| </article> | |
| <article class="card stack" data-variant="outlined" data-tone="warning"> | |
| <h3>Diff polarity requires both the mark and the class</h3> | |
| <p>A <code>+</code> in <code>.mark</code> is visible but does not trigger green row styling. <code>DiffPolarityParser</code> checks that rows with <code>+</code> or <code>-</code> in the mark column also have <code>.add</code> / <code>.del</code> class or <code>data-kind="add/del"</code>. The checker fails rows that rely on mark text alone.</p> | |
| </article> | |
| <article class="card stack" data-variant="outlined" data-tone="warning"> | |
| <h3>SVG <code>polyline</code> defaults to black fill</h3> | |
| <p>Browsers fill un-styled <code><polyline></code> and <code><path></code> elements with black. <code>svg_visual_findings()</code> scans for chart-line elements that lack <code>fill="none"</code> or an explicit stroke attribute. This is a common LLM generation failure that produces large black wedges instead of line charts.</p> | |
| </article> | |
| <article class="card stack" data-variant="outlined" data-tone="warning"> | |
| <h3>Metric alignment is measured in the browser</h3> | |
| <p>The <code>geometry_audit()</code> JS measures the left offset of every <code>.meter</code> within a <code>.metric-list</code>. A spread >2 px across meters in the same list produces a warning. This cannot be detected statically because it depends on the rendered width of label text.</p> | |
| </article> | |
| <article class="card stack" data-variant="outlined" data-tone="warning"> | |
| <h3>Code wrap detection uses tree-walker rects</h3> | |
| <p>The geometry audit's <code>rectStatsForText()</code> walks text nodes with <code>document.createTreeWalker</code> and groups <code>getClientRects()</code> into visual lines. It compares visual line count to logical (newline-split) line count. If a code block that should wrap produces 3× more visual lines than logical lines with <18 chars per line, it is flagged as underfilled.</p> | |
| </article> | |
| </div> | |
| </section> | |
| <section class="section" data-gap="xl"> | |
| <div class="section-rail"> | |
| <div class="section-head"> | |
| <span class="eyebrow">Extension points</span> | |
| <h2>Where to add or change behavior</h2> | |
| </div> | |
| <div class="stack" data-gap="md"> | |
| <article class="card stack" data-variant="outlined"> | |
| <h3>Add a new static contract check</h3> | |
| <p>Find the relevant class in <code>BIRCH_CLASSES</code>, <code>LAYOUT_CLASSES</code>, or <code>SEMANTIC_CLASSES</code> in <code>check_birch_renderings.py</code> (lines ~60–100) and add it if missing. Then add a new <code>check(...)</code> call inside <code>contract_findings()</code> (line ~400). If the check requires custom HTML parsing, write a new <code>HTMLParser</code> subclass (~40–80 lines) following the pattern of <code>MetricRowParser</code> or <code>FlowStepParser</code>:</p> | |
| <ul class="plain-list"> | |
| <li>Track entry/exit with a boolean flag and a depth counter.</li> | |
| <li>Collect direct children (depth=1 elements).</li> | |
| <li>Validate the child contract in <code>handle_endtag</code> when depth returns to 0.</li> | |
| <li>Append to a <code>self.bad_*</code> list with a preview snippet.</li> | |
| </ul> | |
| <p>Wire the new parser into <code>contract_findings()</code> and emit a <code>Finding</code> when the bad-items list is non-empty.</p> | |
| </article> | |
| <article class="card stack" data-variant="outlined"> | |
| <h3>Add a new geometry audit probe</h3> | |
| <p>Inside the <code>audit_js</code> string in <code>geometry_audit()</code>, add a new <code>querySelectorAll</code> loop that measures element positions, sizes, or overflow. Serialize results into the <code>data-birch-audit</code> JSON object. Then add a corresponding block in <code>geometry_findings()</code> that reads the key from the parsed JSON and emits <code>Finding</code> objects. The pattern is: <code>if problems: emit fail; elif key exists: emit pass; else: skip (pre-audit-checker baseline)</code>.</p> | |
| </article> | |
| <article class="card stack" data-variant="outlined"> | |
| <h3>Add a new supported viewport</h3> | |
| <p>Add an entry to the <code>VIEWPORTS</code> dict in <code>evals/charts/run_eval.py</code> (or your own eval runner). The format is <code>"name": "label:WxH"</code>. The checker's <code>parse_viewport()</code> splits on <code>:</code> and <code>x</code>. For "deep" viewports (name contains "deep"), the checker measures document height before capturing; for standard viewports it uses the exact height.</p> | |
| </article> | |
| <article class="card stack" data-variant="outlined"> | |
| <h3>Change palette/token validation</h3> | |
| <p>The canonical palette lives in <code>PALETTE</code> (line ~100 of <code>check_birch_renderings.py</code>) and is duplicated in <code>COLORS</code> in <code>birch_mpl.py</code>. Update both if you change the Birch palette. The <code>is_palette_hex()</code> function uses a tolerance of 3 per channel. <code>palette_metrics()</code> uses tolerance 34 for the "palette-close" fraction. Adjust these tolerances in the checker only; the CSS token values in <code>birch-system.css</code> are the source of truth.</p> | |
| </article> | |
| <article class="card stack" data-variant="outlined"> | |
| <h3>Change the Birch CSS contract signature</h3> | |
| <p>The five strings in <code>BIRCH_CSS_SIGNATURES</code> (line ~40) are what the checker scans for to validate the embedded Birch CSS block. If you add or rename a critical CSS variable or class, update this tuple. The <code>BIRCH_CSS_MIN_BYTES</code> threshold (10,000) is also defined there. These signatures are matched against the raw CSS text, not parsed selectors.</p> | |
| </article> | |
| </div> | |
| <aside class="reference-panel stack" data-gap="md"> | |
| <h3>Key constants</h3> | |
| <div class="stack" data-gap="sm"> | |
| <div class="stat-card"> | |
| <span class="caption">BIRCH_CSS_MIN_BYTES</span> | |
| <strong class="stat-value" style="font-size:24px">10,000</strong> | |
| <p class="muted">Minimum embedded Birch CSS block size. Defined at line ~40 of the checker.</p> | |
| </div> | |
| <div class="stat-card"> | |
| <span class="caption">SEMANTIC_CLASS_MIN</span> | |
| <strong class="stat-value" style="font-size:24px">6</strong> | |
| <p class="muted">Minimum distinct semantic component classes. Below this, the artifact likely uses page-specific CSS.</p> | |
| </div> | |
| <div class="stat-card"> | |
| <span class="caption">LAYOUT_CLASS_MIN</span> | |
| <strong class="stat-value" style="font-size:24px">8</strong> | |
| <p class="muted">Minimum layout primitive uses. Below this, the layout may be brittle.</p> | |
| </div> | |
| <div class="stat-card"> | |
| <span class="caption">PALETTE_TOLERANCE</span> | |
| <strong class="stat-value" style="font-size:24px">3/ch</strong> | |
| <p class="muted">Per-channel RGB tolerance for <code>is_palette_hex()</code>. Palette-metrics tolerance is 34.</p> | |
| </div> | |
| </div> | |
| <h3>Report paths</h3> | |
| <div class="stack" data-gap="xs"> | |
| <pre class="code-block" data-kind="command">reports/birch-rendering-check.json</pre> | |
| <pre class="code-block" data-kind="command">reports/birch-rendering-check.md</pre> | |
| <pre class="code-block" data-kind="command">reports/birch-screenshots/*.png</pre> | |
| </div> | |
| <h3>Key commands</h3> | |
| <div class="stack" data-gap="xs"> | |
| <pre class="code-block" data-kind="command">uv run --with pillow python scripts/check_birch_renderings.py --artifact 24-birch-chart-brief.html --viewport desktop:1365x900</pre> | |
| <pre class="code-block" data-kind="command">uv run --with pillow python scripts/check_birch_renderings.py --artifact 24-birch-chart-brief.html --viewport mobile:390x900 --fail-on-warn</pre> | |
| <pre class="code-block" data-kind="command">uv run python evals/charts/run_eval.py</pre> | |
| </div> | |
| <h3>Finding levels</h3> | |
| <ul class="plain-list"> | |
| <li><strong>fail</strong> — hard contract violation; blocks adoption</li> | |
| <li><strong>warn</strong> — likely problem, non-blocking unless <code>--fail-on-warn</code></li> | |
| <li><strong>note</strong> — informational delta or diagnostic</li> | |
| <li><strong>pass</strong> — check passed (emitted only for geometry/audit checks)</li> | |
| </ul> | |
| </aside> | |
| </div> | |
| </section> | |
| <section class="section stack" data-gap="md"> | |
| <div class="card stack" data-variant="flat"> | |
| <h2>Source and caveat</h2> | |
| <p>All claims are grounded in the six files listed in <code>evals/module-explainer/source-files.txt</code>, inspected at the time of writing. The checker is a living tool; function line numbers may drift. The geometry audit JS is the most complex and fragile part — it probes live browser layout and depends on the Birch CSS being loaded correctly. If Chrome or the Birch CSS changes, audit probes may need adjustment. The <code>--pair</code> mode is maintained for backward compatibility but <code>--artifact</code> mode is preferred for generated eval outputs.</p> | |
| </div> | |
| </section> | |
| </main> | |
| </body> | |
| </html> | |
Xet Storage Details
- Size:
- 61.4 kB
- Xet hash:
- fd5691872cbe8b1a95e206d4e92f21e665e43a50dbd8ed7fe9cdef3356917b9b
·
Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.