@lumencast/runtime 0.11.0 → 0.12.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +39 -0
- package/dist/.tsbuildinfo +1 -1
- package/dist/{broadcast-DtHoU_fS.js → broadcast-Dg77Br5j.js} +3 -3
- package/dist/{broadcast-DtHoU_fS.js.map → broadcast-Dg77Br5j.js.map} +1 -1
- package/dist/{control-B9frEbNG.js → control-iPqpFp80.js} +4 -4
- package/dist/{control-B9frEbNG.js.map → control-iPqpFp80.js.map} +1 -1
- package/dist/{index-Dz27r92m.js → index-C4r-fG1q.js} +361 -326
- package/dist/index-C4r-fG1q.js.map +1 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.html +1 -1
- package/dist/index.js.map +1 -1
- package/dist/lumencast.js +1 -1
- package/dist/mount.d.ts.map +1 -1
- package/dist/mount.js +52 -0
- package/dist/mount.js.map +1 -1
- package/dist/render/primitives/capture-stream-cache.d.ts +26 -0
- package/dist/render/primitives/capture-stream-cache.d.ts.map +1 -0
- package/dist/render/primitives/capture-stream-cache.js +141 -0
- package/dist/render/primitives/capture-stream-cache.js.map +1 -0
- package/dist/render/primitives/capture.d.ts +1 -1
- package/dist/render/primitives/capture.d.ts.map +1 -1
- package/dist/render/primitives/capture.js +20 -87
- package/dist/render/primitives/capture.js.map +1 -1
- package/dist/{status-pill-B2vBTwRC.js → status-pill-nls_2xkN.js} +2 -2
- package/dist/{status-pill-B2vBTwRC.js.map → status-pill-nls_2xkN.js.map} +1 -1
- package/dist/{test-DD2SBDku.js → test-d8HW2LcF.js} +4 -4
- package/dist/{test-DD2SBDku.js.map → test-d8HW2LcF.js.map} +1 -1
- package/dist/transport/ws.d.ts +4 -1
- package/dist/transport/ws.d.ts.map +1 -1
- package/dist/transport/ws.js +7 -0
- package/dist/transport/ws.js.map +1 -1
- package/dist/{tree-CgU_sUwI.js → tree-BME9ba3m.js} +589 -567
- package/dist/tree-BME9ba3m.js.map +1 -0
- package/dist/types.d.ts +18 -2
- package/dist/types.d.ts.map +1 -1
- package/dist/webrtc/index.d.ts +1 -1
- package/dist/webrtc/index.d.ts.map +1 -1
- package/dist/webrtc/index.js.map +1 -1
- package/dist/webrtc/peer-stream-registry.d.ts +17 -0
- package/dist/webrtc/peer-stream-registry.d.ts.map +1 -1
- package/dist/webrtc/peer-stream-registry.js +22 -0
- package/dist/webrtc/peer-stream-registry.js.map +1 -1
- package/package.json +4 -4
- package/src/index.ts +1 -0
- package/src/mount.ts +54 -0
- package/src/render/primitives/capture-stream-cache.ts +164 -0
- package/src/render/primitives/capture.tsx +19 -93
- package/src/transport/ws.ts +11 -0
- package/src/types.ts +18 -2
- package/src/webrtc/index.ts +1 -0
- package/src/webrtc/peer-stream-registry.ts +38 -0
- package/dist/index-Dz27r92m.js.map +0 -1
- package/dist/tree-CgU_sUwI.js.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tree-BME9ba3m.js","sources":["../src/render/primitives/stack.tsx","../src/render/primitives/grid.tsx","../src/render/css-color.ts","../src/render/allowed-hosts.tsx","../src/render/blend-mode.ts","../src/render/fill.tsx","../src/render/primitives/frame.tsx","../src/render/primitives/text.tsx","../src/render/primitives/image.tsx","../src/render/svg-path.ts","../src/render/shape-geometry.tsx","../src/render/primitives/shape.tsx","../src/render/primitives/live-peer-video.tsx","../src/render/primitives/media.tsx","../src/render/primitives/meet-peer.tsx","../src/render/primitives/meet-peer-slot.tsx","../src/render/primitives/instance.tsx","../src/render/primitives/capture-stream-cache.ts","../src/render/primitives/capture.tsx","../src/render/primitives/index.ts","../src/render/scope.tsx","../src/render/universal-wrapper.tsx","../src/animate/keyframes.ts","../src/render/stagger-context.tsx","../src/render/keyframe-player.tsx","../src/animate/frame-coalescer.ts","../src/render/color-interp.ts","../src/render/bind-animate.tsx","../src/render/mask.tsx","../src/render/shape-index.tsx","../src/render/tree.tsx"],"sourcesContent":["import type { CSSProperties } from \"react\";\nimport type { PrimitiveProps } from \"./index\";\n\n/** Vertical or horizontal flex container. Layout-only — bindings\n * here are unusual but tolerated.\n *\n * LSML 1.1 §4.1 adds `wrap` (boolean) and `crossGap` (number) :\n * - wrap: true sets `flex-wrap: wrap` so children flow onto the\n * next row / column when they overflow the main axis.\n * - crossGap is the spacing between rows / columns when wrapping.\n * Mapped to CSS `row-gap` (horizontal stack) or `column-gap`\n * (vertical stack). Ignored when `wrap` is false.\n */\nexport function Stack({ resolved, children, establishesContainingBlock }: PrimitiveProps) {\n const direction = (resolved.direction as string) ?? \"vertical\";\n const gap = numberOr(resolved.gap, 0);\n const wrap = resolved.wrap === true;\n const crossGap = numberOr(resolved.crossGap, 0);\n const align = (resolved.align as string) ?? \"stretch\";\n const justify = (resolved.justify as string) ?? \"flex-start\";\n const isHorizontal = direction === \"horizontal\";\n\n const style: CSSProperties = {\n display: \"flex\",\n flexDirection: isHorizontal ? \"row\" : \"column\",\n alignItems: align,\n justifyContent: justify,\n // ADR 002 §3.1 (D1) — establish a containing block when a child is\n // absolutely placed, so its `left/top` resolve against this stack.\n // Untouched for pure auto-layout stacks (RC#2).\n ...(establishesContainingBlock ? { position: \"relative\" } : {}),\n };\n\n if (wrap) {\n style.flexWrap = \"wrap\";\n if (isHorizontal) {\n style.columnGap = gap;\n style.rowGap = crossGap;\n } else {\n style.rowGap = gap;\n style.columnGap = crossGap;\n }\n } else {\n style.gap = gap;\n }\n\n return <div style={style}>{children}</div>;\n}\n\nfunction numberOr(v: unknown, fallback: number): number {\n return typeof v === \"number\" && Number.isFinite(v) ? v : fallback;\n}\n","import type { PrimitiveProps } from \"./index\";\n\n/** CSS Grid container with declared rows / cols. */\nexport function Grid({ resolved, children, establishesContainingBlock }: PrimitiveProps) {\n const cols = (resolved.cols as string) ?? \"1fr\";\n const rows = (resolved.rows as string) ?? \"auto\";\n const gap = (resolved.gap as number | string | undefined) ?? 0;\n return (\n <div\n style={{\n display: \"grid\",\n gridTemplateColumns: cols,\n gridTemplateRows: rows,\n gap,\n // ADR 002 §3.1 (D1) — establish a containing block for absolutely\n // placed children ; untouched for pure auto-layout grids (RC#2).\n ...(establishesContainingBlock ? { position: \"relative\" } : {}),\n }}\n >\n {children}\n </div>\n );\n}\n","// Strict CSS colour parser — the ONLY gate through which untrusted\n// colour values (bundle props AND live LSDP deltas, see `resolveProps`\n// in tree.tsx) may reach an inline CSS style.\n//\n// ADR 001 §6 RC#11 (CSS strict) + RC#12 (anti-ReDoS), threat model\n// Bastion 2026-06-10, issue #35. Sites #30/#31/#33 must reuse this\n// module — never re-implement colour validation locally.\n//\n// Accepted grammar (LSML 1.1 §6.5 colour forms, nothing more) :\n// - hex : #RGB | #RGBA | #RRGGBB | #RRGGBBAA\n// - rgb() : rgb(R, G, B) | rgba(R, G, B, A) — 0-255 or percentages\n// - hsl() : hsl(H, S%, L%) | hsla(H, S%, L%, A)\n// - named : canonical CSS named colours + `transparent` + `currentcolor`\n// Anything else — including `url(`, `;`, `}`, `expression(`, var(),\n// calc(), whitespace tricks — is REJECTED (null). Never passthrough.\n//\n// ── Linear-time justification (RC#12, written per Bastion) ──────────\n// 1. Inputs longer than MAX_LEN (64) are rejected before any regex\n// runs, so every step below operates on a bounded string.\n// 2. The charset pre-scan is a single O(n) pass over one character\n// class — it rejects `;`, `}`, `:`, `/`, quotes, backslashes and\n// control characters outright, so no later step ever sees them.\n// 3. Every regex is anchored (`^…$`) and built exclusively from\n// literals, character classes and BOUNDED quantifiers ({m,n}, ?).\n// There are no nested unbounded quantifiers ((a+)+ style), no\n// overlapping alternations under a quantifier — i.e. no input can\n// trigger super-linear backtracking. Combined with the 64-char cap,\n// total work is O(64) per value regardless of payload shape.\n// ─────────────────────────────────────────────────────────────────────\n\nimport { emitDiagnostic } from \"./diagnostics\";\n\nconst MAX_LEN = 64;\n\n// Single-pass charset allowlist. Only characters that can appear in\n// the accepted grammar. Notably ABSENT : `;` `}` `{` `:` `/` `\"` `'`\n// `\\` `<` `>` `-` and all control chars — the injection metacharacters.\nconst CHARSET_RE = /^[#a-zA-Z0-9(),.% ]{1,64}$/;\n\n// hex — 3/4/6/8 hex digits. Alternation of fixed-width character-class\n// runs : strictly linear.\nconst HEX_RE = /^#(?:[0-9a-fA-F]{3,4}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$/;\n\n// Number tokens. All quantifiers bounded ; `(?:\\.\\d{1,4})?` is an\n// optional bounded group — one possible match per position, no\n// ambiguity, no backtracking blow-up.\nconst NUM = String.raw`\\d{1,3}(?:\\.\\d{1,4})?`; // 0 … 999.9999\nconst ALPHA = String.raw`(?:0|1|0?\\.\\d{1,4}|${NUM}%)`; // 0-1 or %\nconst SP = String.raw`[ ]{0,4}`; // bounded optional spaces\n\n// rgb(R, G, B[, A]) — channels all plain numbers or all percentages\n// are both accepted (range-checked numerically after the match).\nconst RGB_RE = new RegExp(\n `^rgba?\\\\(${SP}(${NUM})(%?)${SP},${SP}(${NUM})(%?)${SP},${SP}(${NUM})(%?)${SP}` +\n `(?:,${SP}${ALPHA}${SP})?\\\\)$`,\n);\n\n// hsl(H[deg], S%, L%[, A])\nconst HSL_RE = new RegExp(\n `^hsla?\\\\(${SP}(${NUM})(?:deg)?${SP},${SP}(${NUM})%${SP},${SP}(${NUM})%${SP}` +\n `(?:,${SP}${ALPHA}${SP})?\\\\)$`,\n);\n\n// Canonical CSS named colours (CSS Color 4 §6.1) + the two keywords\n// that behave like colours in every site we render.\nconst NAMED = new Set(\n (\n \"aliceblue antiquewhite aqua aquamarine azure beige bisque black blanchedalmond blue \" +\n \"blueviolet brown burlywood cadetblue chartreuse chocolate coral cornflowerblue cornsilk \" +\n \"crimson cyan darkblue darkcyan darkgoldenrod darkgray darkgreen darkgrey darkkhaki \" +\n \"darkmagenta darkolivegreen darkorange darkorchid darkred darksalmon darkseagreen \" +\n \"darkslateblue darkslategray darkslategrey darkturquoise darkviolet deeppink deepskyblue \" +\n \"dimgray dimgrey dodgerblue firebrick floralwhite forestgreen fuchsia gainsboro ghostwhite \" +\n \"gold goldenrod gray green greenyellow grey honeydew hotpink indianred indigo ivory khaki \" +\n \"lavender lavenderblush lawngreen lemonchiffon lightblue lightcoral lightcyan \" +\n \"lightgoldenrodyellow lightgray lightgreen lightgrey lightpink lightsalmon lightseagreen \" +\n \"lightskyblue lightslategray lightslategrey lightsteelblue lightyellow lime limegreen \" +\n \"linen magenta maroon mediumaquamarine mediumblue mediumorchid mediumpurple \" +\n \"mediumseagreen mediumslateblue mediumspringgreen mediumturquoise mediumvioletred \" +\n \"midnightblue mintcream mistyrose moccasin navajowhite navy oldlace olive olivedrab \" +\n \"orange orangered orchid palegoldenrod palegreen paleturquoise palevioletred papayawhip \" +\n \"peachpuff peru pink plum powderblue purple rebeccapurple red rosybrown royalblue \" +\n \"saddlebrown salmon sandybrown seagreen seashell sienna silver skyblue slateblue \" +\n \"slategray slategrey snow springgreen steelblue tan teal thistle tomato turquoise violet \" +\n \"wheat white whitesmoke yellow yellowgreen transparent currentcolor\"\n ).split(\" \"),\n);\n\n/**\n * Validate an untrusted colour value against the strict grammar above.\n *\n * Returns the validated string (trimmed ; named colours lowercased) or\n * `null` on rejection. A `null` MUST be handled as \"omit the style /\n * use the primitive's safe default\" — never interpolate the raw input.\n */\nexport function parseCssColor(value: unknown): string | null {\n if (typeof value !== \"string\") return null;\n const v = value.trim();\n if (v.length === 0 || v.length > MAX_LEN) return null;\n // Contractual explicit rejects (Bastion RC#11) — redundant with the\n // charset scan below, kept as belt-and-braces so the contract holds\n // even if the grammar is ever extended.\n const lower = v.toLowerCase();\n if (lower.includes(\"url(\") || v.includes(\";\") || v.includes(\"}\")) return null;\n // Single-pass charset allowlist (kills every CSS metacharacter).\n if (!CHARSET_RE.test(v)) return null;\n\n if (v.startsWith(\"#\")) return HEX_RE.test(v) ? v : null;\n\n if (lower.startsWith(\"rgb\")) {\n const m = RGB_RE.exec(lower);\n if (!m) return null;\n // Range check : percent channels ≤ 100, plain channels ≤ 255, no mixing.\n const pct = [m[2], m[4], m[6]];\n if (!(pct.every((p) => p === \"%\") || pct.every((p) => p === \"\"))) return null;\n const max = pct[0] === \"%\" ? 100 : 255;\n for (const ch of [m[1], m[3], m[5]]) {\n if (Number(ch) > max) return null;\n }\n return lower;\n }\n\n if (lower.startsWith(\"hsl\")) {\n const m = HSL_RE.exec(lower);\n if (!m) return null;\n if (Number(m[1]) > 360 || Number(m[2]) > 100 || Number(m[3]) > 100) return null;\n return lower;\n }\n\n return NAMED.has(lower) ? lower : null;\n}\n\n/**\n * Diagnostic for a rejected value. Bastion R9 (ADR 001 §5.1) : the\n * rejected VALUE is never logged nor forwarded — only `node.id` (RC#7,\n * issue #34), the field name and a static reason. Routed through the\n * structured diagnostics channel (events, no logs in `broadcast`).\n */\nexport function warnRejectedColor(field: string, nodeId?: string): void {\n emitDiagnostic(\n nodeId,\n field,\n \"rejected unsafe colour : not a strict hex/rgb()/hsl()/named colour\",\n );\n}\n","// Render-side host-allowlist context (LSML 1.2, ADR 002 #E + #F ; Bastion T1/T2).\n//\n// CANONICAL host-gate module for the runtime. There is exactly ONE\n// `AllowedHostsProvider` and ONE allowlist context for the whole render\n// tree. The bundle's `assets.allowedHosts` rides this context from the\n// render root down to every consumer that places an untrusted asset URL\n// into the DOM :\n//\n// - image-fill `src` on frame / shape backgrounds (#F, via `gateImageFills`\n// / `gateSrc` in `fill.tsx`),\n// - the `<img src>` of the `image` primitive (#F — closes the latent 1.1\n// hole where `image.tsx` placed `src` with no host check at all),\n// - a `mask.source`-image `href` (#E, via `checkHostAllowed` in\n// `mask.tsx`, which reads the allowlist off this same context through\n// `tree.tsx`).\n//\n// The underlying decision is ALWAYS delegated to `@lumencast/protocol`'s\n// `checkHostAllowed` / `isHostAllowed` (the #C foundation, single source of\n// truth for host + scheme matching). This module never re-implements that\n// logic ; it only threads the allowlist and adapts it for each call-site.\n//\n// Deny-by-default : a consumer rendered outside any provider, or one whose\n// bundle declares no `allowedHosts`, sees `undefined` — which\n// `checkHostAllowed` treats as \"no allowlist → reject every remote host\".\n// There is no path by which a missing provider silently re-opens the gate.\n//\n// The context value is a read-only, mount-stable `string[] | undefined`\n// (the allowlist is part of the content-addressed bundle), so a plain React\n// context is the right tool.\n\nimport { createContext, useContext, type ReactNode } from \"react\";\nimport { checkHostAllowed } from \"@lumencast/protocol\";\nimport { emitDiagnostic } from \"./diagnostics\";\n\nconst AllowedHostsCtx = createContext<readonly string[] | undefined>(undefined);\n\n/**\n * Provide the bundle's host allowlist to the render subtree. Mounted ONCE at\n * the render root by each mode (broadcast / control / test), wrapping\n * `<Tree>`. The value should come from {@link readAllowedHosts} so the\n * legacy `Asset[]` and the LSML 1.2 object `assets` shapes are both handled\n * and non-string entries are dropped.\n *\n * Prop name is `hosts` (the canonical render-side spelling, #F).\n */\nexport function AllowedHostsProvider({\n hosts,\n children,\n}: {\n hosts: readonly string[] | undefined;\n children: ReactNode;\n}) {\n return <AllowedHostsCtx.Provider value={hosts}>{children}</AllowedHostsCtx.Provider>;\n}\n\n/** Read the active host allowlist. `undefined` when no provider is mounted —\n * which `checkHostAllowed` treats as deny-by-default (never a passthrough). */\nexport function useAllowedHosts(): readonly string[] | undefined {\n return useContext(AllowedHostsCtx);\n}\n\n/** Read `assets.allowedHosts` defensively off a render bundle, for the mode\n * that provides the context. The LSML 1.2 compiler forwards `assets` in the\n * object form `{ allowedHosts?: string[] }` (see `RenderBundle.assets`) ;\n * a legacy bundle may still carry the old `Asset[]` form. Either way we\n * extract a `string[]` of hostnames, or `undefined` (deny-by-default). A\n * non-string entry is dropped — it can never match `new URL().hostname`. */\nexport function readAllowedHosts(bundle: { assets?: unknown }): readonly string[] | undefined {\n const assets = bundle.assets as { allowedHosts?: unknown } | undefined;\n const list = assets?.allowedHosts;\n if (!Array.isArray(list)) return undefined;\n const hosts = list.filter((h): h is string => typeof h === \"string\");\n return hosts.length > 0 ? hosts : undefined;\n}\n\n/**\n * Gate an asset `src` against the host + scheme allowlist BEFORE it reaches\n * the DOM (Bastion T1/T2). Returns the `src` unchanged when allowed, or\n * `undefined` when rejected — in which case the caller MUST omit the asset\n * (never passthrough). On rejection an R9-clean diagnostic is emitted : it\n * carries only `{ nodeId, field, reason }`, never the URL itself.\n *\n * The decision is delegated to `checkHostAllowed` and is deny-by-default :\n * an absent / empty `allowedHosts` rejects every remote host.\n * `undefined`/non-string/empty `src` resolves to `undefined` (absent asset)\n * WITHOUT a diagnostic — that is a primitive with no source, not a rejected\n * one.\n */\nexport function gateSrc(\n src: unknown,\n allowedHosts: readonly string[] | undefined,\n field: string,\n nodeId?: string,\n): string | undefined {\n if (typeof src !== \"string\" || src.length === 0) return undefined;\n const decision = checkHostAllowed(src, allowedHosts);\n if (decision.allowed) return src;\n emitDiagnostic(nodeId, field, decision.reason ?? \"asset host/scheme rejected\");\n return undefined;\n}\n","// Strict `mix-blend-mode` gate — the runtime half of the T4 double-gate\n// (Bastion conditions 1.2, ADR 002 §3.2 / #D).\n//\n// The compiler already validates `blendMode` against its closed enum\n// (`parseBlendMode`, @lumencast/compiler) before emitting the universal\n// prop. This module is the INDEPENDENT runtime gate : a bundle prop OR a\n// live LSDP delta value reaching the wrapper is re-validated here against\n// the same closed allowlist before it may touch an inline CSS style.\n// Anything outside the enum is omitted (never passthrough) — mirroring\n// the `css-color.ts` discipline (self-contained second gate, no untrusted\n// string ever interpolated into CSS).\n//\n// The allowlist is intentionally duplicated rather than imported from the\n// compiler : the runtime does not depend on @lumencast/compiler, and the\n// gate must hold even if a hand-rolled / tampered bundle bypasses the\n// compiler entirely. It is a fixed, finite set of CSS keywords (Figma\n// blend modes minus PASS_THROUGH) — the single source of truth for the\n// CSS value is this closed set.\n\n/** Closed `mix-blend-mode` allowlist (ADR 002 §3.2 — Figma minus\n * `PASS_THROUGH`). Mirrors the compiler's `BLEND_MODES`. */\nconst BLEND_MODES: ReadonlySet<string> = new Set([\n \"normal\",\n \"multiply\",\n \"screen\",\n \"overlay\",\n \"darken\",\n \"lighten\",\n \"color-dodge\",\n \"color-burn\",\n \"hard-light\",\n \"soft-light\",\n \"difference\",\n \"exclusion\",\n \"hue\",\n \"saturation\",\n \"color\",\n \"luminosity\",\n // Figma LINEAR_DODGE (add) — exact additive blend, gentler than color-dodge.\n \"plus-lighter\",\n]);\n\n/**\n * Re-validate a resolved `blendMode` against the closed enum. Returns the\n * CSS `mix-blend-mode` keyword when recognised, else `undefined` (caller\n * omits — the value never reaches the style). Never passthrough.\n */\nexport function parseBlendMode(value: unknown): string | undefined {\n return typeof value === \"string\" && BLEND_MODES.has(value) ? value : undefined;\n}\n","// Fill rendering helpers (LSML 1.1 §4.12).\n//\n// A Fill is a discriminated union :\n// - solid : { kind: \"solid\", color, opacity? }\n// - linear-gradient : { kind: \"linear-gradient\", angle_deg?, stops, opacity? }\n// - radial-gradient : { kind: \"radial-gradient\", center?, radius?, stops, opacity? }\n//\n// shape.fills[] and frame.backgrounds[] both use this shape. Each fill\n// renders as a separate SVG element layered top-to-bottom (first entry\n// renders on top per §4.12).\n\nimport type { CSSProperties, ReactElement } from \"react\";\nimport { parseCssColor, warnRejectedColor } from \"./css-color\";\nimport { emitDiagnostic } from \"./diagnostics\";\nimport { gateSrc } from \"./allowed-hosts\";\nimport { parseBlendMode } from \"./blend-mode\";\n\nexport interface FillStop {\n offset: number;\n color: string;\n opacity?: number;\n}\n\n/** LSML 1.2 §3.2 closed `objectFit` enum, re-validated at the RUNTIME (the\n * compiler is the other arm of the double-gate, Bastion T4). These are\n * exactly the legal CSS `object-fit` / `background-size`-mappable values ;\n * anything else is omitted + diagnosed, never passed through to inline CSS.\n * Kept local to the runtime — the runtime must not import from the\n * compiler (the dependency edge points the other way). */\nconst OBJECT_FITS = new Set([\"cover\", \"contain\", \"fill\", \"none\", \"scale-down\"]);\n\nexport type ObjectFit = \"cover\" | \"contain\" | \"fill\" | \"none\" | \"scale-down\";\n\n/** Validate an `objectFit` against the closed enum at render. Returns the\n * value or `undefined` (caller falls back to the default + diagnoses).\n * Never passthrough. */\nexport function parseObjectFitRuntime(value: unknown): ObjectFit | undefined {\n return typeof value === \"string\" && OBJECT_FITS.has(value) ? (value as ObjectFit) : undefined;\n}\n\n// LSML 1.2 §3.2 (#L) — optional per-fill-layer blend mode. Re-validated at\n// the RUNTIME against the closed enum (`parseBlendMode` from blend-mode.ts,\n// the runtime arm of the T4 double-gate ; the runtime never imports the\n// compiler). Out-of-enum → omitted, never reaches inline CSS. Independent of\n// the node-level blend (#D, applied on the wrapper). Absent = `normal`.\nexport type Fill =\n | { kind: \"solid\"; color: string; opacity?: number; blendMode?: string }\n | {\n kind: \"linear-gradient\";\n angle_deg?: number;\n stops: FillStop[];\n opacity?: number;\n blendMode?: string;\n }\n | {\n kind: \"radial-gradient\";\n center?: { x: number; y: number };\n radius?: number;\n stops: FillStop[];\n opacity?: number;\n blendMode?: string;\n }\n | {\n // LSML 1.2 §3.2 — first-class image-fill. `src` is untrusted and is\n // host/scheme-gated by `gateImageFills` BEFORE this fill is ever\n // rendered (Bastion T1/T2). `objectFit` is the runtime-revalidated\n // closed-enum value (T4).\n kind: \"image\";\n src: string;\n objectFit?: ObjectFit;\n opacity?: number;\n blendMode?: string;\n };\n\nlet gradientIdSeq = 0;\nfunction nextGradientId(): string {\n gradientIdSeq = (gradientIdSeq + 1) % 1_000_000;\n return `lumen-grad-${gradientIdSeq.toString(36)}`;\n}\n\nexport interface FillRenderResult {\n /** SVG <defs> contributions (gradient definitions). */\n defs: ReactElement[];\n /** Reference to use as the `fill` attribute on the shape. */\n ref: string;\n /** #L — the per-fill-layer `mix-blend-mode` keyword, re-validated against\n * the closed enum at the runtime (T4) ; `undefined` when absent or\n * out-of-enum (caller omits — never reaches the style). Applied on the\n * fill layer element, independent of the node-level blend (#D). */\n mixBlendMode?: string;\n}\n\n/** Compile a Fill into an SVG `<defs>` entry + a `fill=\"url(#…)\"` ref.\n * Solid fills produce no defs and return the colour directly. */\nexport function renderFill(fill: Fill): FillRenderResult {\n // #L — re-validate the per-fill blend mode once (runtime T4 arm). An absent\n // or out-of-enum value yields `undefined` → the layer renders `normal`.\n const mixBlendMode = parseBlendMode(fill.blendMode);\n if (fill.kind === \"solid\") {\n // Solid fill — no defs needed, just hand the colour to fill. A solid fill\n // carries its OWN opacity (Figma per-paint alpha, e.g. the bg-texture tiles\n // at 6% white) ; fold it into the colour so the SVG path actually renders\n // at that alpha instead of full-strength (the tiles came out 16× too bright\n // pre-mask, near-black post-mask).\n const ref = fill.opacity !== undefined ? cssWithOpacity(fill.color, fill.opacity) : fill.color;\n return { defs: [], ref, mixBlendMode };\n }\n if (fill.kind === \"image\") {\n // LSML 1.2 §3.2 — image-fill on a shape. Rendered as an SVG <pattern>\n // holding a single <image> that fills the object bounding box ;\n // `preserveAspectRatio` reproduces the closed-enum `objectFit`. `src`\n // is pre-gated (T1/T2) by `gateImageFills`, so it is safe to place on\n // the SVG <image href>. No bundle-derived markup is interpolated — only\n // the URL string and closed-enum-derived attribute values.\n const imgId = nextGradientId();\n const par = objectFitToPreserveAspectRatio(fill.objectFit);\n const defs = [\n <pattern key={imgId} id={imgId} patternContentUnits=\"objectBoundingBox\" width=\"1\" height=\"1\">\n <image href={fill.src} width=\"1\" height=\"1\" preserveAspectRatio={par} />\n </pattern>,\n ];\n return { defs, ref: `url(#${imgId})`, mixBlendMode };\n }\n const id = nextGradientId();\n if (fill.kind === \"linear-gradient\") {\n let x1: number, y1: number, x2: number, y2: number;\n // Honour the Figma `gradientTransform` : the gradient axis (offset 0 → 1) is\n // column 0 = (a, b) of the matrix, in the SVG's y-down space. `angle_deg`\n // alone ignored it and mis-oriented the picto/caramel gradients (too red).\n const t = (fill as { transform?: number[] }).transform;\n if (Array.isArray(t) && t.length === 6 && Number.isFinite(t[0]) && Number.isFinite(t[1])) {\n const len = Math.hypot(t[0], t[1]) || 1;\n const an = t[0] / len;\n const bn = t[1] / len;\n x1 = 0.5 - 0.5 * an;\n y1 = 0.5 - 0.5 * bn;\n x2 = 0.5 + 0.5 * an;\n y2 = 0.5 + 0.5 * bn;\n } else {\n // angle_deg : 0 = bottom-to-top per §4.12.\n const angle = fill.angle_deg ?? 0;\n const rad = ((angle - 90) * Math.PI) / 180; // 0° → x1=0,y1=1 (bottom-up)\n x1 = 0.5 - 0.5 * Math.cos(rad);\n y1 = 0.5 - 0.5 * Math.sin(rad);\n x2 = 0.5 + 0.5 * Math.cos(rad);\n y2 = 0.5 + 0.5 * Math.sin(rad);\n }\n const defs = [\n <linearGradient\n key={id}\n id={id}\n x1={`${x1 * 100}%`}\n y1={`${y1 * 100}%`}\n x2={`${x2 * 100}%`}\n y2={`${y2 * 100}%`}\n >\n {fill.stops.map((s, i) => (\n <stop\n key={i}\n offset={s.offset}\n stopColor={s.color}\n {...(s.opacity !== undefined ? { stopOpacity: s.opacity } : {})}\n />\n ))}\n </linearGradient>,\n ];\n return { defs, ref: `url(#${id})`, mixBlendMode };\n }\n // radial-gradient\n const cx = fill.center?.x ?? 0.5;\n const cy = fill.center?.y ?? 0.5;\n const r = fill.radius ?? 0.5;\n const defs = [\n <radialGradient key={id} id={id} cx={`${cx * 100}%`} cy={`${cy * 100}%`} r={`${r * 100}%`}>\n {fill.stops.map((s, i) => (\n <stop\n key={i}\n offset={s.offset}\n stopColor={s.color}\n {...(s.opacity !== undefined ? { stopOpacity: s.opacity } : {})}\n />\n ))}\n </radialGradient>,\n ];\n return { defs, ref: `url(#${id})`, mixBlendMode };\n}\n\n/** Map a closed-enum `objectFit` to the CSS `background-size` keyword that\n * reproduces the same fit for a `background-image`. `fill`/`none`/`scale-\n * down` have no exact 1:1 `background-size` keyword — we approximate with\n * the nearest safe keyword (all from the closed enum, never free input). */\nfunction objectFitToBackgroundSize(fit: ObjectFit | undefined): string {\n switch (fit) {\n case \"contain\":\n case \"scale-down\":\n return \"contain\";\n case \"none\":\n return \"auto\";\n case \"fill\":\n return \"100% 100%\";\n case \"cover\":\n default:\n return \"cover\";\n }\n}\n\n/** Map a closed-enum `objectFit` to the SVG `<image preserveAspectRatio>`\n * value that reproduces the same fit inside a pattern tile. Every returned\n * value is a fixed literal (closed enum → fixed mapping) — never free\n * input reaching an SVG attribute. */\nfunction objectFitToPreserveAspectRatio(fit: ObjectFit | undefined): string {\n switch (fit) {\n case \"contain\":\n case \"scale-down\":\n return \"xMidYMid meet\";\n case \"fill\":\n return \"none\";\n case \"none\":\n return \"xMidYMid meet\";\n case \"cover\":\n default:\n return \"xMidYMid slice\";\n }\n}\n\n/** Compile an array of Fill into background CSS usable on a `<div>` (frame\n * backgrounds — non-SVG context). Returns `backgroundImage` plus, when an\n * image-fill is present, the matching `backgroundSize`/`backgroundPosition`/\n * `backgroundRepeat`. Stops use percentages in CSS gradient syntax.\n *\n * Image-fill `src` MUST already be host/scheme-gated (`gateImageFills`) —\n * `backgroundsToCss` assumes the URL is trusted at this point and only\n * CSS-escapes it for safe interpolation into `url(\"…\")`. */\nexport function backgroundsToCss(fills: Fill[], nodeId?: string): CSSProperties {\n // Per §4.12, fills[0] renders on top — CSS background-image stacks\n // first → top-most. Match by passing in the same order.\n // #L — keep each layer's validated blend keyword aligned with its CSS\n // layer (a rejected colour drops the layer → drop its blend too), so\n // `background-blend-mode` stays positionally correct.\n const kept: Fill[] = [];\n const layers: string[] = [];\n for (const f of fills) {\n const css = fillToCss(f, nodeId);\n if (css) {\n layers.push(css);\n kept.push(f);\n }\n }\n if (layers.length === 0) return {};\n const css: CSSProperties = { backgroundImage: layers.join(\", \") };\n // #L — per-fill-layer blend on a frame background uses CSS\n // `background-blend-mode` (one keyword per layer, same order). Each value is\n // re-validated against the closed enum (runtime T4 arm) ; an absent/rejected\n // value falls back to `normal`. Emitted only when at least one layer carries\n // a non-`normal` blend, to keep pre-#L output byte-identical (rétro-compat).\n const blends = kept.map((f) => parseBlendMode(f.blendMode) ?? \"normal\");\n if (blends.some((b) => b !== \"normal\")) {\n css.backgroundBlendMode = blends.join(\", \");\n }\n // When any layer is an image-fill, drive its sizing from the (already\n // validated) objectFit. A single image-fill is the common cover case ;\n // for the first image-fill we set the background sizing for the whole box.\n const firstImage = fills.find((f) => f.kind === \"image\") as\n | Extract<Fill, { kind: \"image\" }>\n | undefined;\n if (firstImage) {\n css.backgroundSize = objectFitToBackgroundSize(firstImage.objectFit);\n css.backgroundPosition = \"center\";\n css.backgroundRepeat = \"no-repeat\";\n }\n return css;\n}\n\n/** CSS-escape a (already host-gated) URL for safe interpolation into a\n * `url(\"…\")` token — escape backslash and the double-quote that would\n * otherwise break out of the quoted string. */\nfunction cssUrl(src: string): string {\n return `url(\"${src.replace(/\\\\/g, \"\\\\\\\\\").replace(/\"/g, '\\\\\"')}\")`;\n}\n\nfunction fillToCss(fill: Fill, nodeId?: string): string | null {\n if (fill.kind === \"image\") {\n // `src` is pre-gated (T1/T2) by `gateImageFills` ; only escape it for\n // the CSS string context here.\n return cssUrl(fill.src);\n }\n // RC#11 — every colour interpolated into an inline CSS string MUST\n // pass the strict parser first (fills/stops arrive from untrusted\n // bundles AND live LSDP deltas). A rejected colour drops the whole\n // layer : never passthrough, never a half-built gradient.\n if (fill.kind === \"solid\") {\n const color = parseCssColor(fill.color);\n if (color === null) {\n warnRejectedColor(\"fill.color\", nodeId);\n return null;\n }\n // A solid fill carries its OWN opacity (Figma layer-fill alpha, e.g. a 14%\n // white pill) — apply it like a gradient stop's, else the layer renders\n // fully opaque and hides whatever it overlays.\n const c = fill.opacity !== undefined ? cssWithOpacity(color, fill.opacity) : color;\n // Wrap solid in linear-gradient so it can stack with other layers.\n return `linear-gradient(${c}, ${c})`;\n }\n const safeStops: string[] = [];\n for (const s of fill.stops) {\n const color = parseCssColor(s.color);\n if (color === null) {\n warnRejectedColor(\"fill.stops.color\", nodeId);\n return null;\n }\n const c = s.opacity !== undefined ? cssWithOpacity(color, s.opacity) : color;\n safeStops.push(`${c} ${(s.offset * 100).toFixed(2)}%`);\n }\n const stops = safeStops.join(\", \");\n if (fill.kind === \"linear-gradient\") {\n let angle = fill.angle_deg ?? 0;\n // Honour the Figma `gradientTransform` when present : the gradient's main\n // axis (offset 0 → 1) is column 0 = (a, b) of the 2×3 matrix. CSS `Ndeg`\n // measures clockwise from \"up\" and screen-y points down, so that direction\n // maps to `atan2(a, -b)`. `angle_deg` alone ignored the matrix and rendered\n // the Cover's warm base as a 270° (horizontal) wash instead of the real 180°\n // (warm at top) — leaving the top-right black under the Ruby20 hard-light.\n const t = (fill as { transform?: number[] }).transform;\n if (Array.isArray(t) && t.length === 6 && Number.isFinite(t[0]) && Number.isFinite(t[1])) {\n angle = ((Math.atan2(t[0], -t[1]) * 180) / Math.PI + 360) % 360;\n }\n return `linear-gradient(${angle}deg, ${stops})`;\n }\n // radial-gradient\n const cx = (fill.center?.x ?? 0.5) * 100;\n const cy = (fill.center?.y ?? 0.5) * 100;\n return `radial-gradient(circle at ${cx}% ${cy}%, ${stops})`;\n}\n\n/** Apply a stop opacity to an ALREADY-VALIDATED colour (callers must\n * have run `parseCssColor` first — fillToCss is the single entry).\n * For 6-digit hex we append the alpha byte ; every other accepted\n * form goes through color-mix, which is safe because the interpolated\n * string can only be a strict-grammar colour (RC#11 fix : this used\n * to interpolate the raw, unparsed input). */\nfunction cssWithOpacity(color: string, opacity: number): string {\n const hex = color.match(/^#([0-9a-f]{6})$/i);\n if (hex) {\n const a = Math.round(opacity * 255)\n .toString(16)\n .padStart(2, \"0\");\n return `#${hex[1]}${a}`;\n }\n return `color-mix(in srgb, ${color} ${opacity * 100}%, transparent)`;\n}\n\n/** Validate every colour carried by a Fill array through the strict\n * parser (RC#11 — issue #30 contractual comment : SVG `fill`/`stroke`\n * attributes and `<stop stop-color>` are injection sites too, since\n * fills arrive from untrusted bundles AND live LSDP deltas). A fill\n * whose solid colour — or ANY gradient stop colour — is rejected drops\n * the whole layer with a diagnostic : never passthrough, never a\n * half-built gradient. Returned fills carry canonicalised colours. */\nexport function sanitizeFills(fills: Fill[], field: string, nodeId?: string): Fill[] {\n const out: Fill[] = [];\n for (const fill of fills) {\n // Image-fills carry no colour — they are colour-clean by construction.\n // Their `src` is gated separately (`gateImageFills`, T1/T2) ; pass them\n // through here unchanged so `sanitizeFills` only owns colour validation.\n if (fill.kind === \"image\") {\n out.push(fill);\n continue;\n }\n if (fill.kind === \"solid\") {\n const color = parseCssColor(fill.color);\n if (color === null) {\n warnRejectedColor(`${field}.color`, nodeId);\n continue;\n }\n out.push({ ...fill, color });\n continue;\n }\n const stops: FillStop[] = [];\n let rejected = false;\n for (const s of fill.stops ?? []) {\n const color = parseCssColor(s.color);\n if (color === null) {\n warnRejectedColor(`${field}.stops.color`, nodeId);\n rejected = true;\n break;\n }\n stops.push({ ...s, color });\n }\n if (rejected) continue;\n out.push({ ...fill, stops });\n }\n return out;\n}\n\n/** Coerce loose JSON into a Fill array. Returns [] for non-arrays.\n * A structurally-valid fill entry whose `kind` is not renderable by\n * this runtime (e.g. `angular-gradient` / `diamond-gradient`, promoted\n * to core by the LSML 1.2 RFC) is dropped WITH a diagnostic — never\n * silently (ADR 001 §3.4, issue #34). */\nexport function parseFills(value: unknown, field?: string, nodeId?: string): Fill[] {\n if (!Array.isArray(value)) return [];\n if (field !== undefined) {\n for (const v of value) {\n if (!isFill(v)) {\n emitDiagnostic(\n nodeId,\n `${field}.kind`,\n \"fill kind is not renderable by this runtime ; layer dropped (angular/diamond gradients land with LSML 1.2)\",\n );\n }\n }\n }\n // Image-fill `objectFit` is re-validated against the closed enum here\n // (Bastion T4 runtime arm) : a hostile / unknown value is dropped with a\n // diagnostic and the fill falls back to the default fit — never passed\n // through to inline CSS. `src` is NOT gated here (it needs the host\n // allowlist) — `gateImageFills` does that downstream, before render.\n return value.filter(isFill).map((v) => {\n let fill = v as Fill;\n // #L — re-validate a per-fill `blendMode` against the closed enum (runtime\n // T4 arm). An out-of-enum value is diagnosed + stripped (the layer falls\n // back to `normal`), never passed through to inline CSS. Applies to every\n // fill kind.\n if (fill.blendMode !== undefined && parseBlendMode(fill.blendMode) === undefined) {\n emitDiagnostic(\n nodeId,\n field !== undefined ? `${field}.blendMode` : \"fill.blendMode\",\n \"is not a recognised mix-blend-mode ; falling back to normal (ADR 002 §3.2)\",\n );\n const { blendMode: _drop, ...rest } = fill;\n fill = rest;\n }\n if (fill.kind !== \"image\") return fill;\n if (fill.objectFit === undefined) return fill;\n const fit = parseObjectFitRuntime(fill.objectFit);\n if (fit === undefined) {\n emitDiagnostic(\n nodeId,\n field !== undefined ? `${field}.objectFit` : \"fill.objectFit\",\n \"is not a recognised object-fit ; falling back to default (ADR 002 §3.2)\",\n );\n const { objectFit: _drop, ...rest } = fill;\n return rest;\n }\n return { ...fill, objectFit: fit };\n });\n}\n\nfunction isFill(v: unknown): v is Fill {\n if (typeof v !== \"object\" || v === null) return false;\n const k = (v as { kind?: unknown }).kind;\n if (k === \"solid\" || k === \"linear-gradient\" || k === \"radial-gradient\") return true;\n // An image-fill must carry a string `src` to be structurally valid ; a\n // malformed image entry is dropped like any other unrenderable fill.\n return k === \"image\" && typeof (v as { src?: unknown }).src === \"string\";\n}\n\n/**\n * Drop every image-fill whose `src` fails the host/scheme allowlist\n * (Bastion T1/T2), BEFORE any image-fill reaches the DOM. A rejected\n * image-fill is omitted entirely (never a passthrough URL) with an\n * R9-clean diagnostic emitted by `gateSrc`. Non-image fills pass through\n * untouched. Call this once, after `parseFills`, with the active\n * `allowedHosts` from `useAllowedHosts()`.\n */\nexport function gateImageFills(\n fills: Fill[],\n allowedHosts: readonly string[] | undefined,\n field: string,\n nodeId?: string,\n): Fill[] {\n return fills.filter((fill) => {\n if (fill.kind !== \"image\") return true;\n return gateSrc(fill.src, allowedHosts, `${field}.src`, nodeId) !== undefined;\n });\n}\n","import { motion } from \"framer-motion\";\nimport type { CSSProperties } from \"react\";\nimport type { PrimitiveProps } from \"./index\";\nimport { toFramer, mountPlay, resolveTransition } from \"../../animate/transitions\";\nimport { backgroundsToCss, parseFills, gateImageFills } from \"../fill\";\nimport { parseCssColor, warnRejectedColor } from \"../css-color\";\nimport { emitDiagnostic } from \"../diagnostics\";\nimport { useAllowedHosts } from \"../allowed-hosts\";\n\n/** Absolute-positioned container with size + transform + opacity.\n * Animatable on `transform` and `opacity` only — width/height/position\n * changes are intentionally *not* animatable to keep the broadcast\n * off the layout path.\n *\n * LSML 1.1 §4.3 + §4.12 add `backgrounds[]` as an alternative to the\n * legacy `background` (single color). The array form supports stacked\n * fills with linear / radial gradients ; first entry renders on top.\n *\n * LSML 1.1 §4.3 `clipsContent` (default `true`) clips children outside\n * the frame's bounds via `overflow: hidden` (ADR 001 §3.2.5, RC#5).\n */\nexport function Frame({\n resolved,\n nodeId,\n transitionFor,\n animateInitial,\n children,\n}: PrimitiveProps) {\n const x = numberOr(resolved.x, 0);\n const y = numberOr(resolved.y, 0);\n const width = sizeProp(resolved.width);\n const height = sizeProp(resolved.height);\n const opacity = numberOr(resolved.opacity, 1);\n const scale = numberOr(resolved.scale, 1);\n // Static `rotation` (LSML §5.4) is applied HERE, on the frame's own box, so it\n // pivots around the frame centre (transform-origin: center). It must NOT go on\n // the UniversalWrapper for a frame : the wrapper carries no position/size for\n // a self-positioning frame, so it collapses to a 0-height box and the rotation\n // pivots around the wrong point (the picto/caramel swung off-place). `rotate`\n // (animated) still wins when present.\n const rotate = numberOr(resolved.rotate, numberOr(resolved.rotation, 0));\n // Mirror (Figma `scaleY(-1)`, from a negative transform determinant). Applied\n // on the frame box like the rotation so it composes correctly.\n const flipY = resolved.flipY === true;\n // Compiler forwards `cornerRadius` → `radius` (compile.ts). A frame can be a\n // rounded container (Figma pills, the rounded picto square) — apply it as\n // `border-radius` so the frame isn't rendered square.\n const radius = numberOr(resolved.radius, 0);\n\n // 1.0 single-fill prop — used as fallback when 1.1 `backgrounds[]`\n // is empty. RC#11 : the value is untrusted (static prop OR live LSDP\n // delta) and lands in inline CSS — strict-parse, never passthrough.\n const rawBackground = resolved.background;\n const legacyBackground = rawBackground === undefined ? undefined : parseCssColor(rawBackground);\n if (rawBackground !== undefined && legacyBackground === null) {\n warnRejectedColor(\"frame.background\", nodeId);\n }\n // LSML 1.2 §3.2 — image-fill `src` is host/scheme-gated (Bastion T1/T2)\n // BEFORE any URL reaches `background-image`. A rejected image-fill is\n // dropped (no passthrough) with an R9-clean diagnostic.\n const allowedHosts = useAllowedHosts();\n const backgrounds = gateImageFills(\n parseFills(resolved.backgrounds, \"frame.backgrounds\", nodeId),\n allowedHosts,\n \"frame.backgrounds\",\n nodeId,\n );\n const clipsContent = resolveClipsContent(resolved.clipsContent, nodeId);\n\n // Pick the most expressive declared transition among the animated\n // bindings (transform / opacity). If none, no animation.\n const tx = resolveTransition(\n transitionFor,\n [\"opacity\", \"scale\", \"rotate\", \"x\", \"y\"],\n animateInitial,\n );\n\n const style: CSSProperties = {\n position: \"absolute\",\n left: 0,\n top: 0,\n width,\n height,\n // NB: NO permanent `will-change`. `will-change: opacity` makes the frame an\n // isolated group (the browser pre-promotes it as if opacity < 1), which\n // CONTAINS any descendant `mix-blend-mode` to the frame's own backdrop — so\n // a screen/hard-light layer (Sunshine, Ruby20) silently stops compositing\n // with the scene below. The hint also belongs only on actively-animating\n // nodes (bind-animate adds it there) ; a static board doesn't need it.\n // LSML 1.1 §4.3 `clipsContent` (default `true`) — children outside\n // the frame's `size` are clipped. Static layout property : it never\n // animates, so it stays off the 0-layout-event hot path (ADR 001\n // §3.2.5). `false` => omit the declaration (CSS initial = visible).\n ...(clipsContent ? { overflow: \"hidden\" } : {}),\n ...(radius > 0 ? { borderRadius: radius } : {}),\n };\n if (backgrounds.length > 0) {\n Object.assign(style, backgroundsToCss(backgrounds, nodeId));\n } else if (legacyBackground !== undefined && legacyBackground !== null) {\n style.background = legacyBackground;\n }\n // Figma DROP_SHADOW / INNER_SHADOW. INNER → CSS `box-shadow: inset` (the\n // square's orange/red rim, on the rotated rounded frame, rotates with it in\n // local space — matches Figma). A no-spread DROP → CSS `filter: drop-shadow`,\n // which casts the shadow from the element's RENDERED CONTENT silhouette, not\n // its own rectangular box : the 5 drop shadows live on the UN-rotated wrapper\n // GROUP, so a plain `box-shadow` would project a sharp axis-aligned 464² rect\n // instead of the rotated (8.63°) rounded (r=111) square held inside. The\n // colour is strict-parsed (RC#11) ; geometry is numeric.\n const { filter: shadowFilter, boxShadow } = buildShadows(resolved.shadow, nodeId);\n if (boxShadow !== undefined) style.boxShadow = boxShadow;\n if (shadowFilter !== undefined) style.filter = shadowFilter;\n\n const play = mountPlay(\n { opacity, x, y, scale, rotate, ...(flipY ? { scaleY: -1 } : {}) },\n animateInitial,\n nodeId,\n );\n\n return (\n <motion.div\n style={style}\n initial={play.initial}\n animate={play.animate}\n transition={toFramer(tx)}\n >\n {children}\n </motion.div>\n );\n}\n\n/**\n * Resolve `clipsContent` (LSML 1.1 §4.3, schema default `true`).\n *\n * The prop is wire-drivable (static bundle prop OR live LSDP delta via\n * `resolveProps`, tree.tsx), so a non-boolean is treated as hostile :\n * R9 diagnostic (value withheld) + fall back to the spec default\n * (`true`, i.e. clipped — the safe state for broadcast). The returned\n * value only ever selects between two literal style fragments — no\n * untrusted value can reach inline CSS through this path (RC#11 by\n * construction). Exported for boundary testing.\n */\nexport function resolveClipsContent(v: unknown, nodeId?: string): boolean {\n if (v === undefined) return true;\n if (typeof v === \"boolean\") return v;\n emitDiagnostic(nodeId, \"frame.clipsContent\", \"rejected value : not a boolean\");\n return true;\n}\n\nfunction numberOr(v: unknown, fallback: number): number {\n return typeof v === \"number\" && Number.isFinite(v) ? v : fallback;\n}\n\n/** Build validated shadow CSS from the node's `shadow[]` (each entry:\n * `{ inset?, color, x, y, blur, spread }`). Every colour goes through the\n * strict `parseCssColor` gate (RC#11 : the value is wire-drivable) — a\n * rejected colour drops that layer with a diagnostic, never reaches CSS.\n * Geometry values are coerced to finite numbers.\n *\n * Splits by kind :\n * - INNER (inset) OR any shadow with a non-zero spread → `box-shadow`\n * (inset rim / spread halo — both follow the element's own border box,\n * which for the rotated rounded square IS the right silhouette).\n * - no-spread DROP → `filter: drop-shadow`, cast from the element's rendered\n * CONTENT (so a wrapper group's drop shadow tracks its rotated/rounded\n * child instead of the wrapper's rectangular box). drop-shadow's blur maps\n * to a Gaussian stdDeviation ; box-shadow uses 2×σ, so halve to match.\n * Returns `{}` when nothing usable survives. */\nfunction buildShadows(value: unknown, nodeId?: string): { filter?: string; boxShadow?: string } {\n if (!Array.isArray(value) || value.length === 0) return {};\n const dropParts: string[] = [];\n const boxParts: string[] = [];\n for (const s of value) {\n if (typeof s !== \"object\" || s === null) continue;\n const spec = s as {\n inset?: unknown;\n color?: unknown;\n x?: unknown;\n y?: unknown;\n blur?: unknown;\n spread?: unknown;\n };\n const color = typeof spec.color === \"string\" ? parseCssColor(spec.color) : null;\n if (color === null) {\n warnRejectedColor(\"frame.shadow.color\", nodeId);\n continue;\n }\n const x = numberOr(spec.x, 0);\n const y = numberOr(spec.y, 0);\n const blur = numberOr(spec.blur, 0);\n const spread = numberOr(spec.spread, 0);\n const inset = spec.inset === true;\n if (!inset && spread === 0) {\n dropParts.push(`drop-shadow(${x}px ${y}px ${blur / 2}px ${color})`);\n } else {\n const insetKw = inset ? \"inset \" : \"\";\n boxParts.push(`${insetKw}${x}px ${y}px ${blur}px ${spread}px ${color}`);\n }\n }\n const out: { filter?: string; boxShadow?: string } = {};\n if (dropParts.length > 0) out.filter = dropParts.join(\" \");\n if (boxParts.length > 0) out.boxShadow = boxParts.join(\", \");\n return out;\n}\n\nfunction sizeProp(v: unknown): number | string | undefined {\n if (typeof v === \"number\" && Number.isFinite(v)) return v;\n if (typeof v === \"string\" && v.length > 0) return v;\n return undefined;\n}\n","import { motion } from \"framer-motion\";\nimport type { PrimitiveProps } from \"./index\";\nimport { toFramer, mountPlay, resolveTransition } from \"../../animate/transitions\";\nimport { parseCssColor, warnRejectedColor } from \"../css-color\";\nimport { emitDiagnostic } from \"../diagnostics\";\n\n// ── Typography grammars (LSML 1.1 TextStyle, schema.json) ───────────\n// Every typo prop is wire-drivable (static bundle prop OR live LSDP\n// delta via `resolveProps`, tree.tsx) and lands in inline CSS, so each\n// value is validated against the field's spec'd grammar before it may\n// reach the style object. Enum fields go through a closed allowlist\n// (the emitted string is always one of these constants — never the\n// input), numeric fields through finite-number checks. There is NO\n// string passthrough on any of these sites (ADR 001 RC#11 by\n// construction : no untrusted string ever reaches the style object).\nconst TEXT_TRANSFORMS = new Set([\"none\", \"uppercase\", \"lowercase\", \"capitalize\"]);\nconst TEXT_DECORATIONS = new Set([\"none\", \"underline\", \"line-through\"]);\nconst FONT_STYLES = new Set([\"normal\", \"italic\", \"oblique\"]);\n\n// ── Defence-in-depth upper bounds (issue #34, Bastion follow-up on\n// PR #38) ─────────────────────────────────────────────────────────────\n// The numeric typo fields were type-validated but unbounded ; an absurd\n// value pushed by a hostile bundle or live delta could degrade layout /\n// rendering (e.g. a 10⁹-line clamp or a kilometric letter spacing).\n// Policy : a value beyond its cap is REJECTED (diagnostic + omit → CSS\n// initial), consistent with the existing typo grammar gates — NOT\n// clamped, unlike the R8 filter caps where the spec explicitly blesses\n// clamping. Rationale : there is no \"nearest sensible rendering\" for an\n// absurd typographic value, the author's intent is unknowable ; safe\n// default beats silently-altered output.\n/** Max `maxLines` accepted (Bastion suggested ≤ 1000 on PR #38). */\nexport const MAX_MAX_LINES = 1000;\n/** Max unitless `lineHeight` multiplier (100× the font size is already\n * far beyond any broadcast layout). */\nexport const MAX_LINE_HEIGHT = 100;\n/** Max |letterSpacing| in px, both directions (±1000 px covers any\n * legitimate broadcast typography). */\nexport const MAX_LETTER_SPACING_PX = 1000;\n\n// ── fontFamily policy (issue #34, Bastion follow-up on PR #38) ───────\n// Decision : SHAPE validation, not a font allowlist. `fontFamily` is\n// assigned through the React style object (per-property assignment via\n// CSSStyleDeclaration), which cannot break out of the declaration — so\n// the residual risk is malformed CSS, not injection. A font allowlist\n// would couple the runtime to a host-specific font inventory (a spec /\n// RFC matter — flagged for Atlas in the PR), whereas shape validation\n// keeps any legitimate family name working. The grammar accepts\n// comma-separated family lists with optional quotes ; the injection\n// metacharacters (`;` `}` `{` `:` `\\` `<` `>` `(` `)`) and `url(` are\n// rejected by construction (none of their characters are allowed).\n// Anchored, single character class with a bounded quantifier — linear\n// time (RC#12).\nconst FONT_FAMILY_RE = /^[a-zA-Z0-9 ,.'\"_-]{1,256}$/;\n\n/** Validate an untrusted `fontFamily` value. Returns the string or\n * `null` on rejection (handled as \"omit → inherit\", with diagnostic). */\nexport function parseFontFamily(value: unknown): string | null {\n if (typeof value !== \"string\") return null;\n const v = value.trim();\n if (v.length === 0) return null;\n return FONT_FAMILY_RE.test(v) ? v : null;\n}\n\n/** Text leaf. Value renders as the displayed string ; style props\n * cover the full LSML TextStyle (size / font / weight / colour /\n * alignment / lineHeight / letterSpacing / textTransform /\n * textDecoration / fontStyle) plus `maxLines` (§4.4 ellipsis\n * truncation). Opacity is animated when a transition is declared on\n * `opacity` or `value`. An `animate.from` makes it mount-play\n * (initial → target) on mount. */\nexport function Text({ resolved, nodeId, transitionFor, animateInitial }: PrimitiveProps) {\n const value = resolved.value === undefined ? \"\" : String(resolved.value);\n const size = (resolved.size as string | number | undefined) ?? \"1rem\";\n const weight = (resolved.weight as number | undefined) ?? 400;\n // Issue #34 — `font` is untrusted and lands in inline CSS : shape-\n // validate (see fontFamily policy above) ; rejected → inherit.\n let font: string | undefined;\n if (resolved.font !== undefined) {\n const parsed = parseFontFamily(resolved.font);\n if (parsed === null) {\n emitDiagnostic(nodeId, \"text.font\", \"rejected fontFamily : outside the family-list grammar\");\n } else {\n font = parsed;\n }\n }\n // RC#11 : `colour` is untrusted (static prop OR live LSDP delta) and\n // lands in inline CSS — strict-parse ; rejected → safe default.\n let colour = \"currentColor\";\n if (resolved.colour !== undefined) {\n const parsed = parseCssColor(resolved.colour);\n if (parsed === null) {\n warnRejectedColor(\"text.colour\", nodeId);\n } else {\n colour = parsed;\n }\n }\n const align = (resolved.align as string | undefined) ?? \"start\";\n const opacity = numberOr(resolved.opacity, 1);\n const typography = resolveTypography(resolved, nodeId);\n\n const tx = resolveTransition(transitionFor, [\"opacity\", \"value\"], animateInitial);\n const play = mountPlay({ opacity }, animateInitial, nodeId);\n\n return (\n <motion.span\n style={{\n display: \"inline-block\",\n fontSize: size,\n // `font` carries LSML text.style.fontFamily (spec'd in schema.json).\n // Omitted => inherit the host/container font.\n ...(font !== undefined ? { fontFamily: font } : {}),\n fontWeight: weight,\n color: colour,\n textAlign: align as React.CSSProperties[\"textAlign\"],\n ...typography,\n }}\n initial={play.initial}\n animate={play.animate}\n transition={toFramer(tx)}\n >\n {value}\n </motion.span>\n );\n}\n\nfunction numberOr(v: unknown, fallback: number): number {\n return typeof v === \"number\" && Number.isFinite(v) ? v : fallback;\n}\n\n/**\n * Resolve the LSML 1.1 TextStyle typography props (`lineHeight`,\n * `letterSpacing`, `textTransform`, `textDecoration`, `fontStyle`) and\n * `maxLines` (§4.4) into a validated React style fragment.\n *\n * Exported for boundary testing : happy-dom drops `-webkit-*`\n * declarations from `CSSStyleDeclaration`, so the line-clamp pattern is\n * asserted on the exact object handed to React's inline style (same\n * approach as `backgroundsToCss` for `color-mix`).\n *\n * Defaults = omit the declaration (inherit / CSS initial). A\n * non-conforming value → R9 diagnostic + omit ; the returned object\n * only ever contains allowlisted constants or validated finite\n * numbers — never the raw input. Numeric fields additionally enforce\n * the defence-in-depth caps above (issue #34).\n */\nexport function resolveTypography(\n resolved: Record<string, unknown>,\n nodeId?: string,\n): React.CSSProperties {\n // schema.json : lineHeight is a unitless multiplier ≥ 0 ;\n // letterSpacing is a number (px) ; the three enums are closed sets.\n const lineHeight = boundedNumber(\n resolved.lineHeight,\n 0,\n MAX_LINE_HEIGHT,\n \"text.lineHeight\",\n nodeId,\n );\n const letterSpacing = boundedNumber(\n resolved.letterSpacing,\n -MAX_LETTER_SPACING_PX,\n MAX_LETTER_SPACING_PX,\n \"text.letterSpacing\",\n nodeId,\n );\n const textTransform = enumValue(\n resolved.textTransform,\n TEXT_TRANSFORMS,\n \"text.textTransform\",\n nodeId,\n );\n const textDecoration = enumValue(\n resolved.textDecoration,\n TEXT_DECORATIONS,\n \"text.textDecoration\",\n nodeId,\n );\n const fontStyle = enumValue(resolved.fontStyle, FONT_STYLES, \"text.fontStyle\", nodeId);\n // §4.4 maxLines — truncation with ellipsis after N lines, via the\n // standard line-clamp pattern (display:-webkit-box overrides the\n // base inline-block ; this fragment is spread after it so it wins).\n const maxLines = positiveInteger(resolved.maxLines, MAX_MAX_LINES, \"text.maxLines\", nodeId);\n\n return {\n ...(lineHeight !== undefined ? { lineHeight } : {}),\n // Built from a validated finite number — no string passthrough.\n ...(letterSpacing !== undefined ? { letterSpacing: `${letterSpacing}px` } : {}),\n ...(textTransform !== undefined\n ? { textTransform: textTransform as React.CSSProperties[\"textTransform\"] }\n : {}),\n ...(textDecoration !== undefined ? { textDecoration } : {}),\n ...(fontStyle !== undefined ? { fontStyle } : {}),\n ...(maxLines !== undefined\n ? {\n display: \"-webkit-box\",\n WebkitBoxOrient: \"vertical\" as const,\n WebkitLineClamp: maxLines,\n overflow: \"hidden\",\n textOverflow: \"ellipsis\",\n }\n : {}),\n };\n}\n\n/** Closed-allowlist enum gate. Returns the canonical constant from the\n * allowlist (NEVER the raw input) or `undefined` (field omitted →\n * CSS initial). Non-conforming value → R9 diagnostic, no passthrough. */\nfunction enumValue(\n v: unknown,\n allow: ReadonlySet<string>,\n field: string,\n nodeId?: string,\n): string | undefined {\n if (v === undefined) return undefined;\n if (typeof v === \"string\" && allow.has(v)) return v;\n warnRejectedTypo(field, nodeId);\n return undefined;\n}\n\n/** Finite number within [min, max] or omit (R9 diagnostic on a\n * non-conforming or out-of-cap input — rejected, never clamped). */\nfunction boundedNumber(\n v: unknown,\n min: number,\n max: number,\n field: string,\n nodeId?: string,\n): number | undefined {\n if (v === undefined) return undefined;\n if (typeof v === \"number\" && Number.isFinite(v) && v >= min && v <= max) return v;\n warnRejectedTypo(field, nodeId);\n return undefined;\n}\n\n/** Integer in [1, max] or omit (schema : maxLines is a line count ;\n * capped per the issue #34 defence-in-depth bounds). */\nfunction positiveInteger(\n v: unknown,\n max: number,\n field: string,\n nodeId?: string,\n): number | undefined {\n if (v === undefined) return undefined;\n if (typeof v === \"number\" && Number.isInteger(v) && v >= 1 && v <= max) return v;\n warnRejectedTypo(field, nodeId);\n return undefined;\n}\n\n/**\n * Diagnostic for a typo value outside its spec'd grammar or caps.\n * Bastion R9 (ADR 001 §5.1) : the rejected VALUE is never logged nor\n * forwarded — only `node.id` (RC#7), the field name and a static\n * reason. Routed through the structured diagnostics channel.\n */\nfunction warnRejectedTypo(field: string, nodeId?: string): void {\n emitDiagnostic(\n nodeId,\n field,\n \"rejected typography value : outside the field's spec'd grammar or caps\",\n );\n}\n","import { motion } from \"framer-motion\";\nimport type { PrimitiveProps } from \"./index\";\nimport { toFramer, mountPlay, resolveTransition } from \"../../animate/transitions\";\nimport { gateSrc, useAllowedHosts } from \"../allowed-hosts\";\n\n/** Image leaf. `src`, `fit` (cover/contain/fill), `position`,\n * `opacity`. Opacity is animated when a transition is declared. When an\n * `animate.from` is lowered onto the node, it mounts at that state and\n * plays to its target on mount (mount-play).\n *\n * Security (Bastion T1/T2, ADR 002 #F) : `src` is untrusted (static prop\n * OR live LSDP delta) and was placed into the DOM with NO host/scheme\n * check until #F (the latent 1.1 hole — `assets.allowedHosts` was declared\n * but never enforced). It now passes `gateSrc` BEFORE reaching the `<img>`\n * — a rejected host/scheme omits the image entirely (no passthrough), with\n * an R9-clean diagnostic. This is the runtime arm of the double-gate. */\nexport function Image({ resolved, nodeId, transitionFor, animateInitial }: PrimitiveProps) {\n const allowedHosts = useAllowedHosts();\n const src = gateSrc(resolved.src, allowedHosts, \"image.src\", nodeId);\n if (!src) return null;\n // LSML §4.5 `alt` is required and was silently unrendered until\n // issue #34's allowlist audit surfaced it — now forwarded to the DOM.\n const alt = typeof resolved.alt === \"string\" ? resolved.alt : \"\";\n const fit = (resolved.fit as string | undefined) ?? \"contain\";\n const position = (resolved.position as string | undefined) ?? \"center\";\n const opacity = numberOr(resolved.opacity, 1);\n // `width`/`height` carry LSML image.size (compiler maps size.w/.h → width/height).\n // When present, honour the intrinsic image dimensions; otherwise fill the\n // container (the prior behaviour — a sized parent drives the layout).\n const width = dimOr(resolved.width, \"100%\");\n const height = dimOr(resolved.height, \"100%\");\n\n const tx = resolveTransition(transitionFor, [\"opacity\", \"src\"], animateInitial);\n const play = mountPlay({ opacity }, animateInitial, nodeId);\n\n return (\n <motion.img\n src={src}\n alt={alt}\n style={{\n objectFit: fit as React.CSSProperties[\"objectFit\"],\n objectPosition: position,\n width,\n height,\n // NB: NO `will-change` here. Promoting the <img> to its own GPU layer\n // hoists it out of the wrapper's paint buffer, so a `mix-blend-mode`\n // on the wrapper (Sunshine screen, Ruby20 / caramel hard-light) blends\n // an EMPTY box with the backdrop → the blend silently no-ops and the\n // image's contribution (the diagonal light streaks, the warm Ruby) is\n // lost. Static images don't need the compositor hint anyway.\n }}\n initial={play.initial}\n animate={play.animate}\n transition={toFramer(tx)}\n draggable={false}\n />\n );\n}\n\nfunction numberOr(v: unknown, fallback: number): number {\n return typeof v === \"number\" && Number.isFinite(v) ? v : fallback;\n}\n\n/** A render dimension: a finite number → px, a non-empty string → verbatim\n * (e.g. \"100%\"), anything else → the fallback. */\nfunction dimOr(v: unknown, fallback: string): string {\n if (typeof v === \"number\" && Number.isFinite(v)) return `${v}px`;\n if (typeof v === \"string\" && v.length > 0) return v;\n return fallback;\n}\n","// Strict SVG path-data validator — the ONLY gate through which\n// untrusted `d` strings (bundle props AND live LSDP deltas, see\n// `resolveProps` in tree.tsx) may reach a rendered `<path d>` attribute.\n//\n// ADR 001 §6 RC#10 (allowlisted `d` grammar) + RC#12 (anti-ReDoS),\n// threat model Bastion 2026-06-10, issue #30. Validation runs at EVERY\n// render — props are wire-drivable, so a hostile delta arriving after\n// mount goes through the exact same gate as a static prop.\n//\n// Accepted grammar (SVG path data, LSML 1.1 §4.6, nothing more) :\n// - command letters : M m L l H h V v C c S s Q q T t A a Z z\n// - numbers : [+-]? digits [. digits]? ([eE] [+-]? digits)?\n// - separators : space, tab, CR, LF, comma\n// Anything else — including `url(`, `data:`, `<`, `&`, parentheses,\n// quotes, semicolons, braces — is REJECTED (null). Never passthrough.\n//\n// ── Linear-time justification (RC#12, written per Bastion) ──────────\n// 1. Inputs longer than MAX_SUBPATH_LEN (8 KiB) are rejected on a\n// single O(1) length check before any scanning — a 10⁶-command\n// payload never reaches the scanner.\n// 2. The scanner is a hand-written single forward pass : every loop\n// iteration advances `i` by at least one character and there is no\n// regex anywhere, so total work is O(min(n, 8192)) per value\n// regardless of payload shape. No backtracking is possible by\n// construction.\n// 3. The command cap (MAX_SUBPATH_COMMANDS) additionally bounds the\n// number of path segments the SVG engine will ever be asked to\n// tessellate, independently of string length.\n// ─────────────────────────────────────────────────────────────────────\n\nimport { emitDiagnostic } from \"./diagnostics\";\n\n/** RC#10 — hard cap : 8 KiB per subpath `d` string. */\nexport const MAX_SUBPATH_LEN = 8192;\n/**\n * RC#10 — hard cap on commands per subpath. Aligned on the compiler's\n * MAX_PATH_COMMANDS = 4000 (PR #39, deliberate authoring cap) so a live\n * LSDP delta can never carry more commands than the authoring pipeline\n * accepts. A shared constant module is tracked in issue #41 — do not\n * diverge these two values in the meantime.\n */\nexport const MAX_SUBPATH_COMMANDS = 4000;\n/** RC#10 — hard cap on subpaths per shape. */\nexport const MAX_SUBPATHS = 64;\n\nconst CMD_CHARS = new Set(\"MmLlHhVvCcSsQqTtAaZz\");\n\nfunction isDigit(code: number): boolean {\n return code >= 0x30 && code <= 0x39; // 0-9\n}\n\nfunction isSeparator(code: number): boolean {\n // space, tab, CR, LF, comma\n return code === 0x20 || code === 0x09 || code === 0x0d || code === 0x0a || code === 0x2c;\n}\n\n/**\n * Validate an untrusted SVG path `d` string against the strict grammar\n * above. Returns the validated (trimmed) string or `null` on rejection.\n * A `null` MUST be handled as \"omit the subpath + emit a diagnostic\" —\n * never interpolate the raw input into the DOM.\n */\nexport function validatePathData(value: unknown): string | null {\n if (typeof value !== \"string\") return null;\n // O(1) length gate BEFORE any per-character work (RC#12).\n if (value.length === 0 || value.length > MAX_SUBPATH_LEN) return null;\n const d = value.trim();\n if (d.length === 0) return null;\n\n // Contractual explicit rejects (Bastion RC#10) — redundant with the\n // allowlist scan below, kept as belt-and-braces so the contract\n // holds even if the grammar is ever extended.\n const lower = d.toLowerCase();\n if (lower.includes(\"url(\") || lower.includes(\"data:\")) return null;\n if (d.includes(\"<\") || d.includes(\"&\")) return null;\n\n // Single forward pass — tokenizes commands and numbers, rejects any\n // character outside the allowlist, counts commands.\n const n = d.length;\n let i = 0;\n let commands = 0;\n let sawCommand = false;\n while (i < n) {\n const code = d.charCodeAt(i);\n if (isSeparator(code)) {\n i++;\n continue;\n }\n const ch = d[i];\n if (CMD_CHARS.has(ch)) {\n // Path data must start with a moveto (M/m).\n if (!sawCommand && ch !== \"M\" && ch !== \"m\") return null;\n sawCommand = true;\n commands++;\n if (commands > MAX_SUBPATH_COMMANDS) return null;\n i++;\n continue;\n }\n // Anything else must be a well-formed number token — and numbers\n // can only appear after the leading moveto.\n if (!sawCommand) return null;\n if (ch === \"+\" || ch === \"-\") i++;\n let digits = 0;\n while (i < n && isDigit(d.charCodeAt(i))) {\n i++;\n digits++;\n }\n if (i < n && d[i] === \".\") {\n i++;\n let fracDigits = 0;\n while (i < n && isDigit(d.charCodeAt(i))) {\n i++;\n fracDigits++;\n }\n // A token ending in a bare \".\" (empty decimal part, e.g. \"1.\")\n // must not be immediately followed by another \".\" — \"1..2\" is not\n // valid SVG path data and would otherwise be mis-scanned as the\n // two tokens \"1.\" + \".2\" (Probe bug report, issue #30).\n if (fracDigits === 0 && i < n && d[i] === \".\") return null;\n digits += fracDigits;\n }\n if (digits === 0) return null; // bare sign / dot / forbidden char\n if (i < n && (d[i] === \"e\" || d[i] === \"E\")) {\n i++;\n if (i < n && (d[i] === \"+\" || d[i] === \"-\")) i++;\n let expDigits = 0;\n while (i < n && isDigit(d.charCodeAt(i))) {\n i++;\n expDigits++;\n }\n if (expDigits === 0) return null;\n }\n }\n if (commands === 0) return null;\n return d;\n}\n\nexport interface SubPath {\n d: string;\n fillRule: \"nonzero\" | \"evenodd\";\n}\n\n/**\n * Resolve a shape's `pathData` / `paths[]` props (LSML 1.1 §4.6) into\n * validated subpaths ready for rendering — one `<path>` element per\n * entry (ADR 001 §3.2.3). `pathData` is equivalent to\n * `paths: [{ data: pathData, windingRule: \"NONZERO\" }]`.\n *\n * Re-runs at every render (RC#10 — props are live via LSDP deltas).\n * Every rejected or unrendered field emits a diagnostic (ADR 001 §3.4,\n * anti-silent-drop) that NEVER contains the value (R9).\n */\nexport function parseShapePaths(resolved: Record<string, unknown>, nodeId?: string): SubPath[] {\n const rawPaths = resolved.paths;\n const rawPathData = resolved.pathData;\n\n if (Array.isArray(rawPaths)) {\n if (rawPathData !== undefined) {\n // Spec §4.6 : mutually exclusive. Tolerate with paths[] winning\n // (mirrors the fills[]/fill precedence), but never silently.\n warnPath(nodeId, \"shape.pathData\", \"mutually exclusive with paths[] ; paths[] wins\");\n }\n const out: SubPath[] = [];\n for (let idx = 0; idx < rawPaths.length; idx++) {\n if (out.length >= MAX_SUBPATHS) {\n warnPath(nodeId, \"shape.paths\", \"subpath cap exceeded ; remaining entries dropped\");\n break;\n }\n const entry = rawPaths[idx] as { data?: unknown; windingRule?: unknown } | null;\n const d = validatePathData(\n typeof entry === \"object\" && entry !== null ? entry.data : undefined,\n );\n if (d === null) {\n warnPath(nodeId, \"shape.paths.data\", \"not a strict SVG path grammar (allowlist/caps)\");\n continue;\n }\n out.push({ d, fillRule: toFillRule(entry?.windingRule, nodeId) });\n }\n if (out.length === 0 && rawPaths.length > 0) {\n warnPath(nodeId, \"shape.paths\", \"no renderable subpath ; shape geometry omitted\");\n }\n return out;\n }\n\n if (rawPathData !== undefined) {\n const d = validatePathData(rawPathData);\n if (d === null) {\n warnPath(nodeId, \"shape.pathData\", \"not a strict SVG path grammar (allowlist/caps)\");\n return [];\n }\n return [{ d, fillRule: \"nonzero\" }];\n }\n\n // geometry:\"path\" with neither prop — spec'd field combination we\n // cannot render. Diagnostic, never a silent no-op (ADR 001 §3.4).\n warnPath(nodeId, \"shape.paths\", \"geometry is path but neither pathData nor paths[] is present\");\n return [];\n}\n\nfunction toFillRule(windingRule: unknown, nodeId?: string): \"nonzero\" | \"evenodd\" {\n if (windingRule === undefined || windingRule === \"NONZERO\") return \"nonzero\";\n if (windingRule === \"EVENODD\") return \"evenodd\";\n warnPath(nodeId, \"shape.paths.windingRule\", \"unknown winding rule ; defaulting to nonzero\");\n return \"nonzero\";\n}\n\n/**\n * Diagnostic for a rejected / unrendered path field. Bastion R9\n * (ADR 001 §5.1) : the rejected VALUE is never logged nor forwarded —\n * only `node.id` (RC#7, issue #34), the field name and a static reason.\n * Routed through the structured diagnostics channel.\n */\nfunction warnPath(nodeId: string | undefined, field: string, reason: string): void {\n emitDiagnostic(nodeId, field, reason);\n}\n","// Typed shape-geometry builder (ADR 002 §3.2 Amendment 2 / A2.1 #K).\n//\n// A single source of truth for turning a `shape` RenderNode's typed geometry\n// props (`geometry`/`kind`, `width`, `height`, `radius`, path `d`) into SVG\n// outline elements — built ELEMENT-BY-ELEMENT with React, never from a markup\n// string. Two call-sites consume it :\n//\n// 1. the `shape` primitive, which paints the outline with its fills/strokes ;\n// 2. `buildMask` (#K), which inlines the RESOLVED geometry of a referenced\n// shape into a `<mask>` as coverage paint (white) — replacing the former\n// `<use href=\"#id\">` that relied on a sibling being defs-resolvable.\n//\n// ── Security / structural contract ───────────────────────────────────\n// - T3 — zero arbitrary SVG markup. Every element here is a constructed\n// React node ; no raw-HTML React escape hatch is ever used on this path.\n// A path `d` still flows through `validatePathData` (svg-path.ts).\n// - Anti-cycle (A2.1, Bastion condition) — this builder reads ONLY the\n// node's own geometry props. It never reads `node.mask`, never descends\n// into `node.children`, and never re-enters the mask builder. Resolving a\n// `mask.source.ref` to a shape therefore inlines that shape's geometry and\n// NOTHING else : a `mask → shape (that itself carries a mask) → …` chain is\n// structurally cut at depth 1, so no unbounded recursion / DoS is possible.\n\nimport type { CSSProperties, ReactElement } from \"react\";\nimport type { RenderNode } from \"./bundle\";\nimport { parseShapePaths, type SubPath } from \"./svg-path\";\nimport { emitDiagnostic } from \"./diagnostics\";\n\n/** The geometry kind, read from `geometry` (compiler) or `kind` (legacy). */\nfunction geometryKind(props: Record<string, unknown>): string {\n return (props.geometry as string | undefined) ?? (props.kind as string | undefined) ?? \"rect\";\n}\n\nfunction numberOr(v: unknown, fallback: number): number {\n return typeof v === \"number\" && Number.isFinite(v) ? v : fallback;\n}\n\n/**\n * Build the outline of a `shape` node as SVG elements painted with the given\n * `fill` and `stroke`. Used by the `shape` primitive (per-fill layering) and,\n * with a fixed coverage paint, by the mask builder (#K).\n *\n * Integration #L — `paint.mixBlendMode` carries a per-fill `mix-blend-mode`\n * that has ALREADY been revalidated against the closed enum by `renderFill`\n * (double-gate T4). It is applied as an inline `style` on the painted layer's\n * SVG element. It is `undefined` for stroke passes and ALWAYS `undefined` for\n * mask coverage (`buildMaskCoverageFromShape` never sets it) — a mask is a\n * coverage stencil, never a colour/blend reproduction (#K hypothesis 2). No\n * value other than an enum-validated keyword can reach this style key.\n *\n * `nodeId` is for path-validation diagnostics only (never a value, R9).\n */\nexport function buildShapeOutline(\n props: Record<string, unknown>,\n paint: { fill: string; stroke?: string; strokeWidth?: number; mixBlendMode?: string },\n nodeId: string | undefined,\n keyPrefix = \"geom\",\n): ReactElement {\n const kind = geometryKind(props);\n const width = numberOr(props.width, 100);\n const height = numberOr(props.height, 100);\n const radius = numberOr(props.radius, 0);\n const stroke = paint.stroke ?? \"none\";\n const strokeWidth = paint.strokeWidth ?? 0;\n // #L — only an enum-revalidated keyword reaches here ; absent → no style key\n // (layer blends `normal`, rétro-compat). Mask coverage never passes one.\n const style: CSSProperties | undefined =\n paint.mixBlendMode !== undefined\n ? ({ mixBlendMode: paint.mixBlendMode } as CSSProperties)\n : undefined;\n\n if (kind === \"path\") {\n const subpaths = parseShapePaths(props, nodeId);\n return (\n <g key={keyPrefix} style={style}>\n {subpaths.map((p: SubPath, i: number) => (\n <path\n key={i}\n d={p.d}\n fillRule={p.fillRule}\n fill={paint.fill}\n stroke={stroke}\n strokeWidth={strokeWidth}\n />\n ))}\n </g>\n );\n }\n if (kind === \"circle\") {\n // A Figma ELLIPSE node lowers to `circle`, but its box is often NON-square\n // (the bg-shine glows are 699×428, 955×586…). Render an <ellipse> with the\n // per-axis radii so the shape keeps its real size — a circle (w===h) is the\n // degenerate case. Rendering a `min(w,h)` circle shrank the glows → the warm\n // wash came out too dark and the wrong shape.\n return (\n <ellipse\n key={keyPrefix}\n style={style}\n cx={width / 2}\n cy={height / 2}\n rx={Math.max(0, width / 2 - strokeWidth / 2)}\n ry={Math.max(0, height / 2 - strokeWidth / 2)}\n fill={paint.fill}\n stroke={stroke}\n strokeWidth={strokeWidth}\n />\n );\n }\n if (kind === \"line\") {\n return (\n <line\n key={keyPrefix}\n style={style}\n x1=\"0\"\n y1={height / 2}\n x2={width}\n y2={height / 2}\n stroke={stroke !== \"none\" ? stroke : paint.fill}\n strokeWidth={strokeWidth || 1}\n />\n );\n }\n // rect default\n return (\n <rect\n key={keyPrefix}\n style={style}\n x={strokeWidth / 2}\n y={strokeWidth / 2}\n width={Math.max(0, width - strokeWidth)}\n height={Math.max(0, height - strokeWidth)}\n rx={radius}\n ry={radius}\n fill={paint.fill}\n stroke={stroke}\n strokeWidth={strokeWidth}\n />\n );\n}\n\n/**\n * Build a referenced shape's geometry as mask COVERAGE paint (#K).\n *\n * Resolves to a white-painted outline (the default mask luminance paint) of\n * the referenced `shape` node — inlined into the `<mask>`. Returns `null` when\n * the node is not a paintable shape (defensive : the index only stores shapes,\n * but a live delta could mutate one), so the caller omits the mask.\n *\n * Anti-cycle : reads only `node.props` geometry — never the node's own `mask`\n * or children (profondeur de résolution = 1, A2.1 invariant).\n */\nexport function buildMaskCoverageFromShape(\n node: RenderNode,\n nodeId: string | undefined,\n): ReactElement | null {\n if (node.kind !== \"shape\") return null;\n const props = node.props ?? {};\n // White coverage : the SVG mask default paints luminance from white = full\n // coverage. We deliberately ignore the shape's own fills/strokes — a mask is\n // a coverage stencil, not a colour reproduction (A2.1 : inline the geometry).\n return buildShapeOutline(props, { fill: \"white\" }, nodeId, \"mask-cover\");\n}\n\n/** Default cap on the number of direct children composited into a group mask\n * (A4.4 budget T5). A container with more visible resolvable children is\n * TRUNCATED at this count with a diagnostic — never an unbounded build. The\n * real `817:2011` has 4 children ; the cap is generous yet bounded. */\nexport const GROUP_MASK_MAX_CHILDREN = 64;\n\n/** Default cap on container-descent depth (A4.4 anti-cycle). `1` = a group's\n * direct children may themselves be one level of sub-container ; below that a\n * sub-container contributes nothing (diagnostic), so a `group → group → …`\n * chain can never recurse without bound. We NEVER read a node's own `mask`\n * during descent (a `mask → group → … → mask` cycle is structurally cut). */\nexport const GROUP_MASK_MAX_DEPTH = 1;\n\n/** True iff a child node is excluded from the composite (`visible:false`).\n * `visible` lives in the node's static props (compiler-flattened), mirroring\n * the Tree's universal extraction (`resolved.visible`). */\nfunction isHidden(node: RenderNode): boolean {\n return (node.props as { visible?: unknown } | undefined)?.visible === false;\n}\n\nfunction numProp(props: Record<string, unknown> | undefined, key: string): number {\n const v = props?.[key];\n return typeof v === \"number\" && Number.isFinite(v) ? v : 0;\n}\n\n/**\n * Composite the mask COVERAGE of a GROUP/FRAME container's VISIBLE children\n * into a single typed `<g>` (#O, ADR 002 A4.3/A4.4).\n *\n * The coverage is the **union** of the white outlines of every visible direct\n * child of geometry-resolvable kind — union being the native behaviour of\n * stacking white coverages in one `<mask>` (SVG alpha cumulates). Each child's\n * geometry is translated by its own `x`/`y` so the union lands in the\n * container's coordinate space.\n *\n * Invariants (A4.4) :\n * - **visible-only** : `visible:false` children do not contribute.\n * - **anti-cycle, depth = 1** : a direct child that is itself a container is\n * descended at most `maxDepth` levels (default 1). We read ONLY geometry —\n * never any node's own `mask` — so a `mask → group → … → mask` chain is\n * structurally cut and no recursion through masks is possible.\n * - **budget T5** : at most `maxChildren` direct children are composited ;\n * beyond the cap the remainder is dropped with a static-reason diagnostic\n * (R9 — never the id value), never an unbounded composite / freeze.\n * - **omission, not crash** : a container with no visible resolvable child\n * returns `null` so the caller omits the mask (no throw).\n *\n * @param nodeId for diagnostics only (never a value, R9).\n * @param maxDepth container-descent cap (default {@link GROUP_MASK_MAX_DEPTH}).\n * @param maxChildren per-container child cap (default {@link GROUP_MASK_MAX_CHILDREN}).\n */\nexport function buildMaskCoverageFromGroup(\n node: RenderNode,\n nodeId: string | undefined,\n maxDepth: number = GROUP_MASK_MAX_DEPTH,\n maxChildren: number = GROUP_MASK_MAX_CHILDREN,\n): ReactElement | null {\n if (node.kind !== \"frame\") return null;\n const parts = collectCoverage(node, nodeId, maxDepth, maxChildren, \"grp\");\n if (parts.length === 0) return null;\n return <g key=\"mask-group-cover\">{parts}</g>;\n}\n\n/** True when a group-mask source carries a LAYER_BLUR on any (depth-bounded)\n * visible geometry child — the FEATHERED case (e.g. the bg-texture ellipse\n * blurred 107.76) whose soft rim needs the wrapper feather pad (mask.tsx /\n * tree.tsx). A sharp source returns false so the pad is skipped entirely — no\n * extra wrapper, no structural change to ordinary masks. Mirrors the blur\n * detection + descent bounds of `collectCoverage`. */\nexport function coverageIsFeathered(\n node: RenderNode,\n depth: number = GROUP_MASK_MAX_DEPTH,\n): boolean {\n if (node.kind !== \"frame\") return false;\n for (const child of (node.children ?? []) as RenderNode[]) {\n if (isHidden(child)) continue;\n if (numProp(child.props, \"blur\") > 0) return true;\n if (child.kind === \"frame\" && depth > 0 && coverageIsFeathered(child, depth - 1)) return true;\n }\n return false;\n}\n\n/** Recursive (depth-bounded) collector : returns the white coverage elements\n * of `node`'s visible direct children, translating each by its own `x`/`y`.\n * A child container is descended only while `depth > 0`. NEVER reads a node's\n * `mask`. */\nfunction collectCoverage(\n node: RenderNode,\n nodeId: string | undefined,\n depth: number,\n maxChildren: number,\n keyPrefix: string,\n): ReactElement[] {\n const children = node.children ?? [];\n const out: ReactElement[] = [];\n let composited = 0;\n for (let i = 0; i < children.length; i++) {\n const child = children[i] as RenderNode;\n if (isHidden(child)) continue;\n if (composited >= maxChildren) {\n emitDiagnostic(\n nodeId,\n \"mask.source.ref\",\n `group mask exceeds the ${maxChildren}-child composite cap ; remainder truncated (ADR 002 A4.4 T5)`,\n );\n break;\n }\n let part: ReactElement | null = null;\n if (child.kind === \"shape\") {\n part = buildShapeOutline(child.props ?? {}, { fill: \"white\" }, child.id, `${keyPrefix}-${i}`);\n } else if (child.kind === \"frame\" && depth > 0) {\n // Bounded container descent (anti-cycle) — geometry only, never `mask`.\n const sub = collectCoverage(child, nodeId, depth - 1, maxChildren, `${keyPrefix}-${i}`);\n if (sub.length > 0) part = <g key={`${keyPrefix}-${i}`}>{sub}</g>;\n }\n // A non-geometry child (text/image/instance) or a too-deep sub-container\n // contributes nothing — the mask is a coverage stencil over geometry only.\n if (part === null) continue;\n // A LAYER_BLUR on the coverage shape FEATHERS the mask edge — the bg-texture\n // mask is a single ellipse blurred 107.76 (radius), so the WP tiles fade out\n // softly instead of being cut by a hard circular edge. Apply it via an SVG\n // `<feGaussianBlur>` (radius ≈ 2× the CSS sigma) with a WIDE filter region :\n // a plain CSS `filter:blur()` on an SVG element clips to the default\n // −10%..120% box, so the feathered ellipse re-appeared with a hard SQUARE\n // edge. The wide region (−120%..340%) lets the soft rim spread unclipped.\n const childBlur = numProp(child.props, \"blur\");\n if (childBlur > 0) {\n const bf = `lumen-mcov-blur-${nodeId ?? \"x\"}-${keyPrefix}-${i}`;\n part = (\n <g key={`${keyPrefix}-b-${i}`}>\n <filter id={bf} x=\"-120%\" y=\"-120%\" width=\"340%\" height=\"340%\">\n <feGaussianBlur stdDeviation={childBlur / 2} />\n </filter>\n <g filter={`url(#${bf})`}>{part}</g>\n </g>\n );\n }\n const x = numProp(child.props, \"x\");\n const y = numProp(child.props, \"y\");\n out.push(\n x !== 0 || y !== 0 ? (\n <g key={`${keyPrefix}-t-${i}`} transform={`translate(${x} ${y})`}>\n {part}\n </g>\n ) : (\n part\n ),\n );\n composited++;\n }\n return out;\n}\n","import { motion } from \"framer-motion\";\nimport type { ReactElement } from \"react\";\nimport type { PrimitiveProps } from \"./index\";\nimport { toFramer, mountPlay, resolveTransition } from \"../../animate/transitions\";\nimport { parseFills, renderFill, sanitizeFills, gateImageFills } from \"../fill\";\nimport { parseCssColor, warnRejectedColor } from \"../css-color\";\nimport { useAllowedHosts } from \"../allowed-hosts\";\nimport { buildShapeOutline } from \"../shape-geometry\";\n\ninterface StrokeSpec {\n color?: string;\n width?: number;\n}\n\n/** Rectangle / circle / line / path. Renders as SVG so stroke + fill\n * behave predictably across hosts. Opacity animatable.\n *\n * LSML 1.1 §4.6 + §4.12 add `fills[]` / `strokes[]` arrays as the\n * preferred way to declare multi-layer fills with linear/radial\n * gradients. The legacy single `fill` / `stroke` props remain\n * accepted for 1.0 bundles ; when both are present the array form\n * wins (the spec forbids mixing, but we tolerate to ease migration).\n *\n * Security (ADR 001 §6 RC#10 + RC#11, issue #30) : every colour that\n * reaches an SVG `fill`/`stroke`/`stop-color` attribute goes through\n * the strict `parseCssColor` gate, and every path `d` goes through\n * `validatePathData` — at EVERY render, because props are wire-\n * drivable live via LSDP deltas (`resolveProps`, tree.tsx).\n */\nexport function Shape({ resolved, nodeId, transitionFor, animateInitial }: PrimitiveProps) {\n // Canonical prop name is `geometry` (LSML §4.6 — what the compiler\n // emits) ; `kind` is kept as a fallback for hand-rolled Solar-lineage\n // RenderNodes that predate the compiler.\n const kind =\n (resolved.geometry as string | undefined) ?? (resolved.kind as string | undefined) ?? \"rect\";\n const legacyFill = safeColor(resolved.fill, \"shape.fill\", nodeId) ?? \"transparent\";\n const legacyStroke = safeColor(resolved.stroke, \"shape.stroke\", nodeId) ?? \"transparent\";\n const legacyStrokeWidth = numberOr(resolved.stroke_width, 0);\n const width = numberOr(resolved.width, 100);\n const height = numberOr(resolved.height, 100);\n const opacity = numberOr(resolved.opacity, 1);\n // LSML §4.6 `ariaLabel` was silently unrendered until issue #34's\n // allowlist audit surfaced it — now forwarded as the SVG label.\n const ariaLabel = typeof resolved.ariaLabel === \"string\" ? resolved.ariaLabel : undefined;\n\n const tx = resolveTransition(transitionFor, [\"opacity\"], animateInitial);\n const transition = toFramer(tx);\n const play = mountPlay({ opacity }, animateInitial, nodeId);\n\n // LSML 1.1 §4.6 — `fills[]` is the preferred multi-fill form. Fall\n // back to the singular `fill` for 1.0 bundles. Colours are strict-\n // validated (a rejected colour drops its layer, with diagnostic).\n // LSML 1.2 §3.2 — image-fill `src` is host/scheme-gated (Bastion T1/T2)\n // BEFORE any URL reaches an SVG <image href>. A rejected image-fill is\n // dropped (no passthrough) with an R9-clean diagnostic. Colour fills go\n // through `sanitizeFills` (RC#11) ; image fills pass it through untouched.\n const allowedHosts = useAllowedHosts();\n const fills = gateImageFills(\n sanitizeFills(parseFills(resolved.fills, \"shape.fills\", nodeId), \"shape.fills\", nodeId),\n allowedHosts,\n \"shape.fills\",\n nodeId,\n );\n const strokes = parseStrokes(resolved.strokes);\n\n // Each fill compiles to a (defs, ref) pair. We render the shape\n // outline once per fill, layered top-to-bottom (first entry → on\n // top, per §4.12). The defs are aggregated for a single <defs>.\n const fillRenders = fills.map(renderFill);\n const allDefs = fillRenders.flatMap((r) => r.defs);\n // #L — each fill layer carries its (runtime-revalidated) `mix-blend-mode`,\n // applied on that layer's SVG element, independent of the node-level blend\n // (#D, on the wrapper). Legacy single-fill path carries no per-fill blend.\n const fillLayers: { ref: string; mixBlendMode?: string }[] =\n fillRenders.length > 0\n ? fillRenders.map((r) => ({ ref: r.ref, mixBlendMode: r.mixBlendMode }))\n : [{ ref: legacyFill }];\n\n // Strokes : same layered approach, but solid colours only (gradient\n // strokes are out of scope for §4.6 1.1). Each stroke is rendered\n // as an additional pass over the same shape outline.\n const strokeLayers =\n strokes.length > 0\n ? strokes.map((s) => ({\n color: safeColor(s.color, \"shape.strokes.color\", nodeId) ?? \"transparent\",\n width: s.width ?? 0,\n }))\n : [{ color: legacyStroke, width: legacyStrokeWidth }];\n\n // Stack order : fillRefs are emitted top-to-bottom per §4.12. SVG\n // paints later siblings on top, so we reverse here so the first\n // entry in fills[] ends up rendered last (visually on top).\n const stackedFills = [...fillLayers].reverse();\n const stackedStrokes = [...strokeLayers].reverse();\n // For paths, a zero-width / transparent stroke pass would only emit\n // invisible duplicate <path> elements — skip it.\n const effectiveStrokes =\n kind === \"path\"\n ? stackedStrokes.filter((s) => s.width > 0 && s.color !== \"transparent\")\n : stackedStrokes;\n\n // Integration #K × #L — geometry construction is delegated to the single\n // typed outline builder (`shape-geometry.tsx`, ADR 002 A2.1 #K), so a\n // referenced shape's mask coverage is built from the IDENTICAL geometry as\n // its on-screen render. The per-fill `mix-blend-mode` (#L, already runtime-\n // revalidated by `renderFill` against the closed enum) is threaded through\n // the paint argument and applied as inline `style` on the painted layer's\n // SVG element. `undefined` (absent / out-of-enum) → no style key, layer\n // blends `normal` (rétro-compat). Stroke passes never carry a fill blend —\n // and the mask coverage path NEVER carries a blend (a mask is a coverage\n // stencil, not a colour reproduction : `buildMaskCoverageFromShape` omits\n // `mixBlendMode` entirely, #K hypothesis 2).\n const renderShape = (\n fill: string,\n stroke: { color: string; width: number },\n keyPrefix: string,\n mixBlendMode?: string,\n ): ReactElement =>\n buildShapeOutline(\n resolved,\n { fill, stroke: stroke.color, strokeWidth: stroke.width, mixBlendMode },\n nodeId,\n keyPrefix,\n );\n\n return (\n <motion.svg\n width={width}\n height={height}\n viewBox={`0 0 ${width} ${height}`}\n {...(ariaLabel !== undefined ? { \"aria-label\": ariaLabel, role: \"img\" } : {})}\n initial={play.initial}\n animate={play.animate}\n transition={transition}\n >\n {allDefs.length > 0 && <defs>{allDefs}</defs>}\n {stackedFills.map((layer, i) =>\n renderShape(layer.ref, { color: \"transparent\", width: 0 }, `fill-${i}`, layer.mixBlendMode),\n )}\n {effectiveStrokes.map((s, i) => renderShape(\"none\", s, `stroke-${i}`))}\n </motion.svg>\n );\n}\n\n/** Strict-validate a colour prop (RC#11 — SVG attributes are injection\n * sites too once values are wire-drivable). Non-strings resolve to\n * null silently (absent prop) ; a string that fails the strict grammar\n * is rejected with a diagnostic (value withheld per R9). */\nfunction safeColor(value: unknown, field: string, nodeId?: string): string | null {\n if (typeof value !== \"string\") return null;\n const color = parseCssColor(value);\n if (color === null) warnRejectedColor(field, nodeId);\n return color;\n}\n\nfunction parseStrokes(value: unknown): StrokeSpec[] {\n if (!Array.isArray(value)) return [];\n return value.filter(\n (v): v is StrokeSpec => typeof v === \"object\" && v !== null && (\"color\" in v || \"width\" in v),\n );\n}\n\nfunction numberOr(v: unknown, fallback: number): number {\n return typeof v === \"number\" && Number.isFinite(v) ? v : fallback;\n}\n","import { useEffect, useRef, useState } from \"react\";\nimport { useOptionalLumencastRuntime } from \"../../overlay/runtime-context\";\n\n/** Shared LIVE peer-stream rendering (ADR 006 §3.3/§3.5) — the SINGLE srcObject\n * path used by BOTH the `media` primitive's live mode (#4, keyed on `peerLabel`)\n * AND the generic `meet.peer` source kind (the unified source abstraction).\n * There is no special renderer per source : every live source resolves\n * `peerLabel → MediaStream` through the host viewer and paints it the same way.\n *\n * Resolution : prefer the reactive channel (`subscribePeerStream`, #3) so a node\n * mounted BEFORE its peer connects re-renders on arrival ; fall back to the\n * one-shot `resolvePeerStream` (#4 contract) ; no host resolver → stream-less\n * box. Reading a stream is the ONLY side effect — the scene is never mutated\n * (RC-ReadOnly).\n *\n * Geometry (RC-Geo) : the `<video>` fills `100%`/`100%` of the box the Tree's\n * UniversalWrapper sized from the node's `x/y/width/height`. The geometry lives\n * on the wrapper, NEVER on the video, so it is structurally impossible to force\n * a full-viewport size ; `object-fit` is the scene-authored value.\n *\n * Ownership : the stream is owned by the viewer (#3). This component is a pure\n * consumer — unmounting clears its own `srcObject` and stops NO track (a mirror\n * must never tear a peer down for the on-air composite). */\nexport function LivePeerVideo({\n peerLabel,\n objectFit,\n muted = true,\n}: {\n peerLabel: string;\n objectFit: string;\n /** Audio playout hint. Always muted for now (broadcast audio is Pulsar-side). */\n muted?: boolean;\n}) {\n const runtime = useOptionalLumencastRuntime();\n const resolvePeerStream = runtime?.resolvePeerStream;\n const subscribePeerStream = runtime?.subscribePeerStream;\n\n const videoRef = useRef<HTMLVideoElement | null>(null);\n const [stream, setStream] = useState<MediaStream | null>(null);\n\n useEffect(() => {\n if (subscribePeerStream !== undefined) {\n return subscribePeerStream(peerLabel, setStream);\n }\n if (resolvePeerStream !== undefined) {\n setStream(resolvePeerStream(peerLabel));\n return;\n }\n setStream(null);\n }, [peerLabel, resolvePeerStream, subscribePeerStream]);\n\n // `srcObject` is not a serialisable attribute — attach imperatively. Never\n // stop the tracks here (the viewer owns them).\n useEffect(() => {\n const el = videoRef.current;\n if (el === null) return;\n el.srcObject = stream;\n return () => {\n if (el !== null) el.srcObject = null;\n };\n }, [stream]);\n\n if (stream === null) {\n // Stream-less box of the wrapper geometry — transparent, inert, paints\n // nothing. NOT an error : the peer can connect mid-show.\n return (\n <div\n aria-hidden\n data-lumencast-media-live\n style={{ width: \"100%\", height: \"100%\", opacity: 0, pointerEvents: \"none\" }}\n />\n );\n }\n\n return (\n <video\n ref={videoRef}\n data-lumencast-media-live\n autoPlay\n muted={muted}\n playsInline\n style={{\n width: \"100%\",\n height: \"100%\",\n objectFit: objectFit as React.CSSProperties[\"objectFit\"],\n pointerEvents: \"none\",\n }}\n />\n );\n}\n","import type { PrimitiveProps } from \"./index\";\nimport { gateSrc, useAllowedHosts } from \"../allowed-hosts\";\nimport { LivePeerVideo } from \"./live-peer-video\";\n\n/** Resolver injected by the consuming app (ADR 006 §3.3, #4). Maps a LOGICAL\n * `peerLabel` (the `meet.peer.peer_label` carried by the scene) to the live\n * `MediaStream` of that peer — supplied by the WebRTC viewer (issue #3). The\n * stream is rendered in `srcObject` ; it NEVER enters the bundle or the content\n * hash. Returns `null` when the peer is not (yet) connected → the node stays a\n * stream-less box, no throw, no diagnostic (a peer can join mid-show). */\nexport type ResolvePeerStream = (peerLabel: string) => MediaStream | null;\n\n/** Reactive variant (ADR 006 #3) : the viewer pushes a peer's stream when it\n * connects and `null` when it leaves. The LIVE primitive prefers this over the\n * one-shot resolver so a node that mounted BEFORE the peer connected re-renders\n * on arrival (a peer joins mid-show). The listener is invoked immediately with\n * the current value, then on every change ; the return value unsubscribes.\n * Like `resolvePeerStream`, it is injected at mount — never the bundle. */\nexport type SubscribePeerStream = (\n peerLabel: string,\n listener: (stream: MediaStream | null) => void,\n) => () => void;\n\n/** Embedded video. Two source modes, picked by the node's props :\n *\n * - **BUNDLE** (`src`, the original mode) : a `<video src>` of a bundled /\n * gated URL. Audio muted by default (broadcast audio is Pulsar-side). `src`\n * is the sole network sink and MUST pass `gateSrc` before reaching the\n * `<video>` (Bastion, ADR 003 — an off-allowlist request is an SSRF surface\n * in headless `zabrender`). A rejected host/scheme omits the source.\n *\n * - **LIVE** (`peerLabel`, ADR 006 #4) : the source is a `meet.peer`'s\n * `peer_label`. The runtime resolves the peer's `MediaStream` through a\n * host-provided resolver (`resolvePeerStream`, injected at mount — NOT the\n * bundle, like `resolveCaptureDevice`) and renders it imperatively via\n * `<video>.srcObject` in real time. No URL, no `gateSrc` (a `MediaStream`\n * is not a network sink). An absent resolver or an unconnected peer leaves a\n * stream-less box — no throw, no diagnostic (peers join mid-show).\n *\n * `peerLabel` takes precedence when present (a live node), else `src` (bundle).\n *\n * Geometry is read-only (ADR 006 A1.6) : the node's `x/y/width/height` are\n * applied by the Tree's UniversalWrapper around this primitive ; the `<video>`\n * fills that box (`100%`/`100%`) with the scene-authored `object-fit`. The\n * primitive NEVER forces full-screen and NEVER writes any geometry back — it\n * only reads `resolved`. */\nexport function Media({ resolved, nodeId }: PrimitiveProps) {\n const allowedHosts = useAllowedHosts();\n const fit = (resolved.fit as string | undefined) ?? \"cover\";\n const peerLabel =\n typeof resolved.peerLabel === \"string\" && resolved.peerLabel.length > 0\n ? resolved.peerLabel\n : \"\";\n\n if (peerLabel !== \"\") {\n // LIVE mode — the SAME srcObject path as the generic `meet.peer` source.\n return <LivePeerVideo peerLabel={peerLabel} objectFit={fit} />;\n }\n\n // BUNDLE mode (unchanged) — gated `<video src>`.\n const src = gateSrc(resolved.src, allowedHosts, \"media.src\", nodeId);\n if (!src) return null;\n const loop = (resolved.loop as boolean | undefined) ?? true;\n const mute = (resolved.mute as boolean | undefined) ?? true;\n const autoplay = (resolved.autoplay as boolean | undefined) ?? true;\n\n return (\n <video\n src={src}\n autoPlay={autoplay}\n loop={loop}\n muted={mute}\n playsInline\n style={fillBox(fit)}\n />\n );\n}\n\n/** The bundle `<video src>` fills the box the UniversalWrapper sized from the\n * node's `width`/`height` (RC-Geo) ; `object-fit` is the scene-authored `fit`.\n * The geometry lives on the wrapper, never on the video. */\nfunction fillBox(fit: string): React.CSSProperties {\n return {\n width: \"100%\",\n height: \"100%\",\n objectFit: fit as React.CSSProperties[\"objectFit\"],\n };\n}\n","import type { PrimitiveProps } from \"./index\";\nimport { LivePeerVideo } from \"./live-peer-video\";\n\n/** `meet.peer` — the UNIFIED source primitive (ADR 006 §3.3/§3.5). Every source\n * that crosses the Prism export (cam, screen, game_capture, …) arrives as a\n * single `meet.peer` LSML node ; this is the ONE renderer for all of them — not\n * a special-case path. It generalises the `media` primitive's live mode (#4) to\n * the source abstraction : read `peer_label`, resolve the peer's `MediaStream`\n * through the host viewer (#3), and paint it in `<video srcObject>` constrained\n * to the node's box.\n *\n * Contract (rendered verbatim, ADR §3.3 — no variation) :\n * - `peer_label` (string) — the STREAM REFERENCE. Resolved `peer_label →\n * MediaStream` via `subscribePeerStream`/`resolvePeerStream`. Empty / missing\n * → a transparent inert box (the source is not addressable).\n * - `x-zab.sourceKind` (string) — ADVISORY only. Rendering is UNIFORM whatever\n * the kind ; at most it could hint audio-only, but Phase 0 paints every\n * visual source identically.\n * - `object_fit` (\"cover\"|\"contain\"|\"fill\") — how the video fills the box.\n * - `muted` (bool, optional) — audio playout hint (default muted ; broadcast\n * audio is Pulsar-side).\n * - `position{x,y}` + `size{w,h}` — geometry via the Tree's UniversalWrapper\n * (compiler-flattened to `x/y/width/height`). Z-ORDER = sibling order (cam\n * over game = two ordered `meet.peer` nodes — no special z handling here).\n * - `metadata.figma` — advisory (editor round-trip), never read for rendering.\n *\n * RC-Geo : the `<video>` fills `100%`/`100%` of the wrapper box at the exact\n * authored geometry / `object_fit` — never forced full-screen (the geometry is\n * on the wrapper, not the video). RC-ReadOnly : the primitive only READS\n * `resolved` ; it never writes geometry or any field back to the scene. An\n * unconnected peer → transparent inert box, no throw, no diagnostic. */\nexport function MeetPeer({ resolved }: PrimitiveProps) {\n const peerLabel =\n typeof resolved.peer_label === \"string\" && resolved.peer_label.length > 0\n ? resolved.peer_label\n : \"\";\n\n // Empty / missing label → not addressable yet : a transparent inert box of the\n // wrapper geometry, exactly like an unconnected peer (no throw, no diagnostic).\n if (peerLabel === \"\") {\n return (\n <div\n aria-hidden\n data-lumencast-meet-peer\n style={{ width: \"100%\", height: \"100%\", opacity: 0, pointerEvents: \"none\" }}\n />\n );\n }\n\n const objectFit =\n typeof resolved.object_fit === \"string\" && resolved.object_fit.length > 0\n ? resolved.object_fit\n : \"cover\";\n const muted = resolved.muted === undefined ? true : resolved.muted !== false;\n\n return <LivePeerVideo peerLabel={peerLabel} objectFit={objectFit} muted={muted} />;\n}\n","import type { PrimitiveProps } from \"./index\";\nimport { LivePeerVideo } from \"./live-peer-video\";\n\n/** `x-zab.meet-peer` — the transparent meet-peer SLOT placeholder (Zab vendor\n * primitive, ADR Blue 009 §3.1 Amendment 2 ; type shipped in v0.10.0 / #81).\n *\n * Distinct from `meet.peer` (the cam-identity source) : this node carries NO\n * peer identity, only a hash-stable LOGICAL `x-zab.slotRef` (e.g. `cam-caster-1`)\n * + geometry. WHICH `peer_label` fills a slot is RUNTIME, stream-level ZabCam\n * state — never baked in the scene. The slot→peer binding is ported by Orion on\n * the LSDP as `__cam.slots.<slotRef>` = \"<peer_label>\" (§3.3) and re-keyed into\n * the host's peer-stream registry (Solar `slot-binding.ts`) so the registry\n * resolves `slotRef → peer_label → MediaStream`.\n *\n * Contract (rendered verbatim) :\n * - `x-zab.slotRef` (string) — the SLOT REFERENCE, used as the resolver KEY.\n * The host's peer-stream resolver (`resolvePeerStream`/`subscribePeerStream`)\n * is keyed by `slotRef` on the antenne (Solar's slot-aware registry maps it\n * to a `peer_label`, then to a stream). Empty / missing → a transparent inert\n * box (the slot is not addressable).\n * - geometry (`width`/`height` + position) — applied by the Tree's\n * UniversalWrapper, exactly like `meet.peer` ; the `<video>` fills the box\n * 100%/100% and is never forced full-screen (RC-Geo).\n *\n * Receive-only : the slot reads its stream through the host viewer (Solar joins\n * the room and owns the peer connections / track lifecycle) ; the primitive\n * carries no creds and never mutates the scene (RC-ReadOnly). An UNBOUND slot\n * (no `__cam.slots.*` assignment) or a not-yet-connected peer → a transparent\n * placeholder, no throw, no diagnostic (R3). */\nexport function MeetPeerSlot({ resolved }: PrimitiveProps) {\n const slotRef =\n typeof resolved[\"x-zab.slotRef\"] === \"string\" &&\n (resolved[\"x-zab.slotRef\"] as string).length > 0\n ? (resolved[\"x-zab.slotRef\"] as string)\n : \"\";\n\n // No slotRef → not addressable : a transparent inert box of the wrapper\n // geometry (no throw, no diagnostic), exactly like an unbound slot.\n if (slotRef === \"\") {\n return (\n <div\n aria-hidden\n data-lumencast-meet-peer-slot\n style={{ width: \"100%\", height: \"100%\", opacity: 0, pointerEvents: \"none\" }}\n />\n );\n }\n\n // Key the peer-viewer resolver by `slotRef` (NOT a peer_label). The shared\n // `LivePeerVideo` is resolver-key agnostic : it passes its `peerLabel` prop\n // straight to `resolvePeerStream`/`subscribePeerStream`, and the host's\n // slot-aware registry translates the slotRef to the bound peer's stream. An\n // unbound slot resolves to `null` → the transparent placeholder.\n return <LivePeerVideo peerLabel={slotRef} objectFit=\"cover\" muted />;\n}\n","// LSML 1.1 §4.9 — `instance` primitive (composite-instance reuse).\n//\n// Mounts a sub-scene by `scene_id` + `scene_version`. The sub-scene's\n// state is exposed to its tree under the `__params.*` reserved\n// namespace ; resolution happens via the runtime's bundle fetcher.\n//\n// This implementation is a SCAFFOLD : the visual slot is rendered\n// (size/position honoured) but the sub-tree is replaced by a\n// \"deferred load\" placeholder until the async bundle-fetch path is\n// wired. The composite-reuse rendering is the next iteration's work.\n//\n// What this primitive does today :\n// - parse scene_id, scene_version, params, fit, size, position\n// - reserve the slot in the parent layout\n// - log a one-time warning so authors know it's a scaffold\n//\n// What it does NOT do (yet) :\n// - fetch the inner bundle via the runtime's bundle resolver\n// - render the inner tree with __params.* injected into the store\n// - cycle detection (LSML 1.1 §4.9.2) — depth-8 limit applied at the\n// resolver layer rather than the renderer\n\nimport type { ReactElement } from \"react\";\nimport type { PrimitiveProps } from \"./index\";\nimport { emitDiagnostic } from \"../diagnostics\";\n\nconst warned = new Set<string>();\n\nexport function Instance({ resolved, nodeId }: PrimitiveProps): ReactElement | null {\n const sceneId = resolved.scene_id as string | undefined;\n const sceneVersion = resolved.scene_version as string | undefined;\n if (!sceneId || !sceneVersion) {\n // Structured diagnostic — never dump `resolved` (R9 : prop values,\n // including bound params, must not transit a diagnostic channel).\n emitDiagnostic(nodeId, \"instance.scene_id\", \"missing scene_id or scene_version ; not rendered\");\n return null;\n }\n\n // One-time diagnostic per (sceneId,version) so authors know the\n // scaffold limitation.\n const key = `${sceneId}:${sceneVersion}`;\n if (!warned.has(key)) {\n warned.add(key);\n emitDiagnostic(\n nodeId,\n \"instance\",\n \"scaffold render — async bundle fetch + __params.* injection are not yet wired (LSML 1.1 §4.9)\",\n );\n }\n\n const size = resolved.size as { w?: number; h?: number } | undefined;\n const position = resolved.position as { x?: number; y?: number } | undefined;\n\n return (\n <div\n data-lumencast-instance={sceneId}\n data-lumencast-version={sceneVersion}\n style={{\n position: position ? \"absolute\" : \"relative\",\n left: position?.x,\n top: position?.y,\n width: size?.w,\n height: size?.h,\n outline: import.meta.env.DEV ? \"1px dashed rgba(255,180,0,0.5)\" : \"none\",\n boxSizing: \"border-box\",\n }}\n />\n );\n}\n","// Per-device stream cache for `x-zab.capture` ACQUIRE mode.\n//\n// Why this exists: a scene switch remounts the WHOLE render tree\n// (`AnimatePresence` keyed on the scene id in app.tsx / crossfade.tsx), so every\n// `Capture` node unmounts and a fresh one mounts. Without sharing, each switch\n// stops the old node's tracks (RC11) and re-acquires the same physical device in\n// the new node. A real USB webcam reopens near-instantly, but a synthetic\n// DirectShow filter (OBS Virtual Camera) renegotiates slowly → a visible blink\n// on every switch, because — by design (ADR 007 Prism) — every scene references\n// the SAME shared vcam device.\n//\n// The fix mirrors the editor's `use-live-source.ts`: a ref-counted cache keyed by\n// the resolved PHYSICAL device. Two `Capture` nodes on the same device share one\n// `getUserMedia`; tracks stop (RC11) only when the LAST consumer releases. During\n// a crossfade both the exiting and entering scenes are mounted at once\n// (`AnimatePresence mode=\"sync\"`), so the ref-count never reaches 0 across a\n// switch and the device is never renegotiated — no blink.\n//\n// Cache key stability: the key is the resolved `deviceId` / `captureSourceId`, not\n// the raw logical `deviceRef`. Physical ids are salted per origin/partition (see\n// capture.tsx §A1.3), but the salt is constant WITHIN one runtime origin, so the\n// resolved id is stable across scene switches inside a single mount/session — the\n// exact scope over which sharing must hold. Keying on the physical id also\n// correctly de-dupes two distinct `deviceRef`s that resolve to the same device.\n\nimport type { ResolveCaptureDevice } from \"./capture\";\n\ninterface CacheEntry {\n promise: Promise<MediaStream>;\n stream: MediaStream | null;\n refs: number;\n}\n\nconst cache = new Map<string, CacheEntry>();\n\n/** Outcome of a claim: either a shared stream promise (with the key to release\n * later) or PLACEHOLDER — the unknown-kind / declared-but-unresolved-ref path\n * that acquires nothing, exactly as the old inline `acquireStream` returning\n * `null` did. A PLACEHOLDER claim holds NO ref (nothing to release). */\nexport type CaptureClaim =\n | { kind: \"stream\"; key: string; promise: Promise<MediaStream> }\n | { kind: \"placeholder\" };\n\n/** Resolve the device, then claim a shared stream for it (incrementing the\n * ref-count), or return PLACEHOLDER. Awaits the resolver first — physical ids\n * are salted per origin/partition, so the host may re-resolve a portable key\n * (label) against THIS context (capture.tsx §A1.3). A throw from the underlying\n * `getUserMedia` surfaces via the returned promise (caller → PLACEHOLDER). */\nexport async function claimCaptureStream(\n sourceKind: string,\n deviceRef: string,\n resolveCaptureDevice: ResolveCaptureDevice | undefined,\n): Promise<CaptureClaim> {\n const md = navigator.mediaDevices;\n const resolved = (await resolveCaptureDevice?.(deviceRef, sourceKind)) ?? null;\n const deviceId = resolved?.deviceId;\n const captureSourceId = resolved?.captureSourceId;\n const declaredRef = deviceRef.length > 0;\n\n // Compute a stable physical key + a lazy acquisition thunk, or bail to\n // PLACEHOLDER for the same reasons the inline switch used to return `null`.\n let physicalId: string;\n let acquire: () => Promise<MediaStream>;\n switch (sourceKind) {\n case \"media.webcam\":\n case \"media.mic\":\n case \"media.app_audio\": {\n // §A1.3 (amended) — NO default-device fallback for a DECLARED deviceRef\n // that did not resolve. Acquiring the host default here is the silent\n // \"automatic allocation\" of the WRONG camera. → PLACEHOLDER. The bare\n // default constraint stays ONLY when no deviceRef is declared at all.\n if (declaredRef && (typeof deviceId !== \"string\" || deviceId.length === 0)) {\n return { kind: \"placeholder\" };\n }\n const channel = sourceKind === \"media.webcam\" ? \"video\" : \"audio\";\n physicalId = typeof deviceId === \"string\" && deviceId.length > 0 ? deviceId : \"default\";\n acquire = () => md.getUserMedia({ [channel]: deviceConstraint(deviceId) });\n break;\n }\n case \"media.screen\":\n case \"media.window\": {\n // DIRECT capture of the picked desktopCapturer surface (no system picker)\n // via Electron's legacy `chromeMediaSource:desktop` + resolved id.\n if (typeof captureSourceId === \"string\" && captureSourceId.length > 0) {\n physicalId = captureSourceId;\n acquire = () =>\n md.getUserMedia({\n video: {\n mandatory: {\n chromeMediaSource: \"desktop\",\n chromeMediaSourceId: captureSourceId,\n },\n } as unknown as MediaTrackConstraints,\n });\n break;\n }\n // A declared surface ref that didn't resolve → PLACEHOLDER, never a\n // default picker. The picker stays only when no ref is declared.\n if (declaredRef) return { kind: \"placeholder\" };\n physicalId = \"display\";\n acquire = () => md.getDisplayMedia({ video: true });\n break;\n }\n default:\n return { kind: \"placeholder\" };\n }\n\n const key = `${sourceKind}:${physicalId}`;\n const existing = cache.get(key);\n if (existing) {\n existing.refs += 1;\n return { kind: \"stream\", key, promise: existing.promise };\n }\n const promise = acquire();\n const entry: CacheEntry = { promise, stream: null, refs: 1 };\n cache.set(key, entry);\n promise\n .then((s) => {\n entry.stream = s;\n })\n .catch(() => {\n // Acquisition failed — evict so a later mount retries instead of sharing a\n // rejected promise. Consumers of this promise all fall back to PLACEHOLDER.\n cache.delete(key);\n });\n return { kind: \"stream\", key, promise };\n}\n\n/** Drop one consumer's claim. Stops every track (RC11 — kill the device light)\n * ONLY when the last consumer releases. A no-op for an already-evicted key\n * (e.g. an acquisition that rejected and self-evicted). */\nexport function releaseCaptureStream(key: string): void {\n const entry = cache.get(key);\n if (entry === undefined) return;\n entry.refs -= 1;\n if (entry.refs > 0) return;\n cache.delete(key);\n if (entry.stream !== null) stopStream(entry.stream);\n}\n\n/** A `getUserMedia` track constraint. A resolved deviceId is pinned with\n * `exact`, NOT a bare (ideal) deviceId: an *ideal* constraint SILENTLY falls\n * back to the host default camera when the requested device can't start (e.g.\n * an INACTIVE virtual cam enumerated but producing no stream). `exact` yields\n * the requested device (its placeholder frame if idle), or an\n * OverconstrainedError the caller catches into PLACEHOLDER — never the wrong\n * cam. No deviceId → `true` (host default) applies ONLY when no deviceRef was\n * declared. */\nfunction deviceConstraint(deviceId: string | undefined): MediaTrackConstraints | boolean {\n return typeof deviceId === \"string\" && deviceId.length > 0\n ? { deviceId: { exact: deviceId } }\n : true;\n}\n\n/** Stop every track of a stream (RC11 — release the camera/mic, kill the light). */\nfunction stopStream(stream: MediaStream): void {\n for (const track of stream.getTracks()) track.stop();\n}\n\n/** Test-only: drop all cached entries WITHOUT stopping tracks. Lets a test file\n * start from a clean ref-count without leaking state between cases. */\nexport function __resetCaptureStreamCache(): void {\n cache.clear();\n}\n","import { useEffect, useRef, useState } from \"react\";\nimport type { PrimitiveProps } from \"./index\";\nimport { useOptionalLumencastRuntime } from \"../../overlay/runtime-context\";\nimport { claimCaptureStream, releaseCaptureStream } from \"./capture-stream-cache\";\n\n/** `x-zab.capture` — context-aware capture primitive (Zab vendor primitive,\n * RFC-0001 / ADR 004 §Amendment 1).\n *\n * The primitive reserves a box of the declared geometry so downstream layout\n * (siblings, masks, stacks, grids) is unaffected — exactly as an `image` of\n * the same geometry, in BOTH modes below. It picks a mode by **capability\n * detection at mount** (feature detection, not an env flag) :\n *\n * - **ACQUIRE** (capable host, e.g. the Electron preview webview with\n * auto-granted media permissions) : it acquires a live stream itself via\n * `getUserMedia` (webcam/mic) or `getDisplayMedia` (screen/window) per\n * `x-zab.sourceKind`, and renders it in a `<video>` for visual kinds\n * (audio kinds stay visually empty). The physical device is resolved from\n * the LOGICAL `x-zab.deviceRef` through a host-provided resolver\n * (`resolveCaptureDevice`, §A1.3) — never a bundle-baked id. Any failure\n * (no resolver, no device, permission denied, acquisition error) falls\n * back to PLACEHOLDER WITHOUT throwing or blanking the surrounding tree.\n *\n * - **PLACEHOLDER** (non-capable host, e.g. CEF/Pulsar on-air) : the box is\n * fully transparent, acquires nothing, reaches no device — the original\n * §3.2 behaviour. The consuming app composites a native source behind it\n * (ON-AIR PATH UNCHANGED).\n *\n * A stream-less box is a valid mode, not an error : NO diagnostic is emitted\n * for PLACEHOLDER mode or for an ACQUIRE→PLACEHOLDER fallback.\n *\n * Geometry is the only layout input. `width`/`height` are the\n * compiler-flattened `size:{w,h}` ; universal props (visible/opacity/\n * position) are applied by the Tree's UniversalWrapper. An audio-only\n * capture (`media.mic` / `media.app_audio`) may omit `size` → a zero-area\n * box that never paints. */\nexport function Capture({ resolved }: PrimitiveProps) {\n const width = dimOr(resolved.width, \"100%\");\n const height = dimOr(resolved.height, \"100%\");\n const sourceKind =\n typeof resolved[\"x-zab.sourceKind\"] === \"string\"\n ? (resolved[\"x-zab.sourceKind\"] as string)\n : \"\";\n const deviceRef =\n typeof resolved[\"x-zab.deviceRef\"] === \"string\" ? (resolved[\"x-zab.deviceRef\"] as string) : \"\";\n\n // §A1.3 — the host-provided resolver, injected at mount through the runtime\n // context (NOT the bundle, NOT the LSDP wire). Absent when the tree renders\n // outside a host (direct embedding, tooling, tests) → the default-device\n // path applies.\n const runtime = useOptionalLumencastRuntime();\n const resolveCaptureDevice = runtime?.resolveCaptureDevice;\n\n const videoRef = useRef<HTMLVideoElement | null>(null);\n // `null` → PLACEHOLDER (non-capable, or ACQUIRE→PLACEHOLDER fallback).\n // A `MediaStream` → ACQUIRE succeeded and a visual stream is mounted.\n const [stream, setStream] = useState<MediaStream | null>(null);\n\n useEffect(() => {\n // §A1.2(2) — capability detection at mount. A non-capable host (no\n // `getUserMedia`, e.g. CEF/Pulsar on-air, or jsdom without a mock) stays\n // in PLACEHOLDER : acquire nothing, no diagnostic.\n if (!isCaptureCapable()) return;\n\n let cancelled = false;\n // The cache key of the claim we hold, so cleanup releases exactly one ref.\n let claimedKey: string | null = null;\n\n void (async () => {\n try {\n // Claim a per-device shared stream (ref-counted): a scene switch that\n // remounts a Capture on the SAME device reuses the live stream instead\n // of stopping and re-acquiring it — the vcam-blink fix.\n const claim = await claimCaptureStream(sourceKind, deviceRef, resolveCaptureDevice);\n if (claim.kind === \"placeholder\") return; // unknown/unresolved → PLACEHOLDER\n const media = await claim.promise;\n if (cancelled) {\n // Unmounted (or scene-changed) during acquisition — drop our claim.\n // The shared stream stays alive if another consumer still holds it,\n // and stops (RC11) only when the last one releases.\n releaseCaptureStream(claim.key);\n return;\n }\n claimedKey = claim.key;\n setStream(media);\n } catch {\n // §A1.2(2)(a) — any acquisition failure (permission denied, no device,\n // getUserMedia rejected) falls back to PLACEHOLDER, no throw, no\n // diagnostic. The rejected cache entry self-evicts; our ref went with it.\n }\n })();\n\n return () => {\n cancelled = true;\n // RC11 — release our claim at unmount / scene change. Tracks stop only\n // when this was the last consumer of the shared stream.\n if (claimedKey !== null) releaseCaptureStream(claimedKey);\n };\n // Re-acquire when the logical source identity changes (a scene switch can\n // reuse the node with a new sourceKind/deviceRef).\n }, [sourceKind, deviceRef, resolveCaptureDevice]);\n\n // Attach / detach the live stream to the <video> element imperatively —\n // `srcObject` is not a serialisable attribute.\n useEffect(() => {\n const el = videoRef.current;\n if (el === null) return;\n el.srcObject = stream;\n return () => {\n if (el !== null) el.srcObject = null;\n };\n }, [stream]);\n\n // ACQUIRE with a visual stream → render the <video>. Audio-only kinds keep\n // the transparent box (no visible element) even when acquired.\n if (stream !== null && isVisualKind(sourceKind)) {\n return (\n <video\n ref={videoRef}\n data-lumencast-capture\n autoPlay\n muted\n playsInline\n style={{ width, height, objectFit: \"cover\", pointerEvents: \"none\" }}\n />\n );\n }\n\n // PLACEHOLDER (or audio-only ACQUIRE) — fully transparent, inert box.\n return (\n <div\n aria-hidden\n data-lumencast-capture\n style={{ width, height, opacity: 0, pointerEvents: \"none\" }}\n />\n );\n}\n\n/** A resolved physical device for a live capture constraint, or `null` when the\n * host could not bind the logical `deviceRef`. */\nexport type ResolvedCaptureDevice = {\n deviceId?: string;\n captureSourceId?: string;\n} | null;\n\n/** Resolver injected by the consuming app (ADR 004 §A1.3). Maps the LOGICAL\n * `deviceRef` to a physical `deviceId`/`captureSourceId` for a live\n * `getUserMedia` constraint. The result NEVER enters the bundle or the content\n * hash. MAY be async: physical ids (e.g. getUserMedia `deviceId`) are salted\n * per origin/partition, so the host often must re-resolve a portable key\n * (label) against THIS context's devices — an inherently asynchronous step\n * (`enumerateDevices`). `claimCaptureStream` awaits it, so the device is bound\n * before acquisition rather than racing a late global mutation. */\nexport type ResolveCaptureDevice = (\n deviceRef: string,\n sourceKind: string,\n) => ResolvedCaptureDevice | Promise<ResolvedCaptureDevice>;\n\n/** §A1.2(2) — capture-capable iff `navigator.mediaDevices.getUserMedia`\n * exists and is callable in the current context. Feature detection only ;\n * CEF/Pulsar on-air and jsdom (without a mock) report non-capable. */\nfunction isCaptureCapable(): boolean {\n return (\n typeof navigator !== \"undefined\" && typeof navigator.mediaDevices?.getUserMedia === \"function\"\n );\n}\n\n/** Visual kinds render a `<video>` ; audio kinds stay visually empty. */\nfunction isVisualKind(sourceKind: string): boolean {\n return (\n sourceKind === \"media.webcam\" || sourceKind === \"media.screen\" || sourceKind === \"media.window\"\n );\n}\n\n/** A render dimension: a finite number → px, a non-empty string → verbatim,\n * anything else → the fallback (matches the `image` primitive's helper). */\nfunction dimOr(v: unknown, fallback: string): string {\n if (typeof v === \"number\" && Number.isFinite(v)) return `${v}px`;\n if (typeof v === \"string\" && v.length > 0) return v;\n return fallback;\n}\n","// Primitive component registry. Tree dispatch uses this map to look\n// up the React component for each `kind` ; user components are inlined\n// at compile time so Lumencast's runtime never sees them.\n\nimport type { ComponentType, ReactNode } from \"react\";\nimport type { RenderKind } from \"../bundle\";\nimport type { Transition } from \"../../animate/transitions\";\nimport { Stack } from \"./stack\";\nimport { Grid } from \"./grid\";\nimport { Frame } from \"./frame\";\nimport { Text } from \"./text\";\nimport { Image } from \"./image\";\nimport { Shape } from \"./shape\";\nimport { Media } from \"./media\";\nimport { MeetPeer } from \"./meet-peer\";\nimport { MeetPeerSlot } from \"./meet-peer-slot\";\nimport { Instance } from \"./instance\";\nimport { Capture } from \"./capture\";\n// `repeat` is dispatched specially in the tree (it iterates a bound\n// array and provides a path scope to its children) ; it does not\n// appear here as a regular primitive.\n\nexport interface PrimitiveProps {\n resolved: Record<string, unknown>;\n /** `RenderNode.id` of the node being rendered — threaded into every\n * diagnostic the primitive emits (ADR 001 RC#7, issue #34). */\n nodeId?: string;\n transitionFor: (key: string) => Transition | undefined;\n /** LSML 1.1 `animate.from` lowered to a flat framer `initial` map\n * (keys: `opacity`, `scale`, `rotate`, `x`, `y`). When present, a\n * motion primitive passes it as framer-motion `initial={...}` so the\n * element mounts in this state and animates to its rendered target on\n * mount (mount-play). `undefined` → no `initial` (no mount-play). */\n animateInitial?: Record<string, number | string>;\n /** ADR 002 §3.1 (D1) — set by the Tree when this node has at least one\n * absolutely positioned child. A layout container (`stack`/`grid`)\n * flips to `position: relative` so its children's `left/top` resolve\n * against it. `frame` is already `position: absolute` (a containing\n * block) and ignores it ; leaf primitives have no children and ignore\n * it too. `false`/absent → no change (pure auto-layout, RC#2). */\n establishesContainingBlock?: boolean;\n children?: ReactNode;\n}\n\nexport const PRIMITIVES: Partial<Record<RenderKind, ComponentType<PrimitiveProps>>> = {\n stack: Stack,\n grid: Grid,\n frame: Frame,\n text: Text,\n image: Image,\n shape: Shape,\n media: Media,\n // ADR 006 §3.3/§3.5 — the unified source kind : every exported source is a\n // `meet.peer` node rendered in `<video srcObject>` from the WebRTC viewer.\n \"meet.peer\": MeetPeer,\n instance: Instance,\n // RFC-0001 / ADR 004 — Zab vendor capture placeholder (transparent, inert).\n \"x-zab.capture\": Capture,\n // ADR Blue 009 §3.1 (Amendment 2) — Zab vendor meet-peer SLOT placeholder.\n // Carries only a logical `x-zab.slotRef` ; the host's slot-aware peer-stream\n // registry resolves `slotRef → peer_label → MediaStream` (transparent when\n // unbound). Closes the kind→primitive gap that left it an unknown-kind drop.\n \"x-zab.meet-peer\": MeetPeerSlot,\n};\n","import { createContext, useContext, type ReactNode } from \"react\";\n\n/** Path-scope context. Children inside a `repeat` get a `prefix` that\n * is prepended to their declared bindings, so a single template can\n * bind to per-item paths like `items.{i}.score`. */\nconst PathScopeContext = createContext<string>(\"\");\n\nexport function PathScopeProvider({ prefix, children }: { prefix: string; children: ReactNode }) {\n const parent = useContext(PathScopeContext);\n const next = parent ? `${parent}.${prefix}` : prefix;\n return <PathScopeContext.Provider value={next}>{children}</PathScopeContext.Provider>;\n}\n\n/** Returns the current path prefix, or \"\" if there is no scope. */\nexport function usePathScope(): string {\n return useContext(PathScopeContext);\n}\n\n/** Resolve a binding path under the current scope. */\nexport function scopedPath(prefix: string, path: string): string {\n if (!prefix) return path;\n // Path may itself start with a literal prefix (e.g. `__system.*`),\n // which should NOT be scoped — only paths that are clearly relative\n // get prefixed.\n if (path.startsWith(\"__\")) return path;\n return `${prefix}.${path}`;\n}\n","// Universal-props wrapper (LSML 1.1 §5.4).\n//\n// Every primitive renders inside this wrapper, which applies the\n// universal props uniformly :\n//\n// - `visible: false` → display: none (slot collapses in flex layouts)\n// - `opacity` → CSS opacity, multiplicative with whatever animation\n// a primitive may apply via framer-motion (browsers compose them)\n// - `rotation` → CSS transform: rotate(<deg>)\n// - `sizing.x`/`sizing.y` → flex shorthand on the wrapping div, lets\n// a primitive participate in its parent flex layout's auto-sizing\n// - `position.{x,y}` → absolute placement relative to the nearest\n// positioned ancestor (ADR 002 §3.1 / D1) : a child carrying\n// `position` is taken out of the normal flow and pinned at\n// `left:x; top:y`. A child WITHOUT `position` keeps the normal flow\n// untouched (auto-layout intact) — this is the Figma free-form vs\n// auto-layout duality, honoured at render. `size.{w,h}` fixes the\n// absolute box (the rating square's 24×7 / 14×22 text boxes) ;\n// omitted → hug the content. Position is a static layout property and\n// never animates (it stays off the 0-layout-event broadcast hot path).\n//\n// `bindUniversal` is resolved by the Tree renderer before the wrapper\n// sees its values, so this component only deals with concrete numbers\n// and booleans.\n\nimport type { ReactNode, CSSProperties } from \"react\";\n\nimport { parseBlendMode } from \"./blend-mode\";\n\nexport type SizingMode = \"fixed\" | \"hug\" | \"fill\";\n\nexport interface UniversalProps {\n visible?: boolean;\n opacity?: number;\n rotation?: number;\n /** Mirror across the local X axis (Figma `scaleY(-1)`, negative-determinant\n * transform). Composed with `rotation` on the wrapper so image/shape leaves\n * mirror like frames do — without it the caramel 3d-render rendered as the\n * un-mirrored wave (blue where Figma is orange). */\n flipY?: boolean;\n /** Figma LAYER_BLUR radius (px) → CSS `filter: blur()`. */\n blur?: number;\n sizing?: { x?: SizingMode; y?: SizingMode };\n /** ADR 002 §3.1 (D1) — parent-relative absolute placement. When set,\n * the wrapper pins the primitive at `left:x; top:y` (position:absolute)\n * instead of leaving it in the normal flow. Both axes are required\n * (the Tree only forms this object from a finite `{x,y}` pair). */\n position?: { x: number; y: number };\n /** ADR 002 §3.1 (D1) — the absolute box's fixed size, applied only\n * alongside `position`. Omitted → the box hugs its content. */\n size?: { w?: number; h?: number };\n /** ADR 002 §3.2 (D2 / #D) — a Figma blend mode → CSS `mix-blend-mode`.\n * The value is re-validated against the closed enum at render\n * (`parseBlendMode`, T4 double-gate) ; anything outside the allowlist\n * is omitted, never written to the style. */\n blendMode?: string;\n}\n\nexport interface UniversalWrapperProps extends UniversalProps {\n children: ReactNode;\n}\n\n/**\n * Maps a SizingMode onto a flex shorthand. Per LSML 1.1 §5.4.1 :\n * - fixed : the primitive honours its declared size verbatim\n * - hug : the primitive shrinks to its intrinsic content size\n * - fill : the primitive grows to fill available space\n */\nfunction flexFor(mode: SizingMode | undefined): string | undefined {\n switch (mode) {\n case \"fixed\":\n return \"0 0 auto\";\n case \"hug\":\n return \"0 1 auto\";\n case \"fill\":\n return \"1 1 auto\";\n default:\n return undefined;\n }\n}\n\n/** Collapse a {x,y} sizing pair to a single `flex` shorthand. When both axes\n * agree, that value ; otherwise honour x (horizontal stacks dominate broadcast\n * boards — the renderer doesn't know the parent's axis here). */\nfunction sizingToFlex(sizing: { x?: SizingMode; y?: SizingMode } | undefined): string | undefined {\n const x = flexFor(sizing?.x);\n const y = flexFor(sizing?.y);\n if (x === y && x !== undefined) return x;\n return x ?? y;\n}\n\nexport function UniversalWrapper({\n visible,\n opacity,\n rotation,\n flipY,\n blur,\n sizing,\n position,\n size,\n blendMode,\n children,\n}: UniversalWrapperProps) {\n if (visible === false) {\n return null; // slot collapses in flex/grid layouts (§5.4)\n }\n\n // ADR 002 §3.2 (D2 / #D) — re-validate the blend mode against the\n // closed enum at render (T4 runtime gate). A recognised mode yields a\n // CSS `mix-blend-mode` keyword ; anything else is `undefined` and never\n // reaches the style (no free CSS string, no passthrough).\n const mixBlendMode = parseBlendMode(blendMode);\n // No-op fast path — when no universal props are set, render children\n // directly. Lets simple bundles avoid an extra DOM node per primitive.\n // A child WITHOUT `position` never enters the absolute branch, so the\n // normal flow (auto-layout) is left exactly as before (ADR 002 §3.1\n // non-regression : RC#2).\n const hasOpacity = typeof opacity === \"number\" && opacity !== 1;\n const hasRotation = typeof rotation === \"number\" && rotation !== 0;\n const hasFlipY = flipY === true;\n const hasBlur = typeof blur === \"number\" && blur > 0;\n const hasSizing = sizing?.x !== undefined || sizing?.y !== undefined;\n const hasPosition = position !== undefined;\n const hasBlendMode = mixBlendMode !== undefined;\n if (\n !hasOpacity &&\n !hasRotation &&\n !hasFlipY &&\n !hasBlur &&\n !hasSizing &&\n !hasPosition &&\n !hasBlendMode\n ) {\n return <>{children}</>;\n }\n\n // Build the transform string (rotation + mirror). `rotate(θ) scaleY(-1)`\n // applies the mirror first (rightmost), then the rotation — matching Figma's\n // `rotate·scaleY(-1)` matrix (the caramel's −114° + mirror).\n let transform: string | undefined;\n if (hasRotation || hasFlipY) {\n const parts: string[] = [];\n if (hasRotation) parts.push(`rotate(${rotation}deg)`);\n if (hasFlipY) parts.push(\"scaleY(-1)\");\n transform = parts.join(\" \");\n }\n // Figma LAYER_BLUR → CSS blur (radius ≈ 2× the CSS sigma, measured on 817:3).\n // (A gamma-correct linearRGB blur was tried to close the bg-shine corner's ~23 R\n // deficit vs the Figma PNG ; it measured WORSE — the deficit is in the high-R\n // channel, which is gamma-INVARIANT — and supersampling the render closed that\n // corner anyway. The Chromium(sRGB)≠Figma(linearRGB) blur gap is else irreducible.)\n const filter = hasBlur ? `blur(${blur / 2}px)` : undefined;\n\n const sizingFlex = hasSizing ? sizingToFlex(sizing) : undefined;\n\n // A `mix-blend-mode` composites with the SCENE backdrop only when its element\n // does not also form an isolating group. `transform`, `opacity < 1` and\n // `filter` each force the element into its own group, so the blend would fold\n // over a TRANSPARENT backdrop instead — the caramel hard-light then shows the\n // raw blue wave rather than compositing over the warm gradient, a screen layer\n // silently no-ops. When the node needs BOTH a blend and one of those, SPLIT:\n // the blend (+ absolute placement) lives on the OUTER box, the isolating\n // transform/opacity/blur on an INNER box that carries the sized content.\n if (hasBlendMode && (hasOpacity || transform !== undefined || filter !== undefined)) {\n const outer: CSSProperties = { mixBlendMode: mixBlendMode as CSSProperties[\"mixBlendMode\"] };\n if (hasPosition) {\n outer.position = \"absolute\";\n outer.left = position.x;\n outer.top = position.y;\n }\n if (sizingFlex !== undefined) outer.flex = sizingFlex;\n const inner: CSSProperties = {};\n if (typeof size?.w === \"number\") inner.width = size.w;\n if (typeof size?.h === \"number\") inner.height = size.h;\n if (hasOpacity) inner.opacity = opacity;\n if (transform !== undefined) inner.transform = transform;\n if (filter !== undefined) inner.filter = filter;\n return (\n <div style={outer}>\n <div style={inner}>{children}</div>\n </div>\n );\n }\n\n const style: CSSProperties = {};\n if (hasOpacity) style.opacity = opacity;\n if (transform !== undefined) style.transform = transform;\n if (filter !== undefined) style.filter = filter;\n if (hasBlendMode) style.mixBlendMode = mixBlendMode as CSSProperties[\"mixBlendMode\"];\n // ADR 002 §3.1 (D1) — absolute placement relative to the nearest positioned\n // ancestor. `size` (when present) fixes the box ; otherwise it hugs content.\n if (hasPosition) {\n style.position = \"absolute\";\n style.left = position.x;\n style.top = position.y;\n if (typeof size?.w === \"number\") style.width = size.w;\n if (typeof size?.h === \"number\") style.height = size.h;\n }\n if (sizingFlex !== undefined) style.flex = sizingFlex;\n\n return <div style={style}>{children}</div>;\n}\n","// LSML 1.1 §6.6 — keyframe sequence playback.\n//\n// A primitive's `keyframes` block describes a path through animatable\n// property values over time, applied once on (re)mount or whenever the\n// `key` LeafPath value changes. The shapes here mirror the spec verbatim\n// ; `compileForFramer` flattens them into the per-property arrays\n// (`scale: [0.8, 1.05, 1]`) plus `times: [0, 0.6, 1]` that framer-motion\n// expects on its `animate` / `transition` props.\n\nimport {\n FILTER_IDENTITY,\n sanitizeCssFilterString,\n warnRejectedFilter,\n} from \"../render/filter-clamp\";\n\nexport type KeyframeEasing = \"linear\" | \"ease-in\" | \"ease-out\" | \"ease-in-out\";\n\nexport interface KeyframeStep {\n /** Timeline position in [0, 1]. First step is 0 ; last step is 1. */\n at: number;\n /** Optional transform target at this waypoint. */\n transform?: KeyframeTransform;\n /** Optional opacity in [0, 1]. */\n opacity?: number;\n /** Optional CSS filter string. */\n filter?: string;\n}\n\nexport interface KeyframeTransform {\n scale?: number;\n translateX?: number;\n translateY?: number;\n rotate?: number;\n}\n\nexport interface Keyframes {\n /** LeafPath whose value-change replays the sequence. Omitted = mount-only. */\n key?: string;\n steps: KeyframeStep[];\n duration_ms: number;\n easing?: KeyframeEasing;\n}\n\nconst FRAMER_EASE_MAP: Record<KeyframeEasing, \"linear\" | \"easeIn\" | \"easeOut\" | \"easeInOut\"> = {\n linear: \"linear\",\n \"ease-in\": \"easeIn\",\n \"ease-out\": \"easeOut\",\n \"ease-in-out\": \"easeInOut\",\n};\n\nexport interface CompiledKeyframes {\n /** Per-CSS-property animate target (array of values, one per step). */\n animate: Record<string, (number | string)[]>;\n /** Framer transition config — duration in seconds, ease curve, times[]. */\n transition: {\n duration: number;\n ease: \"linear\" | \"easeIn\" | \"easeOut\" | \"easeInOut\";\n times: number[];\n };\n}\n\n/**\n * Flatten a 1.1 keyframe sequence into the per-property arrays + times[]\n * shape framer-motion expects. Returns `undefined` when `steps` is empty\n * or invariants are violated (first.at !== 0 or last.at !== 1) — the\n * caller then falls back to no animation.\n */\nexport function compileForFramer(kf: Keyframes, nodeId?: string): CompiledKeyframes | undefined {\n const steps = kf.steps;\n if (!Array.isArray(steps) || steps.length < 2) return undefined;\n const first = steps[0];\n const last = steps[steps.length - 1];\n if (first.at !== 0 || last.at !== 1) return undefined;\n\n const times = steps.map((s) => s.at);\n const animate: Record<string, (number | string)[]> = {};\n\n // For each animatable property, pull the value at every step. When a\n // step omits the property, we fall back to the previous step's value\n // (last-known-good) so framer-motion sees a coherent waypoint chain.\n pullChannel(steps, \"opacity\", animate, nodeId);\n pullChannel(steps, \"filter\", animate, nodeId);\n pullTransform(steps, \"scale\", animate);\n pullTransform(steps, \"translateX\", animate);\n pullTransform(steps, \"translateY\", animate);\n pullTransform(steps, \"rotate\", animate);\n\n return {\n animate,\n transition: {\n duration: kf.duration_ms / 1000,\n ease: FRAMER_EASE_MAP[kf.easing ?? \"linear\"],\n times,\n },\n };\n}\n\nfunction pullChannel(\n steps: KeyframeStep[],\n prop: \"opacity\" | \"filter\",\n out: Record<string, (number | string)[]>,\n nodeId?: string,\n): void {\n let any = false;\n const values: (number | string)[] = [];\n let last: number | string | undefined;\n for (const s of steps) {\n let v: number | string | undefined = s[prop];\n // R8 runtime half (ADR 001 §5.1, issue #42) — keyframe filter\n // strings in a hand-crafted bundle bypass the compiler clamps.\n // Re-gate here ; rejected → treat as omitted (last-known-good).\n if (prop === \"filter\" && v !== undefined) {\n const safe = sanitizeCssFilterString(v);\n if (safe === null) {\n warnRejectedFilter(\"keyframes.steps[].filter\", nodeId);\n v = undefined;\n } else {\n v = safe;\n }\n }\n if (v !== undefined) {\n any = true;\n last = v;\n values.push(v);\n } else {\n values.push(last ?? (prop === \"opacity\" ? 1 : FILTER_IDENTITY));\n }\n }\n if (any) out[prop] = values;\n}\n\nfunction pullTransform(\n steps: KeyframeStep[],\n prop: keyof KeyframeTransform,\n out: Record<string, (number | string)[]>,\n): void {\n let any = false;\n const values: number[] = [];\n let last: number | undefined;\n for (const s of steps) {\n const v = s.transform?.[prop];\n if (typeof v === \"number\") {\n any = true;\n last = v;\n values.push(v);\n } else {\n values.push(last ?? defaultFor(prop));\n }\n }\n if (any) {\n if (prop === \"rotate\") {\n out.rotate = values.map((n) => `${n}deg`);\n } else {\n // ADR 011 I7 live-bug fix (2nd half): framer-motion animates transform\n // through its shorthand motion keys `x`/`y`, NOT `translateX`/`translateY`\n // — emitting the authored names verbatim left framer with unknown keys\n // it silently dropped, so the box never translated at the antenna (only\n // the opacity fade survived). Map the translate channels onto the framer\n // keys. `scale`/`rotate` already match framer's vocabulary.\n const framerKey = prop === \"translateX\" ? \"x\" : prop === \"translateY\" ? \"y\" : prop;\n out[framerKey] = values;\n }\n }\n}\n\nfunction defaultFor(prop: keyof KeyframeTransform): number {\n return prop === \"scale\" ? 1 : 0;\n}\n","// LSML 1.1 §6.7 — stagger context.\n//\n// `repeat.stagger_ms` produces wave-like reveals : iteration N's\n// animations start `N * stagger_ms` after iteration 0. The Repeat\n// renderer computes the per-iteration delay and threads it through\n// React context so KeyframePlayer (and future animate-aware primitives)\n// can pick it up without per-primitive wiring.\n\nimport { createContext } from \"react\";\n\n/** Per-iteration stagger delay in milliseconds. `0` means no offset\n * (the implicit default outside a staggered repeat). */\nexport const StaggerContext = createContext<number>(0);\n\n/** Spec hint : runtimes MAY cap effective stagger to avoid pathological\n * wait times on large lists. We cap at 2 s. */\nexport const STAGGER_CAP_MS = 2000;\n\n/** Compute the effective per-iteration delay, applying the runtime cap. */\nexport function computeStaggerDelayMs(index: number, staggerMs: number): number {\n if (staggerMs <= 0) return 0;\n const raw = index * staggerMs;\n return raw > STAGGER_CAP_MS ? STAGGER_CAP_MS : raw;\n}\n","// LSML 1.1 §6.6 — keyframe sequence playback wrapper.\n//\n// Wraps a primitive subtree in a framer-motion `motion.div` that plays\n// out the compiled keyframe arrays once on (re)mount, or whenever the\n// bound `key` LeafPath changes. We trigger replay via React's `key=`\n// reconciliation — bumping a counter when the keyframe key value flips\n// remounts the motion subtree, restarting the animation from `at: 0`.\n//\n// LSML 1.1 §6.7 — when this player runs inside a `repeat` iteration, a\n// `staggerDelay` (ms) is provided through `StaggerContext` and added to\n// framer's transition.delay so each iteration starts `index * stagger_ms`\n// after the previous one.\n\nimport { motion } from \"framer-motion\";\nimport { useContext, useEffect, useRef, type ReactNode } from \"react\";\nimport { useSignals } from \"@preact/signals-react/runtime\";\nimport type { Store } from \"../state/store\";\nimport { compileForFramer, type Keyframes } from \"../animate/keyframes\";\nimport { StaggerContext } from \"./stagger-context\";\nimport { scopedPath, usePathScope } from \"./scope\";\n\nexport interface KeyframePlayerProps {\n keyframes: Keyframes;\n store: Store;\n /** `RenderNode.id` of the owning node — threaded into keyframe\n * diagnostics (ADR 001 RC#7, issue #34). */\n nodeId?: string;\n children: ReactNode;\n}\n\nexport function KeyframePlayer({\n keyframes,\n store,\n nodeId,\n children,\n}: KeyframePlayerProps): ReactNode {\n useSignals();\n const scope = usePathScope();\n const staggerDelayMs = useContext(StaggerContext);\n\n // Pull the latest `key` LeafPath value and remount whenever it\n // changes. We track via a ref + counter so React's reconciliation\n // gives us a fresh motion.div (and thus a fresh animation pass).\n const lastKeyValue = useRef<unknown>(undefined);\n const replayTokenRef = useRef(0);\n if (keyframes.key !== undefined) {\n const v = store.signal(scopedPath(scope, keyframes.key)).value;\n if (lastKeyValue.current !== v) {\n lastKeyValue.current = v;\n replayTokenRef.current += 1;\n }\n }\n\n const compiled = compileForFramer(keyframes, nodeId);\n if (!compiled) {\n return <>{children}</>;\n }\n\n const transition =\n staggerDelayMs > 0\n ? { ...compiled.transition, delay: staggerDelayMs / 1000 }\n : compiled.transition;\n\n return (\n <motion.div\n key={replayTokenRef.current}\n // A `display:contents` element generates NO box, so the browser\n // never composites the animated `transform`/`opacity`/`filter` this\n // player writes — they are silently dropped and the subtree renders\n // dead at its child's default origin (ADR 011 I7 live bug). The\n // player must be a REAL compositing box. `position:absolute; inset:0`\n // overlays the parent without disturbing sibling layout, and — being\n // positioned — becomes the containing block for the absolutely-\n // positioned primitive nested beneath it (Frame is `position:absolute;\n // left:0; top:0`), so the child's authored `x`/`y` resolve against the\n // player's (0,0) exactly as they did against the grandparent under\n // `display:contents`. The animated channels now composite onto a live\n // box and the whole subtree (the nested target's geometry + fill)\n // moves and fades with the keyframes.\n style={{ position: \"absolute\", inset: 0 }}\n initial={firstFrame(compiled.animate)}\n animate={compiled.animate}\n transition={transition}\n >\n <ReplayOnMount />\n {children}\n </motion.div>\n );\n}\n\n/** No-op effect placeholder — kept for symmetry / future hooks like\n * reporting playback completion to the renderer. */\nfunction ReplayOnMount(): null {\n useEffect(() => {\n // intentional no-op\n }, []);\n return null;\n}\n\n/** Pluck the `at: 0` waypoint values into a framer-motion `initial` prop\n * so the very first frame matches the start of the keyframe path. Without\n * this, framer interpolates from the element's current style which can\n * produce a visible jump on mount. */\nfunction firstFrame(animate: Record<string, (number | string)[]>): Record<string, number | string> {\n const out: Record<string, number | string> = {};\n for (const [k, arr] of Object.entries(animate)) {\n if (arr.length > 0) out[k] = arr[0];\n }\n return out;\n}\n","// Per-frame delta coalescing (ADR 001 RC#13 — bindAnimate anti-DoS).\n//\n// A live LSDP producer may push deltas at arbitrary frequency (the\n// threat model assumes 1 kHz). Retargeting a Framer animation per delta\n// would start hundreds of redundant animations per displayed frame. The\n// coalescer buffers the LATEST value per binding key and flushes once\n// per animation frame : one retarget max per rAF per binding,\n// independently of the producer's rate.\n//\n// Pure scheduling logic, injectable rAF — unit-testable without a\n// browser loop.\n\nexport interface FrameCoalescer {\n /** Buffer `value` for `key` ; schedules a flush on the next frame.\n * Multiple pushes on the same key within one frame keep only the\n * last value (the previous targets are obsolete by construction). */\n push(key: string, value: unknown): void;\n /** Cancel any scheduled flush and drop pending values. */\n dispose(): void;\n}\n\ntype Schedule = (cb: () => void) => number;\ntype Cancel = (id: number) => void;\n\nexport function createFrameCoalescer(\n flush: (key: string, value: unknown) => void,\n schedule: Schedule = (cb) => requestAnimationFrame(cb),\n cancel: Cancel = (id) => cancelAnimationFrame(id),\n): FrameCoalescer {\n const pending = new Map<string, unknown>();\n let frameId: number | null = null;\n let disposed = false;\n\n const onFrame = (): void => {\n frameId = null;\n // Swap-before-flush : a push() re-entrant from a flush callback\n // lands in a fresh map and schedules the NEXT frame (never the\n // current one) — the one-retarget-per-rAF bound holds.\n const entries = [...pending.entries()];\n pending.clear();\n for (const [key, value] of entries) {\n flush(key, value);\n }\n };\n\n return {\n push(key, value): void {\n if (disposed) return;\n pending.set(key, value);\n if (frameId === null) {\n frameId = schedule(onFrame);\n }\n },\n dispose(): void {\n disposed = true;\n pending.clear();\n if (frameId !== null) {\n cancel(frameId);\n frameId = null;\n }\n },\n };\n}\n","// sRGB colour interpolation (LSML 1.1 §6.5) — issue #33.\n//\n// Both endpoints of a colour animation are first CANONICALISED through\n// the strict shared parser (`parseCssColor`, css-color.ts — ADR 001\n// RC#11/RC#12, never a raw string), then converted to RGBA channels in\n// [0, 1] and interpolated component-wise :\n//\n// out_c = a_c + t * (b_c - a_c) for c ∈ {r, g, b, a}\n//\n// with `t` produced by the easing curve. The output is serialised back\n// to `rgba()` form — which itself round-trips through `parseCssColor`\n// at the consuming primitive (belt and braces).\n//\n// All conversions are constant-time per value (the parser already\n// bounds inputs to 64 chars) ; the named-colour table is a flat map\n// lookup.\n\nimport { parseCssColor } from \"./css-color\";\n\n/** RGBA channels, each in [0, 1]. */\nexport type Rgba = readonly [number, number, number, number];\n\n// CSS Color 4 §6.1 named colours → packed 0xRRGGBB. Kept numeric (not\n// hex strings) to minimise bundle weight ; the set of NAMES here is\n// exactly the set accepted by css-color.ts (`transparent` and\n// `currentcolor` are handled separately — `currentcolor` cannot be\n// interpolated without computed-style context and is rejected).\nconst NAMED_RGB: Record<string, number> = {\n aliceblue: 0xf0f8ff,\n antiquewhite: 0xfaebd7,\n aqua: 0x00ffff,\n aquamarine: 0x7fffd4,\n azure: 0xf0ffff,\n beige: 0xf5f5dc,\n bisque: 0xffe4c4,\n black: 0x000000,\n blanchedalmond: 0xffebcd,\n blue: 0x0000ff,\n blueviolet: 0x8a2be2,\n brown: 0xa52a2a,\n burlywood: 0xdeb887,\n cadetblue: 0x5f9ea0,\n chartreuse: 0x7fff00,\n chocolate: 0xd2691e,\n coral: 0xff7f50,\n cornflowerblue: 0x6495ed,\n cornsilk: 0xfff8dc,\n crimson: 0xdc143c,\n cyan: 0x00ffff,\n darkblue: 0x00008b,\n darkcyan: 0x008b8b,\n darkgoldenrod: 0xb8860b,\n darkgray: 0xa9a9a9,\n darkgreen: 0x006400,\n darkgrey: 0xa9a9a9,\n darkkhaki: 0xbdb76b,\n darkmagenta: 0x8b008b,\n darkolivegreen: 0x556b2f,\n darkorange: 0xff8c00,\n darkorchid: 0x9932cc,\n darkred: 0x8b0000,\n darksalmon: 0xe9967a,\n darkseagreen: 0x8fbc8f,\n darkslateblue: 0x483d8b,\n darkslategray: 0x2f4f4f,\n darkslategrey: 0x2f4f4f,\n darkturquoise: 0x00ced1,\n darkviolet: 0x9400d3,\n deeppink: 0xff1493,\n deepskyblue: 0x00bfff,\n dimgray: 0x696969,\n dimgrey: 0x696969,\n dodgerblue: 0x1e90ff,\n firebrick: 0xb22222,\n floralwhite: 0xfffaf0,\n forestgreen: 0x228b22,\n fuchsia: 0xff00ff,\n gainsboro: 0xdcdcdc,\n ghostwhite: 0xf8f8ff,\n gold: 0xffd700,\n goldenrod: 0xdaa520,\n gray: 0x808080,\n green: 0x008000,\n greenyellow: 0xadff2f,\n grey: 0x808080,\n honeydew: 0xf0fff0,\n hotpink: 0xff69b4,\n indianred: 0xcd5c5c,\n indigo: 0x4b0082,\n ivory: 0xfffff0,\n khaki: 0xf0e68c,\n lavender: 0xe6e6fa,\n lavenderblush: 0xfff0f5,\n lawngreen: 0x7cfc00,\n lemonchiffon: 0xfffacd,\n lightblue: 0xadd8e6,\n lightcoral: 0xf08080,\n lightcyan: 0xe0ffff,\n lightgoldenrodyellow: 0xfafad2,\n lightgray: 0xd3d3d3,\n lightgreen: 0x90ee90,\n lightgrey: 0xd3d3d3,\n lightpink: 0xffb6c1,\n lightsalmon: 0xffa07a,\n lightseagreen: 0x20b2aa,\n lightskyblue: 0x87cefa,\n lightslategray: 0x778899,\n lightslategrey: 0x778899,\n lightsteelblue: 0xb0c4de,\n lightyellow: 0xffffe0,\n lime: 0x00ff00,\n limegreen: 0x32cd32,\n linen: 0xfaf0e6,\n magenta: 0xff00ff,\n maroon: 0x800000,\n mediumaquamarine: 0x66cdaa,\n mediumblue: 0x0000cd,\n mediumorchid: 0xba55d3,\n mediumpurple: 0x9370db,\n mediumseagreen: 0x3cb371,\n mediumslateblue: 0x7b68ee,\n mediumspringgreen: 0x00fa9a,\n mediumturquoise: 0x48d1cc,\n mediumvioletred: 0xc71585,\n midnightblue: 0x191970,\n mintcream: 0xf5fffa,\n mistyrose: 0xffe4e1,\n moccasin: 0xffe4b5,\n navajowhite: 0xffdead,\n navy: 0x000080,\n oldlace: 0xfdf5e6,\n olive: 0x808000,\n olivedrab: 0x6b8e23,\n orange: 0xffa500,\n orangered: 0xff4500,\n orchid: 0xda70d6,\n palegoldenrod: 0xeee8aa,\n palegreen: 0x98fb98,\n paleturquoise: 0xafeeee,\n palevioletred: 0xdb7093,\n papayawhip: 0xffefd5,\n peachpuff: 0xffdab9,\n peru: 0xcd853f,\n pink: 0xffc0cb,\n plum: 0xdda0dd,\n powderblue: 0xb0e0e6,\n purple: 0x800080,\n rebeccapurple: 0x663399,\n red: 0xff0000,\n rosybrown: 0xbc8f8f,\n royalblue: 0x4169e1,\n saddlebrown: 0x8b4513,\n salmon: 0xfa8072,\n sandybrown: 0xf4a460,\n seagreen: 0x2e8b57,\n seashell: 0xfff5ee,\n sienna: 0xa0522d,\n silver: 0xc0c0c0,\n skyblue: 0x87ceeb,\n slateblue: 0x6a5acd,\n slategray: 0x708090,\n slategrey: 0x708090,\n snow: 0xfffafa,\n springgreen: 0x00ff7f,\n steelblue: 0x4682b4,\n tan: 0xd2b48c,\n teal: 0x008080,\n thistle: 0xd8bfd8,\n tomato: 0xff6347,\n turquoise: 0x40e0d0,\n violet: 0xee82ee,\n wheat: 0xf5deb3,\n white: 0xffffff,\n whitesmoke: 0xf5f5f5,\n yellow: 0xffff00,\n yellowgreen: 0x9acd32,\n};\n\n/**\n * Canonicalise + convert an untrusted colour value to RGBA channels in\n * [0, 1]. The value passes through `parseCssColor` FIRST — anything the\n * strict parser rejects converts to `null` here (never interpolate a\n * raw string, §6.5 step 1 / RC#11). `currentcolor` is also rejected :\n * it has no concrete channels without computed-style context.\n */\nexport function cssColorToRgba(value: unknown): Rgba | null {\n const v = parseCssColor(value);\n if (v === null) return null;\n\n if (v.startsWith(\"#\")) return hexToRgba(v);\n\n if (v.startsWith(\"rgb\")) {\n const body = v.slice(v.indexOf(\"(\") + 1, -1);\n const parts = body.split(\",\").map((p) => p.trim());\n if (parts.length < 3) return null;\n const pct = parts[0]!.endsWith(\"%\");\n const scale = pct ? 100 : 255;\n const r = channel(parts[0]!, scale);\n const g = channel(parts[1]!, scale);\n const b = channel(parts[2]!, scale);\n const a = parts.length > 3 ? alphaChannel(parts[3]!) : 1;\n if (r === null || g === null || b === null || a === null) return null;\n return [r, g, b, a];\n }\n\n if (v.startsWith(\"hsl\")) {\n const body = v.slice(v.indexOf(\"(\") + 1, -1);\n const parts = body.split(\",\").map((p) => p.trim());\n if (parts.length < 3) return null;\n const h = Number(parts[0]!.replace(\"deg\", \"\"));\n const s = Number(parts[1]!.replace(\"%\", \"\")) / 100;\n const l = Number(parts[2]!.replace(\"%\", \"\")) / 100;\n const a = parts.length > 3 ? alphaChannel(parts[3]!) : 1;\n if (![h, s, l].every(Number.isFinite) || a === null) return null;\n const [r, g, b] = hslToRgb(h, s, l);\n return [r, g, b, a];\n }\n\n if (v === \"transparent\") return [0, 0, 0, 0];\n if (v === \"currentcolor\") return null;\n\n const packed = NAMED_RGB[v];\n if (packed === undefined) return null;\n return [((packed >> 16) & 0xff) / 255, ((packed >> 8) & 0xff) / 255, (packed & 0xff) / 255, 1];\n}\n\nfunction hexToRgba(v: string): Rgba | null {\n const h = v.slice(1);\n if (h.length === 3 || h.length === 4) {\n const r = parseInt(h[0]! + h[0]!, 16);\n const g = parseInt(h[1]! + h[1]!, 16);\n const b = parseInt(h[2]! + h[2]!, 16);\n const a = h.length === 4 ? parseInt(h[3]! + h[3]!, 16) : 255;\n return [r / 255, g / 255, b / 255, a / 255];\n }\n if (h.length === 6 || h.length === 8) {\n const r = parseInt(h.slice(0, 2), 16);\n const g = parseInt(h.slice(2, 4), 16);\n const b = parseInt(h.slice(4, 6), 16);\n const a = h.length === 8 ? parseInt(h.slice(6, 8), 16) : 255;\n return [r / 255, g / 255, b / 255, a / 255];\n }\n return null;\n}\n\nfunction channel(token: string, scale: number): number | null {\n const n = Number(token.replace(\"%\", \"\"));\n if (!Number.isFinite(n)) return null;\n return clamp01(n / scale);\n}\n\nfunction alphaChannel(token: string): number | null {\n const pct = token.endsWith(\"%\");\n const n = Number(token.replace(\"%\", \"\"));\n if (!Number.isFinite(n)) return null;\n return clamp01(pct ? n / 100 : n);\n}\n\n/** Standard HSL → RGB (CSS Color 4 §7.1). h in degrees, s/l in [0,1]. */\nfunction hslToRgb(h: number, s: number, l: number): [number, number, number] {\n const hue = ((h % 360) + 360) % 360;\n const c = (1 - Math.abs(2 * l - 1)) * s;\n const hp = hue / 60;\n const x = c * (1 - Math.abs((hp % 2) - 1));\n let r = 0;\n let g = 0;\n let b = 0;\n if (hp < 1) [r, g, b] = [c, x, 0];\n else if (hp < 2) [r, g, b] = [x, c, 0];\n else if (hp < 3) [r, g, b] = [0, c, x];\n else if (hp < 4) [r, g, b] = [0, x, c];\n else if (hp < 5) [r, g, b] = [x, 0, c];\n else [r, g, b] = [c, 0, x];\n const m = l - c / 2;\n return [clamp01(r + m), clamp01(g + m), clamp01(b + m)];\n}\n\n/** Component-wise sRGB lerp (§6.5 step 2). `t` may overshoot (springs) ;\n * channels clamp back into [0, 1] after mixing. */\nexport function mixRgba(a: Rgba, b: Rgba, t: number): Rgba {\n return [\n clamp01(a[0] + t * (b[0] - a[0])),\n clamp01(a[1] + t * (b[1] - a[1])),\n clamp01(a[2] + t * (b[2] - a[2])),\n clamp01(a[3] + t * (b[3] - a[3])),\n ];\n}\n\n/** Serialise RGBA back to `rgba()` form (§6.5 step 3). The output is\n * always re-accepted by `parseCssColor` (integer channels, alpha with\n * at most 4 decimals). */\nexport function serializeRgba(rgba: Rgba): string {\n const r = Math.round(clamp01(rgba[0]) * 255);\n const g = Math.round(clamp01(rgba[1]) * 255);\n const b = Math.round(clamp01(rgba[2]) * 255);\n // 4 decimals max so the alpha token matches the strict grammar.\n const a = Math.round(clamp01(rgba[3]) * 10000) / 10000;\n return `rgba(${r}, ${g}, ${b}, ${a})`;\n}\n\nfunction clamp01(n: number): number {\n return n < 0 ? 0 : n > 1 ? 1 : n;\n}\n","// LSML 1.1 §6.3 `bindAnimate` — continuous interpolation toward a live\n// leaf value (ADR 001 §3.3, issue #33).\n//\n// Per binding, the hook subscribes the existing leaf-grain signal and\n// retargets a Framer motion value on change — NO remount, the DOM node\n// is identical before/after (RC#6). Scalar channels (§6.1) ride motion\n// values attached to a wrapping `motion.div` ; colour channels (§6.5)\n// are interpolated component-wise in sRGB through the strict shared\n// parser and flow back into the primitive's resolved prop (which\n// re-validates them — RC#11 belt and braces).\n//\n// Anti-DoS (Bastion RC#13) : deltas are coalesced per frame — one\n// retarget max per rAF per binding, whatever the producer's rate\n// (1 kHz tested in E2E). Retargets interrupt in-flight springs with\n// velocity carry (§6.2/§6.4 — framer preserves a motion value's\n// velocity when a spring animation is replaced ; no snap).\n//\n// R8 runtime half (issue #42) : `filter.blur` / `filter.brightness`\n// values arriving live re-pass the same caps as the compiler before\n// they may touch the composed CSS filter (see filter-clamp.ts).\n//\n// Stagger (§6.7) : inside a `repeat` iteration the FIRST animated\n// retarget per binding is delayed by the ambient StaggerContext delay ;\n// steady-state retargets are never delayed (a permanently-lagging gauge\n// would defeat the purpose of a live binding). Documented hypothesis —\n// the spec only constrains animation *starts*.\n\nimport {\n animate,\n useMotionValue,\n useTransform,\n type AnimationPlaybackControls,\n type MotionValue,\n type MotionStyle,\n} from \"framer-motion\";\nimport { effect } from \"@preact/signals-react\";\nimport { useContext, useEffect, useMemo, useRef, useState } from \"react\";\nimport type { Store } from \"../state/store\";\nimport type { RenderNode } from \"./bundle\";\nimport { scopedPath } from \"./scope\";\nimport { StaggerContext } from \"./stagger-context\";\nimport { toFramer, type FramerTransition, type Transition } from \"../animate/transitions\";\nimport { createFrameCoalescer } from \"../animate/frame-coalescer\";\nimport { clampFilterChannel, warnRejectedFilter } from \"./filter-clamp\";\nimport { warnRejectedColor } from \"./css-color\";\nimport { emitDiagnostic } from \"./diagnostics\";\nimport { cssColorToRgba, mixRgba, serializeRgba, type Rgba } from \"./color-interp\";\n\n/** §6.5 colour-typed bindAnimate keys → the runtime prop name the\n * primitive reads (and re-validates through `parseCssColor`). */\nexport const BIND_ANIMATE_COLOR_PROPS: Readonly<Record<string, string>> = {\n \"style.color\": \"colour\",\n fill: \"fill\",\n background: \"background\",\n};\n\n/** Scalar motion channels a bindAnimate key drives. */\ntype ScalarChannel = \"opacity\" | \"x\" | \"y\" | \"scaleX\" | \"scaleY\" | \"rotate\" | \"blur\" | \"brightness\";\n\n/**\n * Validate + normalise one live bindAnimate value into per-channel\n * numeric targets. Returns `null` on rejection (wrong JSON shape per\n * §6.3, non-finite numbers, filter values outside the R8 caps when the\n * channel rejects rather than clamps). A `null` keeps the last\n * known-good target — the raw input never reaches a style.\n *\n * Exported pure for the hostile-delta fixture suite (issue #42).\n */\nexport function resolveScalarTargets(\n key: string,\n raw: unknown,\n): Partial<Record<ScalarChannel, number>> | null {\n switch (key) {\n case \"opacity\": {\n const v = toFiniteScalar(raw);\n if (v === null) return null;\n return { opacity: v < 0 ? 0 : v > 1 ? 1 : v };\n }\n case \"transform.translate\": {\n if (!Array.isArray(raw) || raw.length !== 2) return null;\n const tx = toFiniteScalar(raw[0]);\n const ty = toFiniteScalar(raw[1]);\n if (tx === null || ty === null) return null;\n return { x: tx, y: ty };\n }\n case \"transform.scale\": {\n const s = toFiniteScalar(raw);\n if (s !== null) return { scaleX: s, scaleY: s };\n if (Array.isArray(raw) && raw.length === 2) {\n const sx = toFiniteScalar(raw[0]);\n const sy = toFiniteScalar(raw[1]);\n if (sx === null || sy === null) return null;\n return { scaleX: sx, scaleY: sy };\n }\n return null;\n }\n case \"transform.rotate\": {\n const v = toFiniteScalar(raw);\n if (v === null) return null;\n return { rotate: v };\n }\n case \"filter.blur\": {\n const v = clampFilterChannel(\"blur\", raw);\n return v === null ? null : { blur: v };\n }\n case \"filter.brightness\": {\n const v = clampFilterChannel(\"brightness\", raw);\n return v === null ? null : { brightness: v };\n }\n default:\n return null;\n }\n}\n\n// ── IEEE-754 `-0` policy (R8 / PR #39 coherence, issue #33) ───────────\n// `-0 < 0` is FALSE, so a plain sign clamp lets -0 through. Uniform\n// rule : no -0 ever reaches a motion value or a style. Per channel :\n// · opacity — the negative case CLAMPS to 0 (`-5 → 0`), so -0 follows\n// the same line and normalises to +0 (rejecting -0 while clamping\n// -5 would be incoherent within the channel) ;\n// · translate / scale / rotate — negatives are valid values and\n// `-0 == 0` is mathematically neutral, so -0 normalises to +0 (a\n// producer computing `-x` at x = 0 must not be rejected into a\n// stale last-good) ;\n// · filter.blur / filter.brightness — REJECTED (null → last-good) by\n// `clampFilterChannel` : the R8 gate treats any negative sign,\n// including -0, as hostile input (compiler mirror, issues #39/#41\n// — do not relax here).\n/** Finite-number gate + `-0 → +0` normalisation for the generic scalar\n * channels (filter channels go through `clampFilterChannel` instead). */\nfunction toFiniteScalar(v: unknown): number | null {\n if (typeof v !== \"number\" || !Number.isFinite(v)) return null;\n return Object.is(v, -0) ? 0 : v;\n}\n\n/** Default retarget transition when neither a per-leaf wire directive\n * nor a compiled `transitions` entry resolves : the §6.2 default\n * spring (stiffness 170, damping 26, mass 1). A spring is the only\n * curve with well-defined retarget semantics (velocity carry) — a\n * documented hypothesis, see the PR for issue #33. */\nexport const DEFAULT_BIND_ANIMATE_TRANSITION: Transition = {\n kind: \"spring\",\n stiffness: 170,\n damping: 26,\n mass: 1,\n};\n\n/** node.transitions lookup key for each bindAnimate key (mirrors the\n * compiler's `transitionKeysForBindAnimate`). */\nfunction transitionLookupKey(key: string): string {\n switch (key) {\n case \"opacity\":\n return \"opacity\";\n case \"transform.translate\":\n return \"x\";\n case \"transform.scale\":\n return \"scale\";\n case \"transform.rotate\":\n return \"rotate\";\n case \"filter.blur\":\n case \"filter.brightness\":\n return \"filter\";\n default:\n return BIND_ANIMATE_COLOR_PROPS[key] ?? key;\n }\n}\n\nexport interface BindAnimateHandle {\n /** Motion-value style for the wrapping `motion.div` — `null` when no\n * scalar channel is bound (no wrapper needed). */\n motionStyle: MotionStyle | null;\n /** Live-interpolated colour values, keyed by the primitive prop name\n * (`colour` / `fill` / `background`). Merged over `resolved`. */\n colorProps: Record<string, string>;\n}\n\nconst NO_COLORS: Record<string, string> = {};\n\n/**\n * Drive a node's `animateBindings`. Must be called unconditionally\n * (hook) ; cheap no-op when the node has no bindings.\n */\nexport function useBindAnimate(node: RenderNode, store: Store, scope: string): BindAnimateHandle {\n const bindings = node.animateBindings;\n const staggerDelayMs = useContext(StaggerContext);\n\n // Fixed channel set — created unconditionally so hook order is\n // stable ; unbound channels stay at their identity value.\n const opacity = useMotionValue(1);\n const x = useMotionValue(0);\n const y = useMotionValue(0);\n const scaleX = useMotionValue(1);\n const scaleY = useMotionValue(1);\n const rotate = useMotionValue(0);\n const blur = useMotionValue(0);\n const brightness = useMotionValue(1);\n // Composed CSS filter — both functions always present so framer\n // interpolates structurally-identical lists (same form as the\n // compiler emits, clamped per R8).\n const filter = useTransform(\n [blur, brightness] as [MotionValue<number>, MotionValue<number>],\n ([b, br]: number[]) => `blur(${b}px) brightness(${br})`,\n );\n\n const [colorProps, setColorProps] = useState<Record<string, string>>(NO_COLORS);\n\n const channels = useRef<Record<ScalarChannel, MotionValue<number>>>({\n opacity,\n x,\n y,\n scaleX,\n scaleY,\n rotate,\n blur,\n brightness,\n });\n\n useEffect(() => {\n if (!bindings || Object.keys(bindings).length === 0) return;\n\n const mvs = channels.current;\n const controls = new Map<string, AnimationPlaybackControls>();\n const colorState = new Map<string, { current: Rgba }>();\n const animatedOnce = new Set<string>();\n let mounted = false;\n\n const transitionFor = (key: string, fullPath: string): FramerTransition => {\n const live = store.transitionSignal(fullPath).peek();\n const declared = live ?? node.transitions?.[transitionLookupKey(key)];\n const base = toFramer(declared ?? DEFAULT_BIND_ANIMATE_TRANSITION);\n // §6.7 — stagger delays only the first animated retarget.\n if (staggerDelayMs > 0 && !animatedOnce.has(key)) {\n return { ...base, delay: staggerDelayMs / 1000 } as FramerTransition;\n }\n return base;\n };\n\n const dispatch = (key: string, value: unknown, instant: boolean): void => {\n const colorProp = BIND_ANIMATE_COLOR_PROPS[key];\n const fullPath = scopedPath(scope, bindings[key] as string);\n\n if (colorProp !== undefined) {\n // §6.5 — canonicalise BOTH endpoints through the strict parser\n // before interpolating ; never a raw string.\n const end = cssColorToRgba(value);\n if (end === null) {\n warnRejectedColor(`bindAnimate.${key}`, node.id);\n return;\n }\n const prev = colorState.get(key);\n if (instant || prev === undefined) {\n colorState.set(key, { current: end });\n setColorProps((p) => ({ ...p, [colorProp]: serializeRgba(end) }));\n return;\n }\n const start = prev.current;\n const tx = transitionFor(key, fullPath);\n animatedOnce.add(key);\n controls.get(`color:${key}`)?.stop();\n controls.set(\n `color:${key}`,\n animate(0, 1, {\n ...tx,\n onUpdate: (t) => {\n const mixed = mixRgba(start, end, t);\n prev.current = mixed;\n setColorProps((p) => ({ ...p, [colorProp]: serializeRgba(mixed) }));\n },\n }),\n );\n return;\n }\n\n const targets = resolveScalarTargets(key, value);\n if (targets === null) {\n // R9 — the offending value is never logged.\n if (key.startsWith(\"filter.\")) warnRejectedFilter(`bindAnimate.${key}`, node.id);\n else warnRejectedBindValue(key, node.id);\n return;\n }\n if (instant) {\n // §6.3.1 — on mount the rendered state initialises from the\n // bound value instantly (there is no previous state).\n for (const [ch, v] of Object.entries(targets)) {\n mvs[ch as ScalarChannel].jump(v as number);\n }\n return;\n }\n const tx = transitionFor(key, fullPath);\n animatedOnce.add(key);\n for (const [ch, v] of Object.entries(targets)) {\n // framer's animate() replaces any in-flight animation on the\n // motion value and seeds the new spring with the value's\n // current velocity — §6.2 velocity carry, no snap.\n controls.set(ch, animate(mvs[ch as ScalarChannel], v as number, tx));\n }\n };\n\n // RC#13 — one retarget max per rAF per binding.\n const coalescer = createFrameCoalescer((key, value) => dispatch(key, value, false));\n\n const disposers = Object.entries(bindings).map(([key, path]) =>\n effect(() => {\n const v = store.signal(scopedPath(scope, path)).value;\n if (v === undefined) return;\n if (!mounted) dispatch(key, v, true);\n else coalescer.push(key, v);\n }),\n );\n mounted = true;\n\n return () => {\n for (const d of disposers) d();\n coalescer.dispose();\n for (const c of controls.values()) c.stop();\n };\n // node/store/scope identity changes re-wire every subscription ;\n // staggerDelayMs is stable per repeat iteration.\n }, [node, bindings, store, scope, staggerDelayMs]);\n\n const motionStyle = useMemo<MotionStyle | null>(() => {\n if (!bindings) return null;\n const style: MotionStyle = {};\n let any = false;\n for (const key of Object.keys(bindings)) {\n switch (key) {\n case \"opacity\":\n style.opacity = opacity;\n any = true;\n break;\n case \"transform.translate\":\n style.x = x;\n style.y = y;\n any = true;\n break;\n case \"transform.scale\":\n style.scaleX = scaleX;\n style.scaleY = scaleY;\n any = true;\n break;\n case \"transform.rotate\":\n style.rotate = rotate;\n any = true;\n break;\n case \"filter.blur\":\n case \"filter.brightness\":\n style.filter = filter;\n any = true;\n break;\n default:\n break; // colour keys flow through colorProps, not the wrapper\n }\n }\n if (!any) return null;\n style.willChange = \"transform, opacity, filter\";\n return style;\n }, [bindings, opacity, x, y, scaleX, scaleY, rotate, filter]);\n\n return { motionStyle, colorProps };\n}\n\n/** R9 diagnostic — shape-invalid bindAnimate value (non-filter\n * channels). Structured event, value withheld. */\nfunction warnRejectedBindValue(key: string, nodeId?: string): void {\n emitDiagnostic(\n nodeId,\n `bindAnimate.${key}`,\n \"rejected bound value : JSON shape does not match the property type (LSML §6.3)\",\n );\n}\n","// Typed mask builder (LSML 1.2 §4.x, ADR 002 §3.2 #E ; Bastion T1/T2/T3/T4).\n//\n// A node may carry a typed `mask` whose fields are ALL typed — there is\n// deliberately NO free-form SVG string anywhere in the shape. This module\n// turns those fields into a real `<mask>` / `<clipPath>` SVG element built\n// element-by-element with React, and a CSS reference (`mask`/`clip-path`)\n// the Tree applies to the masked subtree's wrapper.\n//\n// ── Security contract ────────────────────────────────────────────────\n// - T3 — zero arbitrary SVG markup from the bundle. Every node of the\n// `<mask>` is constructed here from typed fields ; no raw-HTML injection\n// React escape hatch is ever used on this path, so `<script>` /\n// `<foreignObject>` / event-handlers are structurally impossible to emit —\n// a `mask.source` that tries to smuggle markup is treated as a plain string\n// and lands on a `<use href>` / `<image href>` value or is rejected\n// outright, never parsed as markup.\n// - T4 — `mask.type` / `mask.op` are RE-VALIDATED against the closed runtime\n// enum (defence in depth ; the compiler already gated them, but live LSDP\n// deltas bypass the compiler). Out-of-enum → diagnostic + the mask is\n// omitted, never passthrough.\n// - T1/T2 — an image `mask.source` URL passes `checkHostAllowed(src,\n// allowedHosts)` BEFORE it reaches the `<image href>` ; rejection → a\n// diagnostic carrying only a STATIC reason (never the URL, R9) and the\n// whole mask is omitted.\n//\n// The builder is pure : given the typed mask + allowedHosts it returns either\n// `null` (omit — render the subtree unmasked) or a `{ def, style }` pair. It\n// NEVER throws and NEVER echoes a rejected value.\n\nimport type { ReactElement, CSSProperties } from \"react\";\nimport { checkHostAllowed } from \"@lumencast/protocol\";\nimport { emitDiagnostic } from \"./diagnostics\";\n\n/** Resolve a shape `mask.source.ref` to its inlined mask-coverage geometry\n * (#K). The Tree supplies this from its one-pass `id → shape` index ; it\n * returns `null` for a PENDING ref (id absent from the index) so the mask is\n * omitted, never crashing. The resolver inlines ONLY the referenced shape's\n * geometry — never its own mask (anti-cycle, profondeur = 1). */\nexport type ShapeRefResolver = (ref: string) => ReactElement | null;\n\n/** Closed `mask.type` allowlist — runtime half of the double-gate (T4).\n * Mirrors `@lumencast/compiler` `MASK_TYPES` ; kept local so the runtime\n * has no compile-time dependency on the compiler package. */\nconst MASK_TYPES = new Set([\"alpha\", \"luminance\"]);\n\n/** Feather pad (px). The group/shape mask wrapper's `overflow:hidden` box is\n * grown by this on every side (tree.tsx, `inset:-PAD`) and the coverage is\n * shifted back by the same amount (buildMask) so a BLURRED mask rim isn't\n * re-cut into a hard square at the box edge. Generous enough for the\n * bg-texture ellipse's ~3σ (53.88 CSS sigma) feather. Sharp masks are\n * unaffected (their alpha-0 region simply sits inside the grown box). */\nexport const MASK_FEATHER_PAD = 180;\n\n/** Closed `mask.op` allowlist — runtime half of the double-gate (T4). */\nconst MASK_OPS = new Set([\"intersect\", \"subtract\", \"union\"]);\n\n/** A typed mask source, the only shapes the builder accepts. Anything else\n * (string, missing discriminant, extra markup) is rejected. A `group` source\n * (#O) references a GROUP/FRAME container by id, composited downstream. */\nexport type MaskSource =\n | { kind: \"shape\"; ref: string }\n | { kind: \"image\"; src: string; srcRect?: { x: number; y: number; w: number; h: number } }\n | { kind: \"group\"; ref: string };\n\n/** The typed mask spec as it reaches the runtime (compiler-lowered or a live\n * LSDP delta). All fields are re-validated here — nothing is trusted. */\nexport interface MaskSpec {\n source: MaskSource;\n type: \"alpha\" | \"luminance\";\n op: \"intersect\" | \"subtract\" | \"union\";\n position?: { x: number; y: number };\n size?: { w: number; h: number };\n}\n\n/** What a successfully-built mask contributes to the render. */\nexport interface BuiltMask {\n /** The `<mask>` element to drop into the masked element's SVG `<defs>`. */\n def: ReactElement;\n /** Inline style applying the mask to the masked subtree's wrapper. */\n style: CSSProperties;\n /** The generated mask id (for `url(#…)` wiring and test assertions). */\n id: string;\n /** True when the coverage is FEATHERED (a blurred edge) : the masked wrapper\n * must grow by MASK_FEATHER_PAD (tree.tsx) so the soft rim isn't re-cut into a\n * square, and the coverage here is pre-shifted by the same pad. A sharp mask\n * leaves this false and skips the pad entirely (no structural change). */\n feather: boolean;\n}\n\nlet maskIdSeq = 0;\nfunction nextMaskId(): string {\n maskIdSeq = (maskIdSeq + 1) % 1_000_000;\n return `lumen-mask-${maskIdSeq.toString(36)}`;\n}\n\n/** Sanitise a shape `ref` to a safe SVG id token. A legitimate ref is a\n * compiler-assigned node id (`[A-Za-z0-9_:-]`). Anything carrying markup\n * characters (`<`, `\"`, `#`, whitespace, `(`) is rejected — it can only be\n * an injection attempt, and there is no legitimate id that needs them. */\nfunction safeIdRef(ref: string): string | null {\n return /^[A-Za-z0-9_:-]+$/.test(ref) ? ref : null;\n}\n\nfunction finite(v: unknown): v is number {\n return typeof v === \"number\" && Number.isFinite(v);\n}\n\n/**\n * Validate a loose `mask` value into a strict {@link MaskSpec}, or `null`.\n * Re-runs the closed-enum gates (T4) and the source-shape discriminant ;\n * a malformed mask is dropped whole (it cannot be partially honoured).\n */\nexport function parseMaskSpec(value: unknown, nodeId: string | undefined): MaskSpec | null {\n if (typeof value !== \"object\" || value === null) return null;\n const m = value as Record<string, unknown>;\n\n if (typeof m.type !== \"string\" || !MASK_TYPES.has(m.type)) {\n emitDiagnostic(nodeId, \"mask.type\", \"is not alpha|luminance ; mask omitted (ADR 002 §3.2, T4)\");\n return null;\n }\n if (typeof m.op !== \"string\" || !MASK_OPS.has(m.op)) {\n emitDiagnostic(\n nodeId,\n \"mask.op\",\n \"is not intersect|subtract|union ; mask omitted (ADR 002 §3.2, T4)\",\n );\n return null;\n }\n\n const src = m.source;\n if (typeof src !== \"object\" || src === null) {\n emitDiagnostic(nodeId, \"mask.source\", \"is not a typed shape|image source ; mask omitted (T3)\");\n return null;\n }\n const s = src as Record<string, unknown>;\n let source: MaskSource;\n if (s.kind === \"shape\" && typeof s.ref === \"string\") {\n source = { kind: \"shape\", ref: s.ref };\n } else if (s.kind === \"image\" && typeof s.src === \"string\") {\n // Preserve the mask source's box (`srcRect`: offset from THIS node + size)\n // when present — it places/sizes the CSS mask to the source raster, shared\n // across siblings of different boxes (the caramel halo + drift fix).\n const sr = s.srcRect as { x?: unknown; y?: unknown; w?: unknown; h?: unknown } | undefined;\n source =\n sr && finite(sr.x) && finite(sr.y) && finite(sr.w) && finite(sr.h)\n ? { kind: \"image\", src: s.src, srcRect: { x: sr.x, y: sr.y, w: sr.w, h: sr.h } }\n : { kind: \"image\", src: s.src };\n } else if (s.kind === \"group\" && typeof s.ref === \"string\") {\n source = { kind: \"group\", ref: s.ref };\n } else {\n emitDiagnostic(\n nodeId,\n \"mask.source\",\n \"is not a typed shape|image|group source ; mask omitted (T3)\",\n );\n return null;\n }\n\n const spec: MaskSpec = { source, type: m.type as MaskSpec[\"type\"], op: m.op as MaskSpec[\"op\"] };\n\n const pos = m.position as { x?: unknown; y?: unknown } | undefined;\n if (pos && finite(pos.x) && finite(pos.y)) spec.position = { x: pos.x, y: pos.y };\n\n const size = m.size as { w?: unknown; h?: unknown } | undefined;\n if (size && finite(size.w) && finite(size.h)) spec.size = { w: size.w, h: size.h };\n\n return spec;\n}\n\n/**\n * Build a `<mask>` element + the CSS reference from a typed mask spec.\n * Returns `null` when the mask must be omitted (bad enum, rejected host,\n * unsafe ref) — the caller renders the subtree unmasked.\n *\n * @param mask the typed spec (already enum-checked by parseMaskSpec,\n * but re-checked here so the builder is safe standalone).\n * @param allowedHosts the bundle's `assets.allowedHosts` ; an image source is\n * gated against it (T1/T2) before reaching `<image href>`.\n * @param nodeId for diagnostics (never carries a value, R9).\n * @param resolveShape resolves a shape `mask.source.ref` to its inlined\n * coverage geometry (#K). Omitted / returns `null` ⇒ the\n * shape source is pending → the whole mask is omitted.\n */\nexport function buildMask(\n mask: MaskSpec,\n allowedHosts: readonly string[] | undefined,\n nodeId: string | undefined,\n resolveShape?: ShapeRefResolver,\n boxSize?: { w?: number; h?: number },\n feather = false,\n): BuiltMask | null {\n // T4 — defence in depth : re-validate the enums even though parseMaskSpec\n // already did, so `buildMask` is safe to call on any typed input.\n if (!MASK_TYPES.has(mask.type) || !MASK_OPS.has(mask.op)) {\n emitDiagnostic(nodeId, \"mask\", \"type/op outside the closed enum ; mask omitted (T4)\");\n return null;\n }\n\n const id = nextMaskId();\n\n // The mask content : a single element painted into the mask's luminance\n // (or alpha) channel. Coordinates come from typed numbers only.\n const x = mask.position?.x;\n const y = mask.position?.y;\n const w = mask.size?.w;\n const h = mask.size?.h;\n const geom = {\n ...(finite(x) ? { x } : {}),\n ...(finite(y) ? { y } : {}),\n ...(finite(w) ? { width: w } : {}),\n ...(finite(h) ? { height: h } : {}),\n };\n\n let content: ReactElement;\n if (mask.source.kind === \"image\") {\n // T1/T2 — gate the URL BEFORE it reaches the `<image href>`. A rejected\n // host/scheme omits the whole mask with a static-reason diagnostic.\n const decision = checkHostAllowed(mask.source.src, allowedHosts);\n if (!decision.allowed) {\n emitDiagnostic(\n nodeId,\n \"mask.source.src\",\n `image host/scheme rejected ; mask omitted (T1/T2 — ${decision.reason ?? \"denied\"})`,\n );\n return null;\n }\n // `href` is a typed attribute on a constructed element — never markup.\n // For an alpha mask, read the source's own alpha (mask-type:alpha on the\n // <mask>) ; luminance is the SVG default. The image fills the masked box\n // when no explicit geometry is given.\n // External <image> in an SVG <mask> (0×0 SVG) never loads. For `intersect`\n // apply the raster directly as a CSS mask-image. The masked image content is\n // drawn with `object-fit: cover` (Figma scaleMode FILL), so the mask raster\n // — the SAME source image — must `cover` too, else a `Wpx Hpx` (stretch)\n // mask clips a differently-scaled crop and the caramel ribbon shrinks /\n // shifts off its wave. `cover` keeps the alpha aligned with the content.\n if (mask.op === \"intersect\") {\n const mode = mask.type === \"alpha\" ? \"alpha\" : \"luminance\";\n const url = `url(\"${mask.source.src}\")`;\n // Place + size the mask to the SOURCE raster's box (`srcRect`: offset from\n // this node's box top-left + size), shared by every masked sibling — NOT\n // `cover` of each sibling's box (inflates → orange halo) nor centred\n // (drifts → mask pulled down). The caramel gradient (1146) and 3d-render\n // (930) thus clip to the SAME wave at the SAME spot.\n const rect = (mask.source as { srcRect?: { x: number; y: number; w: number; h: number } })\n .srcRect;\n const usable = rect && finite(rect.x) && finite(rect.y) && finite(rect.w) && finite(rect.h);\n const sizeCss = usable ? `${rect!.w}px ${rect!.h}px` : \"cover\";\n const posCss = usable ? `${rect!.x}px ${rect!.y}px` : \"center\";\n return {\n def: <defs key={id} />,\n style: {\n maskImage: url,\n WebkitMaskImage: url,\n maskSize: sizeCss,\n WebkitMaskSize: sizeCss,\n maskRepeat: \"no-repeat\",\n WebkitMaskRepeat: \"no-repeat\",\n maskPosition: posCss,\n WebkitMaskPosition: posCss,\n maskMode: mode,\n } as CSSProperties,\n id,\n feather: false,\n };\n }\n const imgGeom =\n Object.keys(geom).length > 0\n ? geom\n : finite(boxSize?.w) && finite(boxSize?.h)\n ? { x: 0, y: 0, width: boxSize.w, height: boxSize.h }\n : { width: \"100%\", height: \"100%\" };\n content = <image href={mask.source.src} preserveAspectRatio=\"none\" {...imgGeom} />;\n } else {\n // Shape (#K) or group/frame (#O) source — INLINE the referenced node's\n // resolved coverage geometry into the `<mask>`, built element-by-element\n // (T3 : zero markup). For a `shape` the resolver returns its own outline ;\n // for a `group` it returns the composite of the container's visible\n // children (the resolver routes on the referenced node's kind).\n //\n // The ref is first re-sanitised (defence in depth : a live LSDP delta could\n // smuggle markup chars), then resolved against the Tree's referenceable-node\n // index. A PENDING ref (id absent) → the mask is omitted, sub-tree rendered\n // unmasked (A2.1 : omission, not crash). Anti-cycle is enforced by the\n // resolver inlining ONLY geometry — never any node's own mask.\n const safeRef = safeIdRef(mask.source.ref);\n if (safeRef === null) {\n emitDiagnostic(\n nodeId,\n \"mask.source.ref\",\n \"shape ref is not a safe id token ; mask omitted (T3)\",\n );\n return null;\n }\n const resolved = resolveShape?.(safeRef) ?? null;\n if (resolved === null) {\n emitDiagnostic(\n nodeId,\n \"mask.source.ref\",\n \"shape ref does not resolve to an indexed shape ; mask omitted (ADR 002 A2.1 #K)\",\n );\n return null;\n }\n // Position/size place the inlined geometry numerically when given,\n // wrapping it in a translated group (typed numbers only, never a string).\n content =\n Object.keys(geom).length > 0 ? (\n <g\n transform={\n finite(geom.x) || finite(geom.y)\n ? `translate(${finite(geom.x) ? geom.x : 0} ${finite(geom.y) ? geom.y : 0})`\n : undefined\n }\n >\n {resolved}\n </g>\n ) : (\n resolved\n );\n }\n\n // Feather pad : the mask wrapper's box is grown by MASK_FEATHER_PAD on every\n // side (tree.tsx, `inset:-PAD`) so a BLURRED coverage edge isn't re-cut into a\n // hard square by the wrapper's `overflow:hidden`. The coverage is shifted back\n // by the SAME amount here (userSpaceOnUse), so the mask stays put while the box\n // grows. A sharp mask is unaffected (its alpha-0 region just sits inside the\n // grown box). Applied to the coverage only — never the full-coverage union/\n // subtract rect, which must keep spanning the whole (grown) box.\n if (feather) {\n content = (\n <g key=\"feather-pad\" transform={`translate(${MASK_FEATHER_PAD} ${MASK_FEATHER_PAD})`}>\n {content}\n </g>\n );\n }\n\n // `union` widens coverage : a base full-coverage white rect is unioned with\n // the source paint. `subtract` removes the source area from full coverage by\n // painting the source black over a white base. `intersect` (default) keeps\n // only the source's own coverage. All three are expressed by which fixed\n // elements we emit — never by interpolating an author string.\n let inner: ReactElement;\n if (mask.op === \"intersect\") {\n inner = content;\n } else if (mask.op === \"union\") {\n inner = (\n <>\n <rect x={0} y={0} width=\"100%\" height=\"100%\" fill=\"white\" />\n {content}\n </>\n );\n } else {\n // subtract : white base, source painted black to carve it out.\n inner = (\n <>\n <rect x={0} y={0} width=\"100%\" height=\"100%\" fill=\"white\" />\n <g style={{ filter: \"invert(1)\" }}>{content}</g>\n </>\n );\n }\n\n const def = (\n <mask\n id={id}\n key={id}\n // `maskContentUnits` (not `maskUnits`) places the coverage in the masked\n // element's user space. The mask REGION is widened to −50%..150% of the\n // masked box (objectBoundingBox units) so a FEATHERED coverage (the\n // bg-texture ellipse blurred 107.76) keeps its soft rim — the default\n // −10%..120% clipped the blur to a hard SQUARE edge. (The prior\n // `maskUnits=\"userSpaceOnUse\"` WITHOUT x/y/width/height shrank the region\n // to the 0×0 defs-svg viewport, hiding every group/shape-masked subtree —\n // the platform-wide bug ; an explicit region is the robust form.)\n maskContentUnits=\"userSpaceOnUse\"\n x=\"-50%\"\n y=\"-50%\"\n width=\"200%\"\n height=\"200%\"\n // T4 — alpha vs luminance is a typed switch (closed enum, never author\n // text ; kebab key so `mask-type` is emitted verbatim across React).\n {...(mask.type === \"alpha\" && mask.source.kind !== \"image\" ? { \"mask-type\": \"alpha\" } : {})}\n >\n {inner}\n </mask>\n );\n\n const ref = `url(#${id})`;\n return { def, style: { mask: ref, WebkitMask: ref }, id, feather };\n}\n","// Render-side shape index (ADR 002 §3.2 Amendment 2 / A2.1 #K).\n//\n// A `mask.source.kind:\"shape\"` references a shape primitive by its stable `id`\n// (mapper-assigned `fig-<safeIdRef(figmaNodeId)>`, see lumencast-figma). At\n// render time the `<mask>` must INLINE the referenced shape's resolved geometry\n// (the former `<use href=\"#id\">` relied on a defs-resolvable sibling that does\n// not exist in the runtime's flat tree). This module builds, in ONE pass over\n// the bundle root, an index `id → RenderNode` of every referenceable shape, and\n// threads it to the Tree via a plain React context (the bundle is immutable and\n// content-addressed, so a mount-stable context is the right tool).\n//\n// ── Invariants (A2.1 / A4.3) ─────────────────────────────────────────\n// - A `kind:\"shape\"` node carrying an `id` (shape-source target, #K) OR a\n// `kind:\"frame\"` node carrying an `id` (group/frame-source target, #O —\n// a GROUP and a FRAME container both lower to `frame`) is indexed. The\n// mapper only emits `id` on actually-referenced nodes (no inflation).\n// - Uniqueness : two nodes claiming the same `id` is a build-time defect. The\n// FIRST occurrence wins and a diagnostic is emitted for each collision\n// (never the id value beyond the field tag — R9-clean field only).\n// - The index is read-only ; resolution is a pure in-memory lookup (A2.4 : no\n// new surface, no URL, no fetch).\n\nimport { createContext, useContext, type ReactNode } from \"react\";\nimport type { RenderNode } from \"./bundle\";\nimport { emitDiagnostic } from \"./diagnostics\";\n\nexport type ShapeIndex = ReadonlyMap<string, RenderNode>;\n\nconst EMPTY: ShapeIndex = new Map();\nconst ShapeIndexCtx = createContext<ShapeIndex>(EMPTY);\n\n/**\n * Walk the bundle tree once and index every referenceable node — a\n * `kind:\"shape\"` (shape-source, #K) or a `kind:\"frame\"` (group/frame-source,\n * #O) — that carries an `id`. Collisions keep the first occurrence and\n * diagnose the rest.\n *\n * The walk descends `children` only (the render tree's structural edges) ; it\n * never reads `node.mask`, so building the index can never trigger mask\n * resolution (anti-cycle is enforced at the builder, but the index walk is\n * independent of masks entirely).\n */\nexport function buildShapeIndex(root: RenderNode | undefined): ShapeIndex {\n if (!root) return EMPTY;\n const index = new Map<string, RenderNode>();\n const stack: RenderNode[] = [root];\n while (stack.length > 0) {\n const node = stack.pop() as RenderNode;\n const referenceable = node.kind === \"shape\" || node.kind === \"frame\";\n if (referenceable && typeof node.id === \"string\" && node.id.length > 0) {\n if (index.has(node.id)) {\n emitDiagnostic(\n node.id,\n \"id\",\n \"duplicate shape id ; first occurrence kept, later ones ignored (ADR 002 A2.1 #K)\",\n );\n } else {\n index.set(node.id, node);\n }\n }\n // Push children in REVERSE so the LIFO stack pops them in document order :\n // \"first occurrence wins\" on a duplicate id must follow the bundle's order.\n const children = node.children;\n if (children) {\n for (let i = children.length - 1; i >= 0; i--) stack.push(children[i]);\n }\n }\n return index;\n}\n\n/**\n * Provide a prebuilt shape index to the render subtree. Mounted ONCE at the\n * render root by each mode, wrapping `<Tree>`. Accepts the index directly so\n * the (cheap, one-pass) build happens once per bundle rather than per render.\n */\nexport function ShapeIndexProvider({\n index,\n children,\n}: {\n index: ShapeIndex;\n children: ReactNode;\n}) {\n return <ShapeIndexCtx.Provider value={index}>{children}</ShapeIndexCtx.Provider>;\n}\n\n/** Read the active shape index. Empty map when no provider is mounted (a\n * pending ref then resolves to \"not found\" → mask omitted, never a crash). */\nexport function useShapeIndex(): ShapeIndex {\n return useContext(ShapeIndexCtx);\n}\n","// Recursive tree renderer — resolves bindings, dispatches to\n// primitives, handles `repeat` specially.\n\nimport { useSignals } from \"@preact/signals-react/runtime\";\nimport { motion } from \"framer-motion\";\nimport { useMemo, type ReactNode } from \"react\";\nimport type { Store } from \"../state/store\";\nimport type { Transition } from \"../animate/transitions\";\nimport { PRIMITIVES } from \"./primitives\";\nimport { PathScopeProvider, scopedPath, usePathScope } from \"./scope\";\nimport type { RenderNode } from \"./bundle\";\nimport { UniversalWrapper, type SizingMode } from \"./universal-wrapper\";\nimport { KeyframePlayer } from \"./keyframe-player\";\nimport { StaggerContext, computeStaggerDelayMs } from \"./stagger-context\";\nimport { useBindAnimate } from \"./bind-animate\";\nimport { checkNodeProps } from \"./prop-allowlist\";\nimport { emitDiagnostic } from \"./diagnostics\";\nimport { buildMask, parseMaskSpec, MASK_FEATHER_PAD } from \"./mask\";\nimport { parseBlendMode } from \"./blend-mode\";\nimport { useAllowedHosts } from \"./allowed-hosts\";\nimport { useShapeIndex } from \"./shape-index\";\nimport {\n buildMaskCoverageFromShape,\n buildMaskCoverageFromGroup,\n coverageIsFeathered,\n} from \"./shape-geometry\";\n\nexport interface TreeProps {\n node: RenderNode;\n store: Store;\n}\n\nexport function Tree({ node, store }: TreeProps): ReactNode {\n if (node.kind === \"repeat\") {\n return <Repeat node={node} store={store} />;\n }\n return <Node node={node} store={store} />;\n}\n\nfunction Node({ node, store }: TreeProps): ReactNode {\n // useSignals() lets the surrounding component subscribe to any\n // signal read during render. Each leaf path has its own signal so\n // re-renders only fire on touched paths.\n useSignals();\n const scope = usePathScope();\n // ADR 002 §3.2 (#E) — the bundle's host allowlist, for gating an image\n // mask source (T1/T2). `undefined` = deny every remote host.\n const allowedHosts = useAllowedHosts();\n // ADR 002 A2.1 (#K) — the bundle-wide `id → shape` index, for resolving a\n // `mask.source.kind:\"shape\"` ref to inlined coverage geometry.\n const shapeIndex = useShapeIndex();\n\n // Hooks must run unconditionally — the early-return for unknown\n // kinds happens *after* every hook has fired.\n const resolved = useMemo(\n () => resolveProps(node, store, scope),\n // We re-build per render — signals re-render cheaply, and the\n // resolution itself is O(bindings) which is small. The memo is a\n // micro-optimisation to keep object identity stable across renders\n // when the inputs haven't changed.\n [node, store, scope, ...readBindingValues(node, store, scope)],\n );\n\n // LSML 1.1 §6.3 — bindAnimate : continuous interpolation toward live\n // leaf values, no remount (issue #33). Scalar channels ride motion\n // values on a wrapping motion.div ; colour channels (§6.5) flow back\n // into the primitive's resolved prop as interpolated, re-validated\n // colour strings.\n const bindAnimate = useBindAnimate(node, store, scope);\n\n // ADR 001 §3.4 (issue #34) — audit static props + binding keys\n // against the primitive's allowlist ; unknown props diagnose instead\n // of dropping silently. Key sets are static per node (a live delta\n // can only change values), so the check is once-per-node.\n checkNodeProps(node);\n\n const Primitive = PRIMITIVES[node.kind as keyof typeof PRIMITIVES];\n if (!Primitive) {\n emitDiagnostic(node.id, \"kind\", \"unknown render kind ; node not rendered\");\n return null;\n }\n\n // LSDP/1.1 §3.2.2 — a per-leaf transition on the most recent delta\n // takes precedence over the bundle-level default. Only bound props\n // can carry a wire transition (a static prop never moves). Snapshots\n // clear the directive, so the bundle default reapplies after a reset.\n //\n // We resolve here in the parent's render (useSignals() above tracks\n // these reads) rather than inside the primitive's callback — that way\n // a transition signal change re-renders this Node, which in turn re-\n // renders the primitive with the new transition prop.\n const liveTransitions: Record<string, Transition | undefined> = {};\n if (node.bindings) {\n for (const [key, path] of Object.entries(node.bindings)) {\n const ts = store.transitionSignal(scopedPath(scope, path)).value;\n if (ts !== undefined) liveTransitions[key] = ts;\n }\n }\n const transitionFor = (key: string): Transition | undefined => {\n if (key in liveTransitions) return liveTransitions[key];\n return node.transitions?.[key];\n };\n\n const children = node.children?.map((child, idx) => (\n <Tree key={child.id ?? idx} node={child} store={store} />\n ));\n\n // LSML 1.1 §5.4 — universal props applied uniformly across all\n // primitives. Pulled out of `resolved` so primitives can ignore\n // them ; the wrapper composes with whatever transform/opacity the\n // primitive's own framer-motion may apply.\n //\n // ADR 002 §3.1 (D1) — absolute placement. The compiler flattens LSML\n // `position:{x,y}` → `resolved.x`/`resolved.y` and `size:{w,h}` →\n // `resolved.width`/`resolved.height` on EVERY primitive (compile.ts\n // §universal-props). The wrapper consumes them as absolute placement,\n // EXCEPT on `frame` : a frame already positions itself (it reads\n // `x`/`y`/`width`/`height` into its own absolute box + transform), so\n // letting the wrapper pin it too would double the offset. Every other\n // kind (text/shape/image/media/instance/stack/grid) is placed by the\n // wrapper. A node without `x`/`y` gets `position: undefined` → normal\n // flow (RC#2 non-regression).\n // A masked node with a real blend hoists that blend above the mask wrapper\n // (the mask isolates an inner `mix-blend-mode`). Compute it once here so the\n // universal prop and the wrapper below agree.\n const maskHoistsBlend =\n resolved.mask !== undefined &&\n typeof resolved.blendMode === \"string\" &&\n parseBlendMode(resolved.blendMode) !== undefined;\n const universal = {\n visible: typeof resolved.visible === \"boolean\" ? resolved.visible : undefined,\n opacity:\n typeof resolved.universal_opacity === \"number\" ? resolved.universal_opacity : undefined,\n // A frame applies its own static rotation (frame.tsx) so it pivots around\n // its centre ; the wrapper has no box for a self-positioning frame and would\n // pivot around a collapsed (0-height) box. Non-frames keep it on the wrapper\n // (they DO carry position/size there).\n rotation:\n node.kind === \"frame\"\n ? undefined\n : typeof resolved.rotation === \"number\"\n ? resolved.rotation\n : undefined,\n // Mirror (Figma scaleY(-1)) — like rotation, a frame mirrors itself\n // (frame.tsx) ; non-frames carry it on the wrapper, composed with rotation.\n flipY: node.kind === \"frame\" ? undefined : resolved.flipY === true,\n blur: typeof resolved.blur === \"number\" ? resolved.blur : undefined,\n sizing: extractSizing(resolved.sizing),\n position: node.kind === \"frame\" ? undefined : extractPosition(resolved),\n size: node.kind === \"frame\" ? undefined : extractSize(resolved),\n // ADR 002 §3.2 (D2 / #D) — `blendMode` is a universal prop on every\n // primitive ; the wrapper re-validates it against the closed enum\n // before applying `mix-blend-mode` (T4 runtime gate). Pass the raw\n // resolved value through ; the wrapper omits anything off the enum.\n // A blend on a MASKED node is hoisted ABOVE the mask wrapper (see below) —\n // a CSS mask forms an isolating group, so a `mix-blend-mode` left on the\n // (inner) wrapper would fold over a transparent backdrop (the caramel\n // hard-light showed the raw blue wave instead of compositing over the warm\n // gradient). Drop it here when it will be hoisted.\n blendMode:\n typeof resolved.blendMode === \"string\" && !maskHoistsBlend ? resolved.blendMode : undefined,\n };\n\n // ADR 002 §3.1 (D1) — a container holding at least one absolutely\n // positioned child must establish the containing block so the child's\n // `left/top` resolve against it (and not a distant ancestor). `Frame`\n // is already `position:absolute` ; `Stack`/`Grid` flip to\n // `position:relative` only when needed (no change for pure auto-layout\n // boards — RC#2). Threaded to the primitive so the layout container\n // decides ; a node without absolute children is untouched.\n const hasAbsoluteChild = node.children?.some(childIsAbsolute) ?? false;\n\n // Merge live-interpolated colour values (§6.5) over the resolved\n // props — the primitive re-validates them through `parseCssColor`.\n const resolvedWithColors =\n Object.keys(bindAnimate.colorProps).length > 0\n ? { ...resolved, ...bindAnimate.colorProps }\n : resolved;\n\n const primitiveEl = (\n <Primitive\n resolved={resolvedWithColors}\n nodeId={node.id}\n transitionFor={transitionFor}\n animateInitial={node.animate_initial}\n establishesContainingBlock={hasAbsoluteChild}\n >\n {children}\n </Primitive>\n );\n\n // ADR 002 §3.2 (#E) — a typed `mask` lowered onto the node. Build it up-front\n // so an IMAGE mask (CSS `mask-image`) can sit INSIDE the wrapper — it must\n // rotate WITH the content under the wrapper's transform, else an outer\n // un-rotated mask clips a mis-rotated crop (the caramel wave shrank off-box).\n // A group/shape SVG mask stays OUTSIDE (its coverage is authored in the parent\n // coordinate space). The mask is built ENTIRELY from typed fields (T3) ; enums\n // re-validated (T4), image source host-gated (T1/T2) before any `href`.\n let built: ReturnType<typeof buildMask> | null = null;\n if (resolved.mask !== undefined) {\n const spec = parseMaskSpec(resolved.mask, node.id);\n // #K/#O — resolve a ref to its inlined coverage geometry, routed on the\n // referenced node's `kind` (shape → own outline ; frame → visible children).\n const resolveShape = (ref: string) => {\n const target = shapeIndex.get(ref);\n if (!target) return null;\n return target.kind === \"frame\"\n ? buildMaskCoverageFromGroup(target, target.id)\n : buildMaskCoverageFromShape(target, target.id);\n };\n // A FEATHERED coverage (a blurred mask edge, e.g. the bg-texture ellipse) is\n // the only case that needs the wrapper feather pad. Detect it from the mask\n // SOURCE group's children so a sharp mask skips the pad entirely (no extra\n // wrapper, no structural change).\n let feather = false;\n if (spec) {\n const src = spec.source as { kind?: string; ref?: unknown };\n if ((src.kind === \"group\" || src.kind === \"shape\") && typeof src.ref === \"string\") {\n const t = shapeIndex.get(src.ref);\n feather = t ? coverageIsFeathered(t) : false;\n }\n }\n built = spec\n ? buildMask(spec, allowedHosts, node.id, resolveShape, extractSize(resolved), feather)\n : null;\n }\n const isImageMask =\n built !== null && built.style != null && \"maskImage\" in (built.style as object);\n\n let inner: ReactNode = primitiveEl;\n if (built && isImageMask) {\n // Image mask co-located with the content : the CSS mask-image is on a box the\n // wrapper's transform rotates, keeping its alpha aligned to the wave.\n inner = <div style={{ width: \"100%\", height: \"100%\", ...built.style }}>{inner}</div>;\n }\n\n let body = <UniversalWrapper {...universal}>{inner}</UniversalWrapper>;\n\n if (built && !isImageMask) {\n // The (group/shape) mask wrapper MUST own a real box for the CSS mask to clip\n // anything : its content is `position:absolute`, so fill the parent's\n // containing block to share the absolutely-placed body's coordinate space.\n // `overflow:hidden` bounds the (oversized) masked content to this box — the\n // CSS `mask` alone does NOT clip it (removing it leaked the 2786×1491 tile\n // group everywhere).\n // Only a FEATHERED mask grows the box (+ shifts the coverage, mask.tsx) ;\n // a sharp mask uses pad 0 → inset:0, identical to the un-padded structure.\n const pad = built.feather ? MASK_FEATHER_PAD : 0;\n body = (\n <div\n style={{\n position: \"absolute\",\n inset: -pad,\n overflow: \"hidden\",\n ...built.style,\n }}\n >\n <svg width={0} height={0} style={{ position: \"absolute\" }} aria-hidden>\n <defs>{built.def}</defs>\n </svg>\n {/* Inner box inset by +PAD cancels the wrapper's −PAD grow for the\n CONTENT — the body keeps its original coordinates while the masked\n box (and its feathered rim) is the bigger one. */}\n <div style={{ position: \"absolute\", inset: pad }}>{body}</div>\n </div>\n );\n }\n // Hoist the node's blend ABOVE the wrapper+mask : an outer box carrying ONLY\n // `mix-blend-mode` (no transform / opacity / filter / mask) so it composites\n // the masked result with the SCENE backdrop. The caramel 3d-render then\n // hard-lights over the warm gradient (orange) instead of its raw image (blue).\n if (built && maskHoistsBlend) {\n const hoisted = parseBlendMode(resolved.blendMode);\n body = (\n <div\n style={{\n position: \"absolute\",\n inset: 0,\n mixBlendMode: hoisted as React.CSSProperties[\"mixBlendMode\"],\n }}\n >\n {body}\n </div>\n );\n }\n\n // Scalar bindAnimate channels apply on a wrapping motion.div (same\n // composition model as UniversalWrapper). Motion values mutate the\n // style directly — zero React re-render per frame on the hot path.\n if (bindAnimate.motionStyle) {\n body = (\n <motion.div data-lumencast-bind-animate={node.id ?? \"\"} style={bindAnimate.motionStyle}>\n {body}\n </motion.div>\n );\n }\n\n // LSML 1.1 §6.6 — when a primitive declares keyframes, wrap the\n // rendered subtree in a player that drives framer-motion through the\n // step path. The player handles replay-on-key-change and reads any\n // ambient stagger delay from StaggerContext (§6.7).\n if (node.keyframes) {\n return (\n <KeyframePlayer keyframes={node.keyframes} store={store} nodeId={node.id}>\n {body}\n </KeyframePlayer>\n );\n }\n return body;\n}\n\nfunction extractSizing(value: unknown): { x?: SizingMode; y?: SizingMode } | undefined {\n if (typeof value !== \"object\" || value === null) return undefined;\n const obj = value as { x?: unknown; y?: unknown };\n const out: { x?: SizingMode; y?: SizingMode } = {};\n if (obj.x === \"fixed\" || obj.x === \"hug\" || obj.x === \"fill\") out.x = obj.x;\n if (obj.y === \"fixed\" || obj.y === \"hug\" || obj.y === \"fill\") out.y = obj.y;\n return out.x !== undefined || out.y !== undefined ? out : undefined;\n}\n\nfunction finite(v: unknown): number | undefined {\n return typeof v === \"number\" && Number.isFinite(v) ? v : undefined;\n}\n\n/** ADR 002 §3.1 (D1) — form the absolute-placement `position:{x,y}` from\n * the compiler-flattened `resolved.x`/`resolved.y`. BOTH axes must be\n * finite numbers : a partial or malformed pair yields `undefined` (the\n * node stays in the normal flow — RC#3 mistyped-position is inert, not\n * injected). Values are plain numbers, never untrusted strings.\n *\n * ADR 006 §3.3 — a `meet.peer` node produced DIRECTLY by the Prism from-scene\n * export bypasses `@lumencast/compiler`, so its geometry arrives in the NESTED\n * LSML shape (`position:{x,y}`) rather than flattened `x`/`y`. We accept that\n * nested form as a fallback ONLY when the flat form is absent. This is purely\n * additive : every compiled bundle always carries flat `x`/`y` (which win), so\n * no existing node's placement changes. */\nfunction extractPosition(resolved: Record<string, unknown>): { x: number; y: number } | undefined {\n let x = finite(resolved.x);\n let y = finite(resolved.y);\n if (x === undefined && y === undefined) {\n const nested = resolved.position as { x?: unknown; y?: unknown } | undefined;\n if (nested && typeof nested === \"object\") {\n x = finite(nested.x);\n y = finite(nested.y);\n }\n }\n if (x === undefined || y === undefined) return undefined;\n return { x, y };\n}\n\n/** ADR 002 §3.1 (D1) — the absolute box size from `resolved.width`/\n * `resolved.height`. Only meaningful alongside `position` (the wrapper\n * ignores it otherwise). Partial sizes are allowed (one axis hugs).\n *\n * ADR 006 §3.3 — like `extractPosition`, accept the NESTED `size:{w,h}` shape\n * as a fallback for an uncompiled `meet.peer` node (flat `width`/`height`\n * always win when present, so compiled bundles are unaffected). Without this,\n * the `meet.peer` wrapper got a position but NO size → the `<video>` filled a\n * collapsed box instead of the authored geometry (the observed RC-Geo bug). */\nfunction extractSize(resolved: Record<string, unknown>): { w?: number; h?: number } | undefined {\n let w = finite(resolved.width);\n let h = finite(resolved.height);\n if (w === undefined && h === undefined) {\n const nested = resolved.size as { w?: unknown; h?: unknown } | undefined;\n if (nested && typeof nested === \"object\") {\n w = finite(nested.w);\n h = finite(nested.h);\n }\n }\n if (w === undefined && h === undefined) return undefined;\n return { w, h };\n}\n\n/** True when a child node carries a finite `{x,y}` absolute position\n * (static prop OR a bound `x`/`y`). Used by a container primitive to\n * decide whether to establish a positioned containing block. A bound\n * position is treated as \"absolute\" structurally — the key presence is\n * static even if the value moves live. */\nfunction childIsAbsolute(child: RenderNode): boolean {\n if (child.kind === \"frame\") return false; // a frame positions itself\n const props = child.props ?? {};\n const bindings = child.bindings ?? {};\n // ADR 006 §3.3 — also recognise the nested `position:{x,y}` shape (an\n // uncompiled `meet.peer` node), mirroring extractPosition's fallback.\n const nested = props.position as { x?: unknown; y?: unknown } | undefined;\n const hasX =\n finite(props.x) !== undefined ||\n \"x\" in bindings ||\n (nested ? finite(nested.x) !== undefined : false);\n const hasY =\n finite(props.y) !== undefined ||\n \"y\" in bindings ||\n (nested ? finite(nested.y) !== undefined : false);\n return hasX && hasY;\n}\n\nfunction Repeat({ node, store }: TreeProps): ReactNode {\n useSignals();\n const scope = usePathScope();\n checkNodeProps(node);\n\n const itemsBinding = node.bindings?.items;\n const items =\n itemsBinding === undefined\n ? []\n : ((store.signal(scopedPath(scope, itemsBinding)).value as unknown[] | undefined) ?? []);\n if (!Array.isArray(items)) return null;\n\n const template = node.children?.[0];\n if (!template) return null;\n\n // LSML 1.1 §6.7 — `stagger_ms` produces wave-like reveals across\n // iterations. We compute the per-iteration delay (capped) and feed\n // it to descendants via StaggerContext so the KeyframePlayer (and\n // future animate-aware primitives) can pick it up without per-\n // iteration scripting. `stagger_ms: 0` (or unset) is a no-op.\n const staggerMs = typeof node.stagger_ms === \"number\" ? node.stagger_ms : 0;\n\n return (\n <>\n {items.map((_item, idx) => {\n const delayMs = computeStaggerDelayMs(idx, staggerMs);\n const tree = (\n <PathScopeProvider key={idx} prefix={`${itemsBinding ?? \"\"}.${idx}`}>\n <Tree node={template} store={store} />\n </PathScopeProvider>\n );\n if (delayMs <= 0) return tree;\n return (\n <StaggerContext.Provider key={idx} value={delayMs}>\n {tree}\n </StaggerContext.Provider>\n );\n })}\n </>\n );\n}\n\nfunction resolveProps(node: RenderNode, store: Store, scope: string): Record<string, unknown> {\n const out: Record<string, unknown> = { ...(node.props ?? {}) };\n if (node.bindings) {\n for (const [propKey, path] of Object.entries(node.bindings)) {\n const fullPath = scopedPath(scope, path);\n out[propKey] = store.signal(fullPath).value;\n }\n }\n return out;\n}\n\n/** Helper for the useMemo deps array — read each bound signal so the\n * memo invalidates when any binding moves. */\nfunction readBindingValues(node: RenderNode, store: Store, scope: string): unknown[] {\n if (!node.bindings) return [];\n const values: unknown[] = [];\n for (const path of Object.values(node.bindings)) {\n values.push(store.signal(scopedPath(scope, path)).value);\n }\n return values;\n}\n"],"names":["Stack","resolved","children","establishesContainingBlock","direction","gap","numberOr","wrap","crossGap","align","justify","isHorizontal","style","jsx","v","fallback","Grid","cols","rows","MAX_LEN","CHARSET_RE","HEX_RE","NUM","ALPHA","SP","RGB_RE","HSL_RE","NAMED","parseCssColor","value","lower","m","pct","p","max","ch","warnRejectedColor","field","nodeId","emitDiagnostic","AllowedHostsCtx","createContext","AllowedHostsProvider","hosts","useAllowedHosts","useContext","readAllowedHosts","bundle","list","h","gateSrc","src","allowedHosts","decision","checkHostAllowed","BLEND_MODES","parseBlendMode","OBJECT_FITS","parseObjectFitRuntime","gradientIdSeq","nextGradientId","renderFill","fill","mixBlendMode","ref","cssWithOpacity","imgId","par","objectFitToPreserveAspectRatio","id","x1","y1","x2","y2","t","len","an","bn","rad","s","i","cx","cy","r","objectFitToBackgroundSize","fit","backgroundsToCss","fills","kept","layers","f","css","fillToCss","blends","b","firstImage","cssUrl","color","c","safeStops","stops","angle","opacity","hex","a","sanitizeFills","out","rejected","parseFills","isFill","_drop","rest","k","gateImageFills","Frame","transitionFor","animateInitial","x","y","width","sizeProp","height","scale","rotate","flipY","radius","rawBackground","legacyBackground","backgrounds","clipsContent","resolveClipsContent","tx","resolveTransition","shadowFilter","boxShadow","buildShadows","play","mountPlay","motion","toFramer","dropParts","boxParts","spec","blur","spread","inset","insetKw","TEXT_TRANSFORMS","TEXT_DECORATIONS","FONT_STYLES","MAX_MAX_LINES","MAX_LINE_HEIGHT","MAX_LETTER_SPACING_PX","FONT_FAMILY_RE","parseFontFamily","Text","size","weight","font","parsed","colour","typography","resolveTypography","lineHeight","boundedNumber","letterSpacing","textTransform","enumValue","textDecoration","fontStyle","maxLines","positiveInteger","allow","warnRejectedTypo","min","Image","alt","position","dimOr","MAX_SUBPATH_LEN","MAX_SUBPATH_COMMANDS","MAX_SUBPATHS","CMD_CHARS","isDigit","code","isSeparator","validatePathData","d","n","commands","sawCommand","digits","fracDigits","expDigits","parseShapePaths","rawPaths","rawPathData","warnPath","idx","entry","toFillRule","windingRule","reason","geometryKind","props","buildShapeOutline","paint","keyPrefix","kind","stroke","strokeWidth","subpaths","buildMaskCoverageFromShape","node","GROUP_MASK_MAX_CHILDREN","GROUP_MASK_MAX_DEPTH","isHidden","numProp","key","buildMaskCoverageFromGroup","maxDepth","maxChildren","parts","collectCoverage","coverageIsFeathered","depth","child","composited","part","sub","childBlur","bf","Shape","legacyFill","safeColor","legacyStroke","legacyStrokeWidth","ariaLabel","transition","strokes","parseStrokes","fillRenders","allDefs","fillLayers","strokeLayers","stackedFills","stackedStrokes","effectiveStrokes","renderShape","jsxs","layer","LivePeerVideo","peerLabel","objectFit","muted","runtime","useOptionalLumencastRuntime","resolvePeerStream","subscribePeerStream","videoRef","useRef","stream","setStream","useState","useEffect","el","Media","loop","mute","autoplay","fillBox","MeetPeer","MeetPeerSlot","slotRef","warned","Instance","sceneId","sceneVersion","cache","claimCaptureStream","sourceKind","deviceRef","resolveCaptureDevice","md","deviceId","captureSourceId","declaredRef","physicalId","acquire","channel","deviceConstraint","existing","promise","releaseCaptureStream","stopStream","track","Capture","isCaptureCapable","cancelled","claimedKey","claim","media","isVisualKind","PRIMITIVES","PathScopeContext","PathScopeProvider","prefix","parent","next","usePathScope","scopedPath","path","flexFor","mode","sizingToFlex","sizing","UniversalWrapper","visible","rotation","blendMode","hasOpacity","hasRotation","hasFlipY","hasBlur","hasSizing","hasPosition","hasBlendMode","transform","filter","sizingFlex","outer","inner","FRAMER_EASE_MAP","compileForFramer","kf","steps","first","last","times","animate","pullChannel","pullTransform","prop","any","values","safe","sanitizeCssFilterString","warnRejectedFilter","FILTER_IDENTITY","defaultFor","framerKey","StaggerContext","STAGGER_CAP_MS","computeStaggerDelayMs","index","staggerMs","raw","KeyframePlayer","keyframes","store","useSignals","scope","staggerDelayMs","lastKeyValue","replayTokenRef","compiled","firstFrame","ReplayOnMount","arr","createFrameCoalescer","flush","schedule","cb","cancel","pending","frameId","disposed","onFrame","entries","NAMED_RGB","cssColorToRgba","hexToRgba","g","alphaChannel","l","hslToRgb","packed","token","clamp01","hue","hp","mixRgba","serializeRgba","rgba","BIND_ANIMATE_COLOR_PROPS","resolveScalarTargets","toFiniteScalar","ty","sx","sy","clampFilterChannel","DEFAULT_BIND_ANIMATE_TRANSITION","transitionLookupKey","NO_COLORS","useBindAnimate","bindings","useMotionValue","scaleX","scaleY","brightness","useTransform","br","colorProps","setColorProps","channels","mvs","controls","colorState","animatedOnce","mounted","fullPath","declared","base","dispatch","instant","colorProp","end","prev","start","mixed","targets","warnRejectedBindValue","coalescer","disposers","effect","useMemo","MASK_TYPES","MASK_FEATHER_PAD","MASK_OPS","maskIdSeq","nextMaskId","safeIdRef","finite","parseMaskSpec","source","sr","pos","buildMask","mask","resolveShape","boxSize","feather","w","geom","content","url","rect","usable","sizeCss","posCss","imgGeom","safeRef","Fragment","def","EMPTY","ShapeIndexCtx","buildShapeIndex","root","stack","ShapeIndexProvider","useShapeIndex","Tree","Repeat","Node","shapeIndex","resolveProps","readBindingValues","bindAnimate","checkNodeProps","Primitive","liveTransitions","ts","maskHoistsBlend","universal","extractSizing","extractPosition","extractSize","hasAbsoluteChild","childIsAbsolute","resolvedWithColors","primitiveEl","built","target","isImageMask","body","pad","hoisted","obj","nested","hasX","hasY","itemsBinding","items","template","_item","delayMs","tree","propKey"],"mappings":"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"}
|