/**
 * Generate CSS for the 6 universal visual treatment categories,
 * plus theme treatment overrides.
 *
 * Layer 1: Base treatments (the 6 categories)
 * Layer 2: Theme treatment overrides (merged into base rules)
 * Layer 3: Decorator stub (AI generates decorator CSS from structured definitions)
 */
export function generateTreatmentCSS(
  spatialTokens: Record<string, string>,
  treatmentOverrides?: Record<string, Record<string, string>>,
  themeDecorators?: Record<string, string>,
  themeName?: string,
  themeDecoratorDefinitions?: Record<
    string,
    {
      description?: string;
      intent?: string;
      suggested_properties?: Record<string, string>;
      /**
       * Optional state-variant CSS emitted as pseudo-class rules on the same
       * selector. Each is a flat property map; keys are CSS declarations, not
       * nested selectors. Missing fields fall back to current behavior (base
       * properties only). Introduced for P0-1 so decorator prose that
       * promises hover / focus / active styling (e.g. "carbon-card gains a
       * neon cyan shadow on hover") can be delivered by the content pipeline
       * instead of every scaffolded app reaching for inline styles.
       */
      hover_properties?: Record<string, string>;
      focus_properties?: Record<string, string>;
      active_properties?: Record<string, string>;
      pairs_with?: string[];
      usage?: string[];
    }
  >,
): string {
  const lines: string[] = [];
  const decoratorAnimationNames = new Set<string>();

  lines.push('/* Generated by @decantr/cli — Visual Treatment System */');
  lines.push('');

  // ── Layer 1 + 2: Base Treatments (with optional overrides merged) ──

  lines.push('@layer treatments {');
  lines.push('');
  lines.push('/* ── Layer 1: Base Treatments ── */');
  lines.push('');

  // Properties that are theme-specific effects and should not merge into the base rule.
  // These are emitted in a separate theme-scoped block instead.
  const THEME_ONLY_PROPS = new Set(['backdrop-filter', '-webkit-backdrop-filter']);

  // Collect theme-scoped overrides to emit after base rules
  const themeOverrideRules: string[] = [];

  // Helper: merge overrides into a property map, then emit rule.
  // Theme-specific properties (e.g. backdrop-filter) are separated and
  // emitted later in a theme-scoped block so they don't leak into the base.
  function emitRule(selector: string, props: [string, string][]): void {
    const treatmentName = selector.replace(/^\./, '').replace(/[:[\s].+$/, '');
    const overrides = treatmentOverrides?.[treatmentName];
    const merged = new Map<string, string>();
    for (const [prop, val] of props) {
      merged.set(prop, val);
    }
    if (overrides && selector === `.${treatmentName}`) {
      const themeProps: [string, string][] = [];
      for (const [prop, val] of Object.entries(overrides)) {
        if (THEME_ONLY_PROPS.has(prop)) {
          themeProps.push([prop, val]);
        } else {
          merged.set(prop, val);
        }
      }
      // Emit theme-only properties in a separate scoped rule
      if (themeProps.length > 0 && themeName) {
        const themeSelector = `[data-theme="${themeName}"] ${selector}`;
        const themeBody = themeProps.map(([p, v]) => `  ${p}: ${v};`).join('\n');
        themeOverrideRules.push(`${themeSelector} {\n${themeBody}\n}`);
      }
    }
    const body = Array.from(merged.entries())
      .map(([p, v]) => `  ${p}: ${v};`)
      .join('\n');
    lines.push(`${selector} {`);
    lines.push(body);
    lines.push('}');
    lines.push('');
  }

  // ── 1. Interactive Surface — .d-interactive ──

  emitRule('.d-interactive', [
    ['display', 'inline-flex'],
    ['align-items', 'center'],
    ['gap', '0.5em'],
    [
      'padding',
      'calc(var(--d-interactive-py) * var(--d-density-scale, 1)) var(--d-interactive-px)',
    ],
    ['border', '1px solid var(--d-border)'],
    ['border-radius', 'var(--d-radius)'],
    ['background', 'transparent'],
    ['color', 'var(--d-text)'],
    ['font', 'inherit'],
    ['cursor', 'pointer'],
    ['text-decoration', 'none'],
    [
      'transition',
      'background 0.15s ease, border-color 0.15s ease, color 0.15s ease, box-shadow 0.15s ease, opacity 0.15s ease',
    ],
  ]);

  emitRule('.d-interactive:hover', [
    ['border-color', 'var(--d-primary-hover)'],
    ['background', 'var(--d-surface)'],
  ]);

  emitRule('.d-interactive:focus-visible', [
    ['outline', '2px solid var(--d-primary)'],
    ['outline-offset', '2px'],
  ]);

  emitRule('.d-interactive:disabled', [
    ['opacity', '0.5'],
    ['cursor', 'not-allowed'],
    ['pointer-events', 'none'],
  ]);

  emitRule('.d-interactive[data-variant="primary"]', [
    ['background', 'var(--d-primary)'],
    ['color', '#fff'],
    ['border-color', 'var(--d-primary)'],
  ]);

  emitRule('.d-interactive[data-variant="primary"]:hover', [
    ['background', 'var(--d-primary-hover)'],
    ['border-color', 'var(--d-primary-hover)'],
  ]);

  emitRule('.d-interactive[data-variant="ghost"]', [
    ['border-color', 'transparent'],
    ['background', 'transparent'],
  ]);

  emitRule('.d-interactive[data-variant="ghost"]:hover', [['background', 'var(--d-surface)']]);

  emitRule('.d-interactive[data-variant="danger"]', [
    ['background', 'var(--d-error)'],
    ['color', '#fff'],
    ['border-color', 'var(--d-error)'],
  ]);

  // Size variants. Default (no data-size) is "md". Use "sm" for compact chrome
  // (52px-tall headers, 32px nav items) and "lg" for prominent primary CTAs.
  // Eliminates inline padding/font-size workarounds for non-default sizes.
  emitRule('.d-interactive[data-size="sm"]', [
    [
      'padding',
      'calc(var(--d-interactive-py) * 0.5 * var(--d-density-scale, 1)) calc(var(--d-interactive-px) * 0.75)',
    ],
    ['font-size', '0.875rem'],
    ['gap', '0.375em'],
  ]);

  emitRule('.d-interactive[data-size="md"]', [
    // Explicit md — same as default. Lets authors opt in without inheriting
    // contextual sizing from an ancestor that may have set data-size.
    [
      'padding',
      'calc(var(--d-interactive-py) * var(--d-density-scale, 1)) var(--d-interactive-px)',
    ],
    ['font-size', '1rem'],
    ['gap', '0.5em'],
  ]);

  emitRule('.d-interactive[data-size="lg"]', [
    [
      'padding',
      'calc(var(--d-interactive-py) * 1.5 * var(--d-density-scale, 1)) calc(var(--d-interactive-px) * 1.25)',
    ],
    ['font-size', '1.125rem'],
    ['gap', '0.625em'],
  ]);

  // ── 2. Container Surface — .d-surface ──

  emitRule('.d-surface', [
    ['background', 'var(--d-surface)'],
    ['border', '1px solid var(--d-border)'],
    ['border-radius', 'var(--d-radius)'],
    ['box-shadow', 'var(--d-shadow)'],
    ['padding', 'calc(var(--d-surface-p) * var(--d-density-scale, 1))'],
  ]);

  emitRule('.d-surface[data-elevation="raised"]', [
    ['background', 'var(--d-surface-raised)'],
    ['box-shadow', 'var(--d-shadow-md)'],
  ]);

  emitRule('.d-surface[data-elevation="overlay"]', [
    ['background', 'var(--d-surface-raised)'],
    ['box-shadow', 'var(--d-shadow-lg)'],
    ['z-index', '50'],
  ]);

  emitRule('.d-surface[data-interactive]', [['cursor', 'pointer']]);

  emitRule('.d-surface[data-interactive]:hover', [
    ['border-color', 'var(--d-primary-hover, var(--d-border))'],
    ['box-shadow', 'var(--d-shadow-md)'],
    ['transition', 'border-color 0.15s ease, box-shadow 0.15s ease'],
  ]);

  // ── 3. Data Display — .d-data, .d-data-header, .d-data-row, .d-data-cell ──

  emitRule('.d-data', [
    ['width', '100%'],
    ['border-collapse', 'collapse'],
    ['text-align', 'left'],
    ['font-size', '0.875rem'],
  ]);

  emitRule('.d-data-header', [
    ['padding', 'calc(var(--d-data-py) * var(--d-density-scale, 1)) var(--d-content-gap)'],
    ['font-weight', '500'],
    ['color', 'var(--d-text-muted)'],
    ['border-bottom', '1px solid var(--d-border)'],
    ['font-size', '0.75rem'],
    ['text-transform', 'uppercase'],
    ['letter-spacing', '0.05em'],
  ]);

  emitRule('.d-data-row', [
    ['border-bottom', '1px solid var(--d-border)'],
    ['transition', 'background 0.1s ease'],
  ]);

  emitRule('.d-data-row:hover', [['background', 'var(--d-surface)']]);

  emitRule('.d-data-cell', [
    ['padding', 'calc(var(--d-data-py) * var(--d-density-scale, 1)) var(--d-content-gap)'],
    ['vertical-align', 'middle'],
  ]);

  // ── 4. Form Control — .d-control ──

  emitRule('.d-control', [
    ['background', 'var(--d-surface)'],
    ['color', 'var(--d-text)'],
    ['padding', 'calc(var(--d-control-py) * var(--d-density-scale, 1)) 0.75rem'],
    ['border-radius', 'var(--d-radius)'],
    ['border', '1px solid var(--d-border)'],
    ['width', '100%'],
    ['outline', 'none'],
    ['font', 'inherit'],
    ['transition', 'border-color 0.15s ease, box-shadow 0.15s ease'],
  ]);

  emitRule('.d-control:focus', [
    ['border-color', 'var(--d-primary)'],
    ['box-shadow', '0 0 0 3px color-mix(in srgb, var(--d-primary) 25%, transparent)'],
  ]);

  emitRule('.d-control::placeholder', [['color', 'var(--d-text-muted)']]);

  emitRule('.d-control:disabled', [
    ['opacity', '0.5'],
    ['cursor', 'not-allowed'],
  ]);

  emitRule('.d-control[aria-invalid]', [
    ['border-color', 'var(--d-error)'],
    ['box-shadow', '0 0 0 3px color-mix(in srgb, var(--d-error) 15%, transparent)'],
  ]);

  // ── 5. Section Rhythm — .d-section ──

  // ── Section Rhythm ──
  emitRule('.d-section', [
    ['--d-density-scale', '1'],
    ['padding', 'calc(var(--d-section-py) * var(--d-density-scale)) 0'],
  ]);

  // Density variants — broadcast scale to descendants
  lines.push('.d-section[data-density="compact"] {');
  lines.push('  --d-density-scale: 0.65;');
  lines.push('}');
  lines.push('');

  lines.push('.d-section[data-density="spacious"] {');
  lines.push('  --d-density-scale: 1.4;');
  lines.push('}');
  lines.push('');

  // Adjacent section separator — density-aware gap
  lines.push('.d-section + .d-section {');
  lines.push('  border-top: 1px solid transparent;');
  lines.push(
    '  border-image: linear-gradient(to right, transparent, var(--d-border), transparent) 1;',
  );
  lines.push('  margin-top: calc(var(--d-section-gap) * var(--d-density-scale, 1));');
  lines.push('}');
  lines.push('');

  // ── 6. Inline Annotation — .d-annotation ──

  emitRule('.d-annotation', [
    ['display', 'inline-flex'],
    ['align-items', 'center'],
    ['gap', '0.25em'],
    ['font-size', '0.75rem'],
    ['font-weight', '500'],
    ['padding', '0.125rem 0.5rem'],
    ['border-radius', 'var(--d-radius-full)'],
    ['background', 'color-mix(in srgb, var(--d-surface-raised) 88%, transparent)'],
    ['border', '1px solid color-mix(in srgb, var(--d-border) 72%, transparent)'],
    ['color', 'var(--d-text-muted)'],
    ['white-space', 'nowrap'],
  ]);

  emitRule('.d-annotation[data-status="success"]', [
    ['background', 'color-mix(in srgb, var(--d-success) 15%, transparent)'],
    ['color', 'var(--d-success)'],
  ]);

  emitRule('.d-annotation[data-status="error"]', [
    ['background', 'color-mix(in srgb, var(--d-error) 15%, transparent)'],
    ['color', 'var(--d-error)'],
  ]);

  emitRule('.d-annotation[data-status="warning"]', [
    ['background', 'color-mix(in srgb, var(--d-warning) 15%, transparent)'],
    ['color', 'var(--d-warning)'],
  ]);

  emitRule('.d-annotation[data-status="info"]', [
    ['background', 'color-mix(in srgb, var(--d-info) 15%, transparent)'],
    ['color', 'var(--d-info)'],
  ]);

  // ── 7. Label Utility — .d-label ──

  // ── Label ──
  emitRule('.d-label', [
    ['font-size', '0.7rem'],
    ['font-weight', '600'],
    ['text-transform', 'uppercase'],
    ['letter-spacing', '0.08em'],
    ['color', 'var(--d-text-muted)'],
    ['font-family', 'var(--d-font-mono, ui-monospace, monospace)'],
    ['display', 'block'],
    ['margin-bottom', 'calc(var(--d-label-mb) * var(--d-density-scale, 1))'],
  ]);

  // Anchored section header variant — accent border. Used as the
  // section eyebrow (e.g., "PLATFORM HEALTH", "CHARTS") that marks
  // the start of a new content section.
  emitRule('.d-label[data-anchor]', [
    ['padding-left', 'var(--d-label-px)'],
    ['border-left', '2px solid var(--d-accent)'],
  ]);

  // NOTE: inter-section spacing is owned by the parent `d-shell-body`
  // container's flex `gap`, not by the eyebrow itself. A previous
  // `* + .d-label[data-anchor]` rule turned out to be fragile because
  // the adjacent-sibling combinator silently breaks the moment a
  // SectionHeading wrapper is introduced (which is exactly the kind of
  // composition the rest of the spec encourages). Putting the gap on
  // the flow container handles all wrapping shapes uniformly.

  // ── 8. Text Link — .d-link ──
  // Chromeless inline anchor. Covers breadcrumbs, footer links, inline
  // body-copy links, and "learn more" affordances. The v4 ecommerce
  // harness forced 5+ hand-rolled `.nav-link` / `.nav-link-active`
  // classes because there was no link treatment.

  emitRule('.d-link', [
    ['color', 'var(--d-text)'],
    ['text-decoration', 'none'],
    ['border-bottom', '1px solid transparent'],
    ['transition', 'color 0.15s ease, border-color 0.15s ease'],
    ['cursor', 'pointer'],
  ]);

  emitRule('.d-link:hover', [
    ['color', 'var(--d-primary)'],
    ['border-bottom-color', 'var(--d-primary)'],
  ]);

  emitRule('.d-link:focus-visible', [
    ['outline', '2px solid var(--d-primary)'],
    ['outline-offset', '2px'],
    ['border-radius', '2px'],
  ]);

  emitRule('.d-link[data-variant="subtle"]', [['color', 'var(--d-text-muted)']]);

  emitRule('.d-link[data-variant="subtle"]:hover', [
    ['color', 'var(--d-text)'],
    ['border-bottom-color', 'var(--d-text)'],
  ]);

  emitRule('.d-link[data-variant="strong"]', [
    ['color', 'var(--d-primary)'],
    ['font-weight', '500'],
  ]);

  emitRule('.d-link[data-variant="strong"]:hover', [
    ['color', 'var(--d-primary-hover)'],
    ['border-bottom-color', 'var(--d-primary-hover)'],
  ]);

  // Active state for nav-link-style usage (e.g., sidebar/topnav when
  // current route matches). Pair with aria-current="page" for a11y.
  emitRule('.d-link[aria-current="page"], .d-link[data-active="true"]', [
    ['color', 'var(--d-primary)'],
    ['font-weight', '500'],
  ]);

  // ── 9. Icon Button — .d-icon-btn ──
  // Chromeless square button for icon-only actions (header actions,
  // card overflow menus, close X, etc.). Avoids the hand-rolled
  // `.icon-btn` / `.header-btn` classes the ecommerce harness produced.

  emitRule('.d-icon-btn', [
    ['display', 'inline-flex'],
    ['align-items', 'center'],
    ['justify-content', 'center'],
    ['width', '2rem'],
    ['height', '2rem'],
    ['border', 'none'],
    ['background', 'transparent'],
    ['color', 'var(--d-text-muted)'],
    ['border-radius', 'var(--d-radius-sm)'],
    ['cursor', 'pointer'],
    ['transition', 'background 0.15s ease, color 0.15s ease'],
  ]);

  emitRule('.d-icon-btn:hover', [
    ['background', 'color-mix(in srgb, var(--d-text) 8%, transparent)'],
    ['color', 'var(--d-text)'],
  ]);

  emitRule('.d-icon-btn:focus-visible', [
    ['outline', '2px solid var(--d-primary)'],
    ['outline-offset', '2px'],
  ]);

  emitRule('.d-icon-btn:disabled', [
    ['opacity', '0.5'],
    ['cursor', 'not-allowed'],
    ['pointer-events', 'none'],
  ]);

  emitRule('.d-icon-btn[data-size="sm"]', [
    ['width', '1.5rem'],
    ['height', '1.5rem'],
  ]);

  emitRule('.d-icon-btn[data-size="lg"]', [
    ['width', '2.5rem'],
    ['height', '2.5rem'],
  ]);

  emitRule('.d-icon-btn[data-variant="primary"]', [
    ['background', 'var(--d-primary)'],
    ['color', '#fff'],
  ]);

  emitRule('.d-icon-btn[data-variant="primary"]:hover', [['background', 'var(--d-primary-hover)']]);

  // ── 10. Sidebar Nav Link — .d-nav-link ──
  // Muted-by-default nav-link row. `[data-active]` or `aria-current="page"`
  // switches to the "current route" pill style with primary accent.
  // Replaces hand-rolled `.sidebar-link` / `.nav-link-active` classes.

  emitRule('.d-nav-link', [
    ['display', 'flex'],
    ['align-items', 'center'],
    ['gap', '0.5rem'],
    ['padding', '0.5rem 0.75rem'],
    ['border-radius', 'var(--d-radius-sm)'],
    ['color', 'var(--d-text-muted)'],
    ['text-decoration', 'none'],
    ['font-size', '0.875rem'],
    ['cursor', 'pointer'],
    ['transition', 'background 0.15s ease, color 0.15s ease'],
    ['border-left', '2px solid transparent'],
  ]);

  emitRule('.d-nav-link:hover', [
    ['color', 'var(--d-text)'],
    ['background', 'color-mix(in srgb, var(--d-text) 6%, transparent)'],
  ]);

  emitRule('.d-nav-link:focus-visible', [
    ['outline', '2px solid var(--d-primary)'],
    ['outline-offset', '2px'],
  ]);

  // Active state — matches whichever attribute the framework produces.
  emitRule('.d-nav-link[aria-current="page"], .d-nav-link[data-active="true"]', [
    ['color', 'var(--d-primary)'],
    ['background', 'color-mix(in srgb, var(--d-primary) 10%, transparent)'],
    ['border-left-color', 'var(--d-primary)'],
    ['font-weight', '500'],
  ]);

  // ── 11. Stepper Chip — .d-step-chip ──
  // Circular badge for wizard/checkout steppers. Handles the three
  // canonical states (pending / active / done).

  emitRule('.d-step-chip', [
    ['display', 'inline-flex'],
    ['align-items', 'center'],
    ['justify-content', 'center'],
    ['width', '2rem'],
    ['height', '2rem'],
    ['border-radius', '50%'],
    ['border', '1.5px solid var(--d-border)'],
    ['background', 'transparent'],
    ['color', 'var(--d-text-muted)'],
    ['font-size', '0.875rem'],
    ['font-weight', '600'],
    ['font-variant-numeric', 'tabular-nums'],
    ['transition', 'background 0.15s ease, border-color 0.15s ease, color 0.15s ease'],
  ]);

  emitRule('.d-step-chip[data-shape="pill"]', [
    ['width', 'auto'],
    ['min-width', '2rem'],
    ['height', 'auto'],
    ['min-height', '2rem'],
    ['padding', '0.375rem 0.875rem'],
    ['border-radius', '9999px'],
    ['gap', '0.375rem'],
    ['font-variant-numeric', 'normal'],
  ]);

  emitRule('.d-step-chip[data-step-state="active"]', [
    ['background', 'var(--d-primary)'],
    ['border-color', 'var(--d-primary)'],
    ['color', '#fff'],
  ]);

  emitRule('.d-step-chip[data-step-state="done"]', [
    ['background', 'color-mix(in srgb, var(--d-success) 15%, transparent)'],
    ['border-color', 'var(--d-success)'],
    ['color', 'var(--d-success)'],
  ]);

  // ── 12a. Agent Node + Ports — .d-agent-node ──
  // Card for spatial/graph canvases where nodes render as positioned
  // cards with connection ports. Eliminates the 15-inline-style cluster
  // the v4 harness reported in AgentSwarmCanvas. Pair with absolute
  // positioning on the parent canvas; this treatment only handles the
  // card's internal layout + port anchors.

  emitRule('.d-agent-node', [
    ['display', 'flex'],
    ['flex-direction', 'column'],
    ['gap', '0.5rem'],
    ['position', 'relative'],
    ['min-width', '200px'],
    ['max-width', '260px'],
    ['padding', '0.75rem'],
    ['background', 'var(--d-surface)'],
    ['border', '1px solid var(--d-border)'],
    ['border-radius', 'var(--d-radius)'],
    ['cursor', 'pointer'],
    ['transition', 'border-color 0.15s ease, box-shadow 0.15s ease, transform 0.15s ease'],
  ]);

  emitRule('.d-agent-node:hover', [
    ['border-color', 'var(--d-primary)'],
    ['transform', 'translateY(-1px)'],
  ]);

  emitRule('.d-agent-node[data-status="error"]', [
    ['box-shadow', '0 0 12px color-mix(in srgb, var(--d-error) 25%, transparent)'],
    ['border-color', 'color-mix(in srgb, var(--d-error) 60%, transparent)'],
  ]);

  emitRule('.d-agent-node[data-status="active"]', [['border-color', 'var(--d-primary)']]);

  // Connection ports — positioned absolutely on the node edges so SVG
  // connection paths can anchor to predictable coordinates instead of
  // guessing center offsets. Pair with canvas that reads getBoundingClientRect
  // on these elements.
  emitRule('.d-port', [
    ['position', 'absolute'],
    ['width', '8px'],
    ['height', '8px'],
    ['border-radius', '50%'],
    ['background', 'var(--d-border)'],
    ['top', '50%'],
    ['transform', 'translateY(-50%)'],
    ['transition', 'background 0.15s ease'],
  ]);

  emitRule('.d-port[data-side="left"]', [['left', '-4px']]);

  emitRule('.d-port[data-side="right"]', [['right', '-4px']]);

  emitRule('.d-port[data-side="top"]', [
    ['top', '-4px'],
    ['left', '50%'],
    ['transform', 'translateX(-50%)'],
  ]);

  emitRule('.d-port[data-side="bottom"]', [
    ['bottom', '-4px'],
    ['top', 'auto'],
    ['left', '50%'],
    ['transform', 'translateX(-50%)'],
  ]);

  emitRule('.d-port[data-active="true"]', [['background', 'var(--d-primary)']]);

  // ── 12b. CTA Banner — .d-cta-banner ──
  // Prominent full-width CTA with gradient wash + dark pill action.
  // Replaces the inline-hex cluster the v4 harness reported in CtaBanner
  // (the pack contract was asking for `_bgdark` / `_fgwhite` atoms that
  // don't exist — now there's a semantic treatment for it).

  emitRule('.d-cta-banner', [
    ['display', 'flex'],
    ['flex-direction', 'column'],
    ['align-items', 'center'],
    ['justify-content', 'center'],
    ['gap', '1rem'],
    ['padding', '3rem 1.5rem'],
    ['border-radius', 'var(--d-radius-lg)'],
    ['text-align', 'center'],
    ['position', 'relative'],
    ['overflow', 'hidden'],
    // Default gradient uses theme tokens — themes can override the stops
    // via CSS variables --d-cta-gradient if desired.
    [
      'background',
      'var(--d-cta-gradient, linear-gradient(135deg, color-mix(in srgb, var(--d-primary) 85%, transparent), color-mix(in srgb, var(--d-accent) 80%, transparent)))',
    ],
    ['color', 'var(--d-cta-text, #ffffff)'],
  ]);

  emitRule('.d-cta-banner[data-size="compact"]', [
    ['padding', '1.5rem 1rem'],
    ['gap', '0.5rem'],
  ]);

  emitRule('.d-cta-banner[data-size="hero"]', [
    ['padding', '5rem 2rem'],
    ['gap', '1.5rem'],
  ]);

  // Dark pill CTA inside a banner — the v4 harness explicitly called out
  // this shape. Using a d-interactive with data-variant="dark" parallels
  // the existing primary/ghost/danger variants.
  emitRule('.d-interactive[data-variant="dark"]', [
    ['background', 'var(--d-cta-pill-bg, #18181b)'],
    ['color', 'var(--d-cta-pill-text, #ffffff)'],
    ['border-color', 'transparent'],
    ['border-radius', 'var(--d-radius-full)'],
  ]);

  emitRule('.d-interactive[data-variant="dark"]:hover', [
    ['background', 'var(--d-cta-pill-bg-hover, #27272a)'],
  ]);

  // ── 12. Divider Utilities ──
  // Single-side border rules. Use these as plain class additions on
  // containers instead of hand-rolling `.divider-top` / `.divider-bottom`.

  emitRule('.d-divider-top', [['border-top', '1px solid var(--d-border)']]);

  emitRule('.d-divider-bottom', [['border-bottom', '1px solid var(--d-border)']]);

  emitRule('.d-divider-left', [['border-left', '1px solid var(--d-border)']]);

  emitRule('.d-divider-right', [['border-right', '1px solid var(--d-border)']]);

  // Horizontal standalone divider element (<hr class="d-divider">).
  emitRule('.d-divider', [
    ['border', '0'],
    ['border-top', '1px solid var(--d-border)'],
    ['margin', '0'],
    ['width', '100%'],
    ['height', '0'],
  ]);

  // ── 13. Shell Structural Treatments — .d-shell-* ──
  // The v5 harness reported that cold scaffolds hand-rolled 310 lines /
  // 56 CSS classes of shell structural layout because Decantr didn't
  // ship shell treatments. These treatments cover the three shells
  // declared across most blueprints: sidebar-main, centered,
  // top-nav-footer. Compose with atoms for per-region overrides.

  // Root shell container — full viewport height + overflow containment.
  emitRule('.d-shell', [
    ['display', 'flex'],
    ['flex-direction', 'column'],
    ['min-height', '100vh'],
    ['background', 'var(--d-bg)'],
    ['color', 'var(--d-text)'],
  ]);

  // Sidebar-main variant — sidebar + main body side by side.
  emitRule('.d-shell[data-layout="sidebar-main"]', [
    ['flex-direction', 'row'],
    ['height', '100vh'],
    ['overflow', 'hidden'],
  ]);

  // Centered variant — single card centered in the viewport.
  emitRule('.d-shell[data-layout="centered"]', [
    ['align-items', 'center'],
    ['justify-content', 'center'],
    ['padding', '1rem'],
  ]);

  // Top-nav-footer variant — explicit marker for the default vertical-column
  // layout with sticky header and footer. Default behaviour if no
  // data-layout is set, but naming the variant explicitly makes the
  // contract readable and lets authors match the blueprint's declared
  // shell name exactly.
  emitRule('.d-shell[data-layout="top-nav-footer"]', [
    ['flex-direction', 'column'],
    ['height', '100vh'],
    ['overflow', 'hidden'],
  ]);

  // Sidebar-aside variant — 3-column dashboard layout with primary
  // navigation on the left, main content in the centre, and a context
  // aside on the right. Used by video editors, trace explorers, and any
  // workspace where a persistent auxiliary panel (inspector, timeline,
  // minimap) lives alongside the main canvas. The v4 ai-video-studio
  // harness run reported this as the single biggest contributor to
  // inline-style count (11 in SidebarAsideShell.tsx alone) because the
  // treatment didn't exist and the grid had to be hand-rolled.
  //
  // Usage: wrap `<div className="d-shell" data-layout="sidebar-aside">`
  // with three children — `d-shell-sidebar`, `d-shell-main`, `d-shell-aside`.
  emitRule('.d-shell[data-layout="sidebar-aside"]', [
    ['display', 'grid'],
    ['grid-template-columns', '240px 1fr 320px'],
    ['grid-template-rows', '1fr'],
    ['height', '100vh'],
    ['overflow', 'hidden'],
  ]);

  // Aside region — right-side auxiliary panel for inspector/timeline/minimap.
  emitRule('.d-shell-aside', [
    ['display', 'flex'],
    ['flex-direction', 'column'],
    ['border-left', '1px solid var(--d-border)'],
    ['background', 'var(--d-surface)'],
    ['overflow-y', 'auto'],
  ]);

  // Below md, the aside collapses out of the grid. Pair with a drawer
  // toggle when the pattern's mobile reflow asks for it, or simply hide
  // the auxiliary panel entirely on phone viewports.
  lines.push('@media (max-width: 767.98px) {');
  lines.push('  .d-shell[data-layout="sidebar-aside"] {');
  lines.push('    grid-template-columns: 1fr;');
  lines.push('    grid-template-rows: auto 1fr;');
  lines.push('  }');
  lines.push('  .d-shell[data-layout="sidebar-aside"] .d-shell-aside {');
  lines.push('    display: none;');
  lines.push('  }');
  lines.push('  .d-shell[data-layout="sidebar-aside"] .d-shell-aside[data-mobile-open="true"] {');
  lines.push('    display: flex;');
  lines.push('    position: fixed;');
  lines.push('    inset: 0 0 0 auto;');
  lines.push('    width: min(320px, 100vw);');
  lines.push('    z-index: 50;');
  lines.push('  }');
  lines.push('}');
  lines.push('');

  // Sidebar region — 240px persistent nav column.
  emitRule('.d-shell-sidebar', [
    ['display', 'flex'],
    ['flex-direction', 'column'],
    ['width', '240px'],
    ['flex-shrink', '0'],
    ['border-right', '1px solid var(--d-border)'],
    ['background', 'var(--d-surface)'],
    ['overflow-y', 'auto'],
    ['transition', 'width 0.2s ease, transform 0.2s ease'],
  ]);

  // Collapsed rail variant — 64px icon-only.
  emitRule('.d-shell-sidebar[data-collapsed="true"]', [['width', '64px']]);

  // Below md: sidebar becomes an off-canvas drawer controlled by
  // `data-mobile-open="true|false"`. Hidden by default (translate off-screen).
  lines.push('@media (max-width: 767.98px) {');
  lines.push('  .d-shell-sidebar {');
  lines.push('    position: fixed;');
  lines.push('    top: 0;');
  lines.push('    left: 0;');
  lines.push('    bottom: 0;');
  lines.push('    z-index: 50;');
  lines.push('    transform: translateX(-100%);');
  lines.push('    box-shadow: var(--d-elevation-4, 0 8px 24px rgba(0,0,0,0.25));');
  lines.push('  }');
  lines.push('  .d-shell-sidebar[data-mobile-open="true"] {');
  lines.push('    transform: translateX(0);');
  lines.push('  }');
  lines.push('}');
  lines.push('');

  // Mobile menu trigger — hamburger button that opens the sidebar drawer
  // below _mdmax: and is hidden above. Place inside d-shell-header.
  // The cold UX review surfaced that scaffolds collapse the sidebar on
  // mobile but then provide no way to re-open it — users got stuck.
  // This treatment ships the trigger button so the contract closes the
  // loop. Implementation: button toggles `data-mobile-open` on the
  // sibling `.d-shell-sidebar` element.
  emitRule('.d-shell-mobile-trigger', [
    ['display', 'none'],
    ['align-items', 'center'],
    ['justify-content', 'center'],
    ['width', '36px'],
    ['height', '36px'],
    ['border', '1px solid var(--d-border)'],
    ['border-radius', 'var(--d-radius-sm)'],
    ['background', 'transparent'],
    ['color', 'var(--d-text)'],
    ['cursor', 'pointer'],
    ['flex-shrink', '0'],
    [
      'transition',
      'background var(--d-motion-fast, 150ms) var(--d-motion-ease-out, cubic-bezier(0,0,0.2,1)), border-color var(--d-motion-fast, 150ms) var(--d-motion-ease-out, cubic-bezier(0,0,0.2,1))',
    ],
  ]);
  emitRule('.d-shell-mobile-trigger:hover', [
    ['background', 'var(--d-surface)'],
    ['border-color', 'var(--d-primary)'],
  ]);
  emitRule('.d-shell-mobile-trigger:focus-visible', [
    ['outline', '2px solid var(--d-primary)'],
    ['outline-offset', '2px'],
  ]);

  // Mobile backdrop — dim scrim shown behind the open sidebar drawer so
  // tapping outside closes it. Hidden above _mdmax:.
  emitRule('.d-shell-mobile-backdrop', [
    ['display', 'none'],
    ['position', 'fixed'],
    ['inset', '0'],
    ['z-index', '49'],
    ['background', 'color-mix(in srgb, var(--d-bg) 60%, transparent)'],
    ['backdrop-filter', 'blur(2px)'],
    ['-webkit-backdrop-filter', 'blur(2px)'],
    [
      'transition',
      'opacity var(--d-motion-fast, 150ms) var(--d-motion-ease-out, cubic-bezier(0,0,0.2,1))',
    ],
  ]);

  // Show trigger + backdrop only on mobile (below _md:). Above md, both
  // are display:none — sidebar is always visible inline.
  lines.push('@media (max-width: 767.98px) {');
  lines.push('  .d-shell-mobile-trigger {');
  lines.push('    display: inline-flex;');
  lines.push('  }');
  lines.push('  .d-shell-mobile-backdrop[data-visible="true"] {');
  lines.push('    display: block;');
  lines.push('  }');
  lines.push('}');
  lines.push('');

  // Main content area (to the right of sidebar, or spanning full width
  // in top-nav-* shells). Takes remaining space, scroll container itself.
  emitRule('.d-shell-main', [
    ['display', 'flex'],
    ['flex-direction', 'column'],
    ['flex', '1'],
    ['min-width', '0'],
    ['overflow', 'hidden'],
  ]);

  // Header — 52px sticky top bar. Used inside d-shell-main (sidebar-main)
  // or at the top of d-shell (top-nav-*). Horizontal layout, flex aligned.
  emitRule('.d-shell-header', [
    ['display', 'flex'],
    ['align-items', 'center'],
    ['justify-content', 'space-between'],
    ['gap', '1rem'],
    ['height', '52px'],
    ['flex-shrink', '0'],
    ['padding', '0 clamp(1rem, 2vw, 1.5rem)'],
    ['border-bottom', '1px solid var(--d-border)'],
    ['background', 'var(--d-bg)'],
    ['position', 'sticky'],
    ['top', '0'],
    ['z-index', '10'],
  ]);

  // Body — scrollable main region inside d-shell-main.
  // F1 review fix: `min-width: 0` + `overflow-x: clip` together prevent the
  // dashboard right-edge clipping observed on observability-platform's
  // /metrics, /traces, /alerts. Wide grid children (KPI cards, chart
  // columns) were overflowing past the viewport because they had no
  // upper bound and the parent flex column wasn't allowed to shrink.
  // F1 follow-up: d-shell-body is a flex-column with a section-level
  // gap between its direct children. This is the architectural answer
  // to the "section eyebrow has no breathing room above it" problem
  // surfaced by the live observability-platform UX review. Putting
  // the gap on the FLOW CONTAINER means every direct child block
  // (eyebrow, headline section, card grid, chart row, table) is spaced
  // uniformly regardless of internal composition — works whether
  // section headings are flat or wrapped in a SectionHeading
  // component, because the container's gap doesn't care about
  // descendant structure.
  //
  // Pages that need to opt out can set `data-flow="tight"` (no gap)
  // or wrap a region in their own flex container with a different gap.
  emitRule('.d-shell-body', [
    ['flex', '1'],
    ['min-width', '0'],
    ['overflow-y', 'auto'],
    ['overflow-x', 'clip'],
    ['padding', '1rem'],
    ['display', 'flex'],
    ['flex-direction', 'column'],
    ['gap', 'var(--d-section-gap, 2rem)'],
  ]);

  // Body size variants.
  emitRule('.d-shell-body[data-padding="compact"]', [['padding', '0.75rem']]);

  emitRule('.d-shell-body[data-padding="spacious"]', [['padding', '1.5rem']]);

  emitRule('.d-shell-body[data-padding="none"]', [['padding', '0']]);

  // Flow variants — let pages opt out of the default section gap when
  // they need tighter (or zero) inter-block spacing.
  emitRule('.d-shell-body[data-flow="tight"]', [['gap', '0.75rem']]);

  emitRule('.d-shell-body[data-flow="none"]', [
    ['display', 'block'],
    ['gap', '0'],
  ]);

  // Footer — narrow band below body.
  emitRule('.d-shell-footer', [
    ['padding', '1rem clamp(1rem, 2vw, 1.5rem)'],
    ['border-top', '1px solid var(--d-border)'],
    ['background', 'var(--d-surface)'],
    ['flex-shrink', '0'],
  ]);

  // Centered card — the content parent inside d-shell[data-layout="centered"].
  // F1 review fix: add `margin-inline: auto` for defensive self-centering.
  // The auth pages observed in the cold-LLM run wrapped content in
  // `d-shell-centered-card` but were rendering full-viewport-width because
  // the parent shell didn't always apply flex centering. Belt-and-braces
  // ensures the card is always horizontally centered and capped at 28rem
  // regardless of parent layout. Vertical centering still relies on the
  // parent shell's `data-layout="centered"` (`align-items: center`).
  emitRule('.d-shell-centered-card', [
    ['width', '100%'],
    ['max-width', '28rem'],
    ['margin-inline', 'auto'],
  ]);

  // ── 13.5 Additional Shell Layouts — F2 Phase 1 finding ──
  // Audit of decantr-content registry vs treatments.css revealed 10 of 15
  // declared shells had no matching `[data-layout="..."]` rule. Cold AI
  // scaffolds were forced to hand-roll layouts (creating exactly the
  // inline-style violations `decantr audit` then warned about). Each
  // shell treatment below maps to a real shell.json spec in decantr-content.

  // ── Vertical column variants (header + body, no footer) ──
  // top-nav-main: 52px sticky header + scrollable body. Default for
  // utility/content surfaces that don't need a footer rail.
  emitRule('.d-shell[data-layout="top-nav-main"]', [
    ['flex-direction', 'column'],
    ['height', '100vh'],
    ['overflow', 'hidden'],
  ]);

  // minimal-header: slim 44px sticky header for focused/checkout flows.
  // Functionally same flex-column shape; downstream pages set the slim
  // header height via inline atoms or by overriding the d-shell-header
  // padding directly.
  emitRule('.d-shell[data-layout="minimal-header"]', [
    ['flex-direction', 'column'],
    ['height', '100vh'],
    ['overflow', 'hidden'],
  ]);

  // full-bleed: edge-to-edge content, no shared insets. Used for canvas
  // surfaces, immersive editor experiences. Hides nav by default per spec.
  emitRule('.d-shell[data-layout="full-bleed"]', [
    ['flex-direction', 'column'],
    ['height', '100vh'],
    ['overflow', 'hidden'],
  ]);
  emitRule('.d-shell[data-layout="full-bleed"] .d-shell-body', [['padding', '0']]);

  // recipefork-top-nav: recipefork-specific 64px top-nav variant. Same
  // column shape as top-nav-main but taller header for branded marketing.
  emitRule('.d-shell[data-layout="recipefork-top-nav"]', [
    ['flex-direction', 'column'],
    ['height', '100vh'],
    ['overflow', 'hidden'],
  ]);

  // ── Grid-based shells ──

  // canvas-overlay: full-bleed canvas with optional overlay panels (toolbox,
  // properties inspector). Header sits above canvas; body fills remainder
  // and acts as the canvas paint area (no internal scroll). Use d-shell-overlay
  // for floating tool/property panels positioned absolutely over the canvas.
  emitRule('.d-shell[data-layout="canvas-overlay"]', [
    ['display', 'grid'],
    ['grid-template-rows', '52px 1fr'],
    ['grid-template-columns', '1fr'],
    ['height', '100vh'],
    ['overflow', 'hidden'],
    ['position', 'relative'],
  ]);
  emitRule('.d-shell[data-layout="canvas-overlay"] .d-shell-body', [
    ['padding', '0'],
    ['overflow', 'hidden'],
    ['position', 'relative'],
  ]);

  // chat-portal: 280px conversation sidebar + chat thread + anchored input.
  // Used by ai-chatbot archetype. The body acts as a column with scrollable
  // message list above an anchored input bar.
  emitRule('.d-shell[data-layout="chat-portal"]', [
    ['display', 'grid'],
    ['grid-template-columns', '280px 1fr'],
    ['grid-template-rows', '52px 1fr'],
    ['grid-template-areas', '"nav header" "nav body"'],
    ['height', '100vh'],
    ['overflow', 'hidden'],
  ]);
  emitRule('.d-shell[data-layout="chat-portal"] .d-shell-sidebar', [['grid-area', 'nav']]);
  emitRule('.d-shell[data-layout="chat-portal"] .d-shell-header', [['grid-area', 'header']]);
  emitRule('.d-shell[data-layout="chat-portal"] .d-shell-body', [['grid-area', 'body']]);
  lines.push('@media (max-width: 767.98px) {');
  lines.push('  .d-shell[data-layout="chat-portal"] {');
  lines.push('    grid-template-columns: 1fr;');
  lines.push('    grid-template-areas: "header" "body";');
  lines.push('  }');
  lines.push('  .d-shell[data-layout="chat-portal"] .d-shell-sidebar {');
  lines.push('    display: none;');
  lines.push('  }');
  lines.push('}');
  lines.push('');

  // copilot-overlay: main app + right-side AI copilot drawer. The most-cited
  // missing shell in F2/ai-copilot-shell harness. Header spans both columns;
  // body and copilot share the second row. Copilot collapses to 0 width
  // when toggled off; pair with d-shell-copilot child region.
  emitRule('.d-shell[data-layout="copilot-overlay"]', [
    ['display', 'grid'],
    ['grid-template-columns', '1fr 360px'],
    ['grid-template-rows', '56px 1fr'],
    ['grid-template-areas', '"header header" "body copilot"'],
    ['height', '100vh'],
    ['overflow', 'hidden'],
    ['transition', 'grid-template-columns 0.2s ease'],
  ]);
  emitRule('.d-shell[data-layout="copilot-overlay"] .d-shell-header', [['grid-area', 'header']]);
  emitRule('.d-shell[data-layout="copilot-overlay"] .d-shell-body', [['grid-area', 'body']]);
  emitRule('.d-shell[data-layout="copilot-overlay"] .d-shell-copilot', [['grid-area', 'copilot']]);
  // Collapsed state — copilot pane closes via data-collapsed on the shell.
  emitRule('.d-shell[data-layout="copilot-overlay"][data-copilot-collapsed="true"]', [
    ['grid-template-columns', '1fr 0px'],
  ]);
  lines.push('@media (max-width: 767.98px) {');
  lines.push('  .d-shell[data-layout="copilot-overlay"] {');
  lines.push('    grid-template-columns: 1fr;');
  lines.push('    grid-template-areas: "header" "body";');
  lines.push('  }');
  lines.push('  .d-shell[data-layout="copilot-overlay"] .d-shell-copilot {');
  lines.push('    display: none;');
  lines.push('  }');
  lines.push(
    '  .d-shell[data-layout="copilot-overlay"] .d-shell-copilot[data-mobile-open="true"] {',
  );
  lines.push('    display: flex;');
  lines.push('    position: fixed;');
  lines.push('    inset: 0 0 0 auto;');
  lines.push('    width: min(360px, 100vw);');
  lines.push('    z-index: 50;');
  lines.push('  }');
  lines.push('}');
  lines.push('');

  // terminal-split: top status-bar + body (split panes) + bottom hotkey-bar.
  // Used by terminal/IDE-like blueprints. The body region is a split-pane
  // container; consumers compose actual panes inside.
  emitRule('.d-shell[data-layout="terminal-split"]', [
    ['display', 'grid'],
    ['grid-template-rows', '24px 1fr 28px'],
    ['grid-template-columns', '1fr'],
    ['height', '100vh'],
    ['overflow', 'hidden'],
  ]);
  emitRule('.d-shell[data-layout="terminal-split"] .d-shell-body', [['overflow', 'hidden']]);

  // three-column-browser: classic mail/file-browser shape — nav + list + detail.
  // Header spans all three columns; nav 220px, list 320px, detail flex.
  emitRule('.d-shell[data-layout="three-column-browser"]', [
    ['display', 'grid'],
    ['grid-template-columns', '220px 320px 1fr'],
    ['grid-template-rows', '52px 1fr'],
    ['grid-template-areas', '"header header header" "nav list detail"'],
    ['height', '100vh'],
    ['overflow', 'hidden'],
  ]);
  emitRule('.d-shell[data-layout="three-column-browser"] .d-shell-header', [
    ['grid-area', 'header'],
  ]);
  emitRule('.d-shell[data-layout="three-column-browser"] .d-shell-sidebar', [['grid-area', 'nav']]);
  emitRule('.d-shell[data-layout="three-column-browser"] .d-shell-list', [['grid-area', 'list']]);
  emitRule('.d-shell[data-layout="three-column-browser"] .d-shell-main', [['grid-area', 'detail']]);
  lines.push('@media (max-width: 1023.98px) {');
  lines.push('  .d-shell[data-layout="three-column-browser"] {');
  lines.push('    grid-template-columns: 320px 1fr;');
  lines.push('    grid-template-areas: "header header" "list detail";');
  lines.push('  }');
  lines.push('  .d-shell[data-layout="three-column-browser"] .d-shell-sidebar {');
  lines.push('    display: none;');
  lines.push('  }');
  lines.push('}');
  lines.push('@media (max-width: 767.98px) {');
  lines.push('  .d-shell[data-layout="three-column-browser"] {');
  lines.push('    grid-template-columns: 1fr;');
  lines.push('    grid-template-areas: "header" "detail";');
  lines.push('  }');
  lines.push('  .d-shell[data-layout="three-column-browser"] .d-shell-list {');
  lines.push('    display: none;');
  lines.push('  }');
  lines.push('}');
  lines.push('');

  // workspace-aside: 3-column collaborative editor — page tree + body + comments
  // aside. Most-cited missing shell in F2/realtime-collaboration-workspace
  // harness. Nav (left) spans both rows; header spans body + aside columns.
  emitRule('.d-shell[data-layout="workspace-aside"]', [
    ['display', 'grid'],
    ['grid-template-columns', '240px 1fr 280px'],
    ['grid-template-rows', '52px 1fr'],
    ['grid-template-areas', '"nav header header" "nav body aside"'],
    ['height', '100vh'],
    ['overflow', 'hidden'],
  ]);
  emitRule('.d-shell[data-layout="workspace-aside"] .d-shell-sidebar', [['grid-area', 'nav']]);
  emitRule('.d-shell[data-layout="workspace-aside"] .d-shell-header', [['grid-area', 'header']]);
  emitRule('.d-shell[data-layout="workspace-aside"] .d-shell-body', [['grid-area', 'body']]);
  emitRule('.d-shell[data-layout="workspace-aside"] .d-shell-aside', [['grid-area', 'aside']]);
  lines.push('@media (max-width: 1279.98px) {');
  lines.push('  .d-shell[data-layout="workspace-aside"] {');
  lines.push('    grid-template-columns: 240px 1fr;');
  lines.push('    grid-template-areas: "nav header" "nav body";');
  lines.push('  }');
  lines.push('  .d-shell[data-layout="workspace-aside"] .d-shell-aside {');
  lines.push('    display: none;');
  lines.push('  }');
  lines.push('}');
  lines.push('@media (max-width: 1023.98px) {');
  lines.push('  .d-shell[data-layout="workspace-aside"] {');
  lines.push('    grid-template-columns: 1fr;');
  lines.push('    grid-template-areas: "header" "body";');
  lines.push('  }');
  lines.push('  .d-shell[data-layout="workspace-aside"] .d-shell-sidebar {');
  lines.push('    display: none;');
  lines.push('  }');
  lines.push('}');
  lines.push('');

  // ── New child region treatments to support the shells above ──

  // d-shell-list: middle column for three-column browsers (220-320px).
  // Mail-app inbox list, file browser items list, etc.
  emitRule('.d-shell-list', [
    ['display', 'flex'],
    ['flex-direction', 'column'],
    ['border-right', '1px solid var(--d-border)'],
    ['background', 'var(--d-surface)'],
    ['overflow-y', 'auto'],
    ['min-width', '0'],
  ]);

  // d-shell-copilot: right-side AI copilot drawer for copilot-overlay shell.
  // Frosted glass surface, full-height column with anchored input at bottom.
  emitRule('.d-shell-copilot', [
    ['display', 'flex'],
    ['flex-direction', 'column'],
    ['border-left', '1px solid var(--d-border)'],
    ['background', 'var(--d-surface)'],
    ['overflow', 'hidden'],
    ['min-width', '0'],
    ['transition', 'transform 0.2s ease'],
  ]);

  // d-shell-status-bar: thin top-of-viewport status row for terminal-split.
  // Use for connection state, project name, current branch, etc.
  emitRule('.d-shell-status-bar', [
    ['display', 'flex'],
    ['align-items', 'center'],
    ['gap', '1rem'],
    ['padding', '0 0.75rem'],
    ['font-size', 'var(--d-text-xs)'],
    ['color', 'var(--d-text-muted)'],
    ['background', 'var(--d-surface)'],
    ['border-bottom', '1px solid var(--d-border)'],
    ['flex-shrink', '0'],
  ]);

  // d-shell-hotkey-bar: thin bottom-of-viewport hotkey hints row for
  // terminal-split. Use to display the active key bindings (^P, ^B, ^X, etc.).
  emitRule('.d-shell-hotkey-bar', [
    ['display', 'flex'],
    ['align-items', 'center'],
    ['gap', '0.75rem'],
    ['padding', '0 0.75rem'],
    ['font-size', 'var(--d-text-xs)'],
    ['color', 'var(--d-text-muted)'],
    ['background', 'var(--d-surface)'],
    ['border-top', '1px solid var(--d-border)'],
    ['flex-shrink', '0'],
  ]);

  // d-shell-overlay: floating tool/property panel positioned absolutely
  // over the canvas in canvas-overlay shells. Use [data-corner] attribute
  // to position (top-left, top-right, bottom-left, bottom-right).
  emitRule('.d-shell-overlay', [
    ['position', 'absolute'],
    ['z-index', '10'],
    ['background', 'var(--d-surface)'],
    ['border', '1px solid var(--d-border)'],
    ['border-radius', 'var(--d-radius)'],
    ['box-shadow', 'var(--d-elevation-3, 0 6px 16px rgba(0,0,0,0.18))'],
    ['padding', '0.75rem'],
    ['min-width', '200px'],
    ['max-width', '320px'],
  ]);
  emitRule('.d-shell-overlay[data-corner="top-left"]', [
    ['top', '1rem'],
    ['left', '1rem'],
  ]);
  emitRule('.d-shell-overlay[data-corner="top-right"]', [
    ['top', '1rem'],
    ['right', '1rem'],
  ]);
  emitRule('.d-shell-overlay[data-corner="bottom-left"]', [
    ['bottom', '1rem'],
    ['left', '1rem'],
  ]);
  emitRule('.d-shell-overlay[data-corner="bottom-right"]', [
    ['bottom', '1rem'],
    ['right', '1rem'],
  ]);

  // ── 13.7 Universal Utility Treatments — F2 Phase 1 finding ──
  // Cold AI runs across 4 paradigm clusters all named the same missing
  // primitives. Cold agents either hand-rolled inline styles or (worse)
  // composed approximations from atoms that miss the semantic intent.
  // Shipping these eliminates ~80 inline-style instances per scaffold.

  // d-tooltip: small popover anchored near a hover/focus target. Pair with
  // a [data-position] attribute (top|right|bottom|left) and parent
  // position:relative. Render via React state; Decantr ships only the
  // visual treatment, not the positioning logic.
  emitRule('.d-tooltip', [
    ['position', 'absolute'],
    ['z-index', '20'],
    ['padding', '0.375rem 0.625rem'],
    ['font-size', 'var(--d-text-xs)'],
    ['line-height', 'var(--d-leading-snug)'],
    ['color', 'var(--d-bg)'],
    ['background', 'var(--d-text)'],
    ['border-radius', 'var(--d-radius-sm)'],
    ['white-space', 'nowrap'],
    ['pointer-events', 'none'],
    ['box-shadow', 'var(--d-elevation-2, 0 4px 12px rgba(0,0,0,0.15))'],
  ]);
  emitRule('.d-tooltip[data-position="top"]', [
    ['bottom', '100%'],
    ['left', '50%'],
    ['transform', 'translate(-50%, -0.375rem)'],
  ]);
  emitRule('.d-tooltip[data-position="bottom"]', [
    ['top', '100%'],
    ['left', '50%'],
    ['transform', 'translate(-50%, 0.375rem)'],
  ]);
  emitRule('.d-tooltip[data-position="left"]', [
    ['right', '100%'],
    ['top', '50%'],
    ['transform', 'translate(-0.375rem, -50%)'],
  ]);
  emitRule('.d-tooltip[data-position="right"]', [
    ['left', '100%'],
    ['top', '50%'],
    ['transform', 'translate(0.375rem, -50%)'],
  ]);

  // d-empty-state: centered container for empty UI states. Composes with
  // d-icon-well + d-title + d-caption + d-interactive for the standard
  // "no items yet" pattern.
  emitRule('.d-empty-state', [
    ['display', 'flex'],
    ['flex-direction', 'column'],
    ['align-items', 'center'],
    ['justify-content', 'center'],
    ['gap', '0.75rem'],
    ['padding', '3rem 1.5rem'],
    ['text-align', 'center'],
    ['color', 'var(--d-text-muted)'],
  ]);

  // d-breadcrumb / d-breadcrumb-item / d-breadcrumb-separator: page hierarchy
  // navigation. Use a parent with d-breadcrumb (a flex row) and children
  // with d-breadcrumb-item (link styling) interleaved with d-breadcrumb-separator
  // (chevron or slash). Active item gets [data-current="true"].
  emitRule('.d-breadcrumb', [
    ['display', 'flex'],
    ['align-items', 'center'],
    ['gap', '0.375rem'],
    ['flex-wrap', 'wrap'],
    ['font-size', 'var(--d-text-sm)'],
    ['color', 'var(--d-text-muted)'],
  ]);
  emitRule('.d-breadcrumb-item', [
    ['color', 'var(--d-text-muted)'],
    ['text-decoration', 'none'],
    [
      'transition',
      'color var(--d-motion-fast, 150ms) var(--d-motion-ease-out, cubic-bezier(0,0,0.2,1))',
    ],
  ]);
  emitRule('.d-breadcrumb-item:hover', [['color', 'var(--d-text)']]);
  emitRule('.d-breadcrumb-item[data-current="true"]', [
    ['color', 'var(--d-text)'],
    ['font-weight', 'var(--d-weight-medium)'],
    ['pointer-events', 'none'],
  ]);
  emitRule('.d-breadcrumb-separator', [
    ['color', 'var(--d-text-muted)'],
    ['opacity', '0.5'],
    ['user-select', 'none'],
  ]);

  // d-avatar: circular avatar with size variants. Pair with [data-size] for
  // sm (24px), md (32px), lg (48px). Default md.
  emitRule('.d-avatar', [
    ['display', 'inline-flex'],
    ['align-items', 'center'],
    ['justify-content', 'center'],
    ['width', '32px'],
    ['height', '32px'],
    ['border-radius', '50%'],
    ['background', 'var(--d-surface)'],
    ['color', 'var(--d-text)'],
    ['font-size', 'var(--d-text-xs)'],
    ['font-weight', 'var(--d-weight-medium)'],
    ['overflow', 'hidden'],
    ['flex-shrink', '0'],
    ['border', '1px solid var(--d-border)'],
  ]);
  emitRule('.d-avatar[data-size="sm"]', [
    ['width', '24px'],
    ['height', '24px'],
  ]);
  emitRule('.d-avatar[data-size="lg"]', [
    ['width', '48px'],
    ['height', '48px'],
    ['font-size', 'var(--d-text-sm)'],
  ]);

  // d-icon-well: tinted square icon container — the "feature card" icon
  // tile, the "empty-state" iconography, the "bullet" decoration. Pair
  // with a Lucide icon child.
  emitRule('.d-icon-well', [
    ['display', 'inline-flex'],
    ['align-items', 'center'],
    ['justify-content', 'center'],
    ['width', '48px'],
    ['height', '48px'],
    ['border-radius', 'var(--d-radius)'],
    ['background', 'color-mix(in srgb, var(--d-primary) 12%, transparent)'],
    ['color', 'var(--d-primary)'],
    ['flex-shrink', '0'],
  ]);
  emitRule('.d-icon-well[data-size="sm"]', [
    ['width', '32px'],
    ['height', '32px'],
  ]);
  emitRule('.d-icon-well[data-size="lg"]', [
    ['width', '64px'],
    ['height', '64px'],
  ]);

  // d-toggle: toggle switch (binary on/off). Visually a pill with sliding
  // thumb. Use as `<button class="d-toggle" data-on="true|false">`.
  // Consumer wires the click handler; treatment ships visual state.
  emitRule('.d-toggle', [
    ['position', 'relative'],
    ['display', 'inline-block'],
    ['width', '36px'],
    ['height', '20px'],
    ['border-radius', '9999px'],
    ['background', 'var(--d-border)'],
    ['border', 'none'],
    ['cursor', 'pointer'],
    ['flex-shrink', '0'],
    [
      'transition',
      'background var(--d-motion-fast, 150ms) var(--d-motion-ease-out, cubic-bezier(0,0,0.2,1))',
    ],
  ]);
  emitRule('.d-toggle[data-on="true"]', [['background', 'var(--d-primary)']]);
  emitRule('.d-toggle::after', [
    ['content', '""'],
    ['position', 'absolute'],
    ['top', '2px'],
    ['left', '2px'],
    ['width', '16px'],
    ['height', '16px'],
    ['border-radius', '50%'],
    ['background', 'var(--d-bg)'],
    [
      'transition',
      'transform var(--d-motion-fast, 150ms) var(--d-motion-ease-out, cubic-bezier(0,0,0.2,1))',
    ],
  ]);
  emitRule('.d-toggle[data-on="true"]::after', [['transform', 'translateX(16px)']]);
  emitRule('.d-toggle:focus-visible', [
    ['outline', '2px solid var(--d-primary)'],
    ['outline-offset', '2px'],
  ]);

  // d-toc: sticky table-of-contents nav. Used in legal/long-form prose
  // pages. Renders as a flex column anchored to the right. Pair with
  // d-toc-item for individual links (active state via [data-current="true"]).
  emitRule('.d-toc', [
    ['position', 'sticky'],
    ['top', '1rem'],
    ['display', 'flex'],
    ['flex-direction', 'column'],
    ['gap', '0.25rem'],
    ['padding', '1rem'],
    ['font-size', 'var(--d-text-sm)'],
    ['border-left', '2px solid var(--d-border)'],
    ['max-height', 'calc(100vh - 2rem)'],
    ['overflow-y', 'auto'],
  ]);
  emitRule('.d-toc-item', [
    ['color', 'var(--d-text-muted)'],
    ['text-decoration', 'none'],
    ['padding', '0.25rem 0.5rem'],
    ['border-radius', 'var(--d-radius-sm)'],
    [
      'transition',
      'color var(--d-motion-fast, 150ms) var(--d-motion-ease-out, cubic-bezier(0,0,0.2,1)), background var(--d-motion-fast, 150ms) var(--d-motion-ease-out, cubic-bezier(0,0,0.2,1))',
    ],
  ]);
  emitRule('.d-toc-item:hover', [
    ['color', 'var(--d-text)'],
    ['background', 'var(--d-surface)'],
  ]);
  emitRule('.d-toc-item[data-current="true"]', [
    ['color', 'var(--d-primary)'],
    ['font-weight', 'var(--d-weight-medium)'],
  ]);

  // d-popover: generic positioned popover for menus, dropdowns, slash menus.
  // Use as a menu/listbox parent. Anchor positioning is consumer-driven
  // (e.g. set top/left inline based on trigger rect or use a positioning
  // library); treatment ships only the visual chrome.
  emitRule('.d-popover', [
    ['position', 'absolute'],
    ['z-index', '30'],
    ['background', 'var(--d-surface)'],
    ['border', '1px solid var(--d-border)'],
    ['border-radius', 'var(--d-radius)'],
    ['box-shadow', 'var(--d-elevation-3, 0 6px 16px rgba(0,0,0,0.18))'],
    ['min-width', '200px'],
    ['max-width', '320px'],
    ['padding', '0.25rem'],
    ['overflow', 'hidden'],
  ]);

  // ── 14. Modal + Palette Chrome — .d-modal, .d-palette, .d-kbd ──
  // The v5 harness reported that command_palette is a mandatory feature
  // in every scaffold-pack but Decantr shipped no modal/palette treatments.
  // Cold scaffolds hand-rolled the same overlay chrome repeatedly. These
  // treatments cover the universal modal + palette shape.

  // Modal root — fixed overlay covering viewport.
  emitRule('.d-modal', [
    ['position', 'fixed'],
    ['inset', '0'],
    ['z-index', '100'],
    ['display', 'flex'],
    ['align-items', 'center'],
    ['justify-content', 'center'],
    ['padding', '1rem'],
  ]);

  emitRule('.d-modal[data-align="top"]', [
    ['align-items', 'flex-start'],
    ['padding-top', '15vh'],
  ]);

  // Backdrop — absolute scrim that covers everything.
  emitRule('.d-modal-backdrop', [
    ['position', 'absolute'],
    ['inset', '0'],
    ['background', 'color-mix(in srgb, var(--d-bg) 70%, transparent)'],
    ['backdrop-filter', 'blur(8px)'],
    ['-webkit-backdrop-filter', 'blur(8px)'],
  ]);

  // Panel — the actual dialog content.
  emitRule('.d-modal-panel', [
    ['position', 'relative'],
    ['z-index', '1'],
    ['width', '100%'],
    ['max-width', '32rem'],
    ['background', 'var(--d-surface-raised)'],
    ['border', '1px solid var(--d-border)'],
    ['border-radius', 'var(--d-radius-lg)'],
    ['box-shadow', 'var(--d-shadow-lg)'],
    ['max-height', '85vh'],
    ['display', 'flex'],
    ['flex-direction', 'column'],
    ['overflow', 'hidden'],
  ]);

  emitRule('.d-modal-panel[data-size="sm"]', [['max-width', '24rem']]);

  emitRule('.d-modal-panel[data-size="lg"]', [['max-width', '48rem']]);

  // Command palette — specialized modal variant with fixed 640px width
  // and specific search + list internal rhythm.
  // F1 review fix: add `margin-inline: auto` so the palette self-centers
  // even when the implementation forgets to wrap in `d-modal`. The
  // observability-platform cold-LLM run rendered d-palette as a top-level
  // 100%-width strip because the implementation skipped the modal wrap.
  // Self-centering keeps the visual contract intact.
  emitRule('.d-palette', [
    ['position', 'relative'],
    ['z-index', '1'],
    ['width', '100%'],
    ['max-width', '40rem'],
    ['margin-inline', 'auto'],
    ['background', 'var(--d-surface-raised)'],
    ['border', '1px solid var(--d-border)'],
    ['border-radius', 'var(--d-radius-lg)'],
    ['box-shadow', 'var(--d-shadow-lg)'],
    ['display', 'flex'],
    ['flex-direction', 'column'],
    ['overflow', 'hidden'],
    ['max-height', '60vh'],
  ]);

  // Search input at the top of the palette.
  emitRule('.d-palette-search', [
    ['display', 'flex'],
    ['align-items', 'center'],
    ['gap', '0.75rem'],
    ['padding', '0.85rem 1rem'],
    ['border-bottom', '1px solid var(--d-border)'],
    ['background', 'color-mix(in srgb, var(--d-surface) 82%, transparent)'],
    ['color', 'var(--d-text-muted)'],
    [
      'transition',
      'background var(--d-motion-fast, 150ms) ease, box-shadow var(--d-motion-fast, 150ms) ease, color var(--d-motion-fast, 150ms) ease',
    ],
  ]);

  emitRule('.d-palette-search:focus-within', [
    ['background', 'var(--d-surface)'],
    ['color', 'var(--d-text)'],
    ['box-shadow', 'inset 0 -2px 0 var(--d-primary)'],
  ]);

  emitRule('.d-palette-input', [
    ['flex', '1'],
    ['min-width', '0'],
    ['padding', '0.6rem 0'],
    ['border', '0'],
    ['background', 'transparent'],
    ['color', 'var(--d-text)'],
    ['font-size', '1.05rem'],
    ['line-height', '1.4'],
    ['outline', '0'],
    ['width', '100%'],
  ]);

  emitRule('.d-palette-input:focus-visible', [
    ['outline', '0'],
    ['box-shadow', 'none'],
  ]);

  emitRule('.d-palette-input::placeholder', [['color', 'var(--d-text-muted)']]);

  // Scrollable list of commands.
  emitRule('.d-palette-list', [
    ['flex', '1'],
    ['overflow-y', 'auto'],
    ['padding', '0.5rem'],
    ['display', 'grid'],
    ['gap', '0.25rem'],
  ]);

  // Individual command row.
  emitRule('.d-palette-row', [
    ['display', 'flex'],
    ['align-items', 'center'],
    ['gap', '0.75rem'],
    ['width', '100%'],
    ['min-height', '3rem'],
    ['padding', '0.7rem 0.75rem'],
    ['border', '0'],
    ['border-radius', 'var(--d-radius)'],
    ['background', 'transparent'],
    ['cursor', 'pointer'],
    ['color', 'var(--d-text)'],
    ['font', 'inherit'],
    ['font-size', '0.92rem'],
    ['text-align', 'left'],
    ['box-shadow', 'inset 0 0 0 1px transparent'],
    ['transition', 'background 0.12s ease, box-shadow 0.12s ease, color 0.12s ease'],
  ]);

  emitRule('.d-palette-row:hover, .d-palette-row[data-active="true"]', [
    ['background', 'color-mix(in srgb, var(--d-primary) 10%, transparent)'],
    ['box-shadow', 'inset 0 0 0 1px color-mix(in srgb, var(--d-primary) 24%, transparent)'],
  ]);

  emitRule('.d-palette-row svg', [
    ['flex', '0 0 auto'],
    ['color', 'var(--d-text-muted)'],
  ]);

  emitRule('.d-palette-row:hover svg, .d-palette-row[data-active="true"] svg', [
    ['color', 'var(--d-primary)'],
  ]);

  // Section label inside a palette (e.g., "Navigation", "Settings").
  emitRule('.d-palette-section', [
    ['padding', '0.5rem 0.75rem 0.25rem'],
    ['font-size', '0.7rem'],
    ['font-weight', '600'],
    ['text-transform', 'uppercase'],
    ['letter-spacing', '0.08em'],
    ['color', 'var(--d-text-muted)'],
  ]);

  // Keyboard chip — mono-font key hint. Used in palette rows,
  // shortcut-help modals, and inline next to action buttons.
  emitRule('.d-kbd', [
    ['display', 'inline-flex'],
    ['align-items', 'center'],
    ['justify-content', 'center'],
    ['min-width', '1.5rem'],
    ['padding', '0 0.375rem'],
    ['height', '1.375rem'],
    ['border', '1px solid var(--d-border)'],
    ['border-radius', 'var(--d-radius-sm)'],
    ['background', 'var(--d-surface)'],
    ['color', 'var(--d-text-muted)'],
    ['font-family', 'var(--d-font-mono, ui-monospace, monospace)'],
    ['font-size', '0.75rem'],
    ['font-weight', '500'],
    ['line-height', '1'],
  ]);

  // ── 15. Motion Treatments — enforce declared interactions[] ──
  // These classes provide the canonical implementations for
  // interactions declared on patterns (e.g., `animate-on-mount`,
  // `status-pulse`, `glow-hover`). Before shipping these, cold LLMs
  // hand-rolled @keyframes on every scaffold — inconsistent, rarely tuned.
  // Each treatment respects `prefers-reduced-motion: reduce` at the bottom
  // of this section. Duration and easing read from --d-motion-* tokens so
  // themes can customize rhythm globally.

  emitRule('.d-enter-fade', [
    [
      'animation',
      'd-fade-in var(--d-motion-base, 250ms) var(--d-motion-ease-out, cubic-bezier(0,0,0.2,1)) both',
    ],
  ]);

  emitRule('.d-enter-slide-up', [
    [
      'animation',
      'd-slide-up var(--d-motion-base, 250ms) var(--d-motion-ease-out, cubic-bezier(0,0,0.2,1)) both',
    ],
  ]);

  emitRule('.d-enter-scale', [
    [
      'animation',
      'd-scale-in var(--d-motion-base, 250ms) var(--d-motion-ease-out, cubic-bezier(0,0,0.2,1)) both',
    ],
  ]);

  emitRule('.d-stagger-children > *', [
    [
      'animation',
      'd-fade-in var(--d-motion-base, 250ms) var(--d-motion-ease-out, cubic-bezier(0,0,0.2,1)) both',
    ],
    ['animation-delay', 'calc(var(--d-stagger-index, 0) * var(--d-motion-stagger, 60ms))'],
  ]);

  emitRule('.d-pulse', [
    ['animation', 'd-pulse 2s var(--d-motion-ease, cubic-bezier(0.4,0,0.2,1)) infinite'],
  ]);

  emitRule('.d-pulse-ring', [
    ['position', 'relative'],
    ['animation', 'd-pulse-ring 1.5s var(--d-motion-ease-out, cubic-bezier(0,0,0.2,1)) infinite'],
  ]);

  emitRule('.d-shimmer', [
    ['background', 'linear-gradient(90deg, transparent, var(--d-surface-raised) 50%, transparent)'],
    ['background-size', '200% 100%'],
    ['animation', 'd-shimmer 1.5s linear infinite'],
  ]);

  emitRule('.d-float', [
    ['animation', 'd-float 3s var(--d-motion-ease, cubic-bezier(0.4,0,0.2,1)) infinite'],
  ]);

  emitRule('.d-glow-hover', [
    [
      'transition',
      'box-shadow var(--d-motion-fast, 150ms) var(--d-motion-ease-out, cubic-bezier(0,0,0.2,1))',
    ],
  ]);
  emitRule('.d-glow-hover:hover', [
    [
      'box-shadow',
      '0 0 24px var(--d-accent-glow, color-mix(in srgb, var(--d-accent) 40%, transparent))',
    ],
  ]);

  emitRule('.d-scale-hover', [
    [
      'transition',
      'transform var(--d-motion-fast, 150ms) var(--d-motion-ease-out, cubic-bezier(0,0,0.2,1))',
    ],
  ]);
  emitRule('.d-scale-hover:hover', [['transform', 'scale(1.02)']]);

  emitRule('.d-lift-hover', [
    [
      'transition',
      'transform var(--d-motion-fast, 150ms) var(--d-motion-ease-out, cubic-bezier(0,0,0.2,1)), box-shadow var(--d-motion-fast, 150ms) var(--d-motion-ease-out, cubic-bezier(0,0,0.2,1))',
    ],
  ]);
  emitRule('.d-lift-hover:hover', [
    ['transform', 'translateY(-2px)'],
    ['box-shadow', 'var(--d-elevation-3, 0 4px 12px rgba(0,0,0,0.10))'],
  ]);

  emitRule('.d-ripple', [
    ['position', 'relative'],
    ['overflow', 'hidden'],
  ]);
  emitRule('.d-ripple::after', [
    ['content', "''"],
    ['position', 'absolute'],
    ['inset', '0'],
    ['background', 'radial-gradient(circle, currentColor 10%, transparent 10.01%)'],
    ['opacity', '0'],
    ['transform', 'scale(0)'],
    ['transition', 'transform var(--d-motion-slow, 400ms), opacity var(--d-motion-slow, 400ms)'],
    ['pointer-events', 'none'],
  ]);
  emitRule('.d-ripple:active::after', [
    ['transform', 'scale(1)'],
    ['opacity', '0.15'],
    ['transition', '0s'],
  ]);

  // ── 16. Typography Treatments ──
  // Canonical type hierarchy. Before these, scaffolds
  // hand-rolled font-size/font-weight/letter-spacing on every heading.
  // Themes can override the --d-text-*, --d-weight-*, --d-tracking-*,
  // --d-leading-* tokens to tune the hierarchy globally.
  // Names intentionally distinct from existing `.d-label` (anchored
  // section-header treatment) and `.d-data` (tabular data surface).

  emitRule('.d-display', [
    ['font-family', 'var(--d-font-display, var(--d-font-body, system-ui, sans-serif))'],
    ['font-weight', 'var(--d-weight-bold, 700)'],
    ['font-size', 'var(--d-text-5xl, 3rem)'],
    ['line-height', 'var(--d-leading-tight, 1.1)'],
    ['letter-spacing', 'var(--d-tracking-tight, -0.02em)'],
    ['margin', '0'],
  ]);

  emitRule('.d-headline', [
    ['font-family', 'var(--d-font-display, var(--d-font-body, system-ui, sans-serif))'],
    ['font-weight', 'var(--d-weight-semibold, 600)'],
    ['font-size', 'var(--d-text-3xl, 1.875rem)'],
    ['line-height', 'var(--d-leading-snug, 1.25)'],
    ['letter-spacing', 'var(--d-tracking-tight, -0.01em)'],
    ['margin', '0'],
  ]);

  emitRule('.d-title', [
    ['font-family', 'var(--d-font-display, var(--d-font-body, system-ui, sans-serif))'],
    ['font-weight', 'var(--d-weight-semibold, 600)'],
    ['font-size', 'var(--d-text-xl, 1.25rem)'],
    ['line-height', 'var(--d-leading-snug, 1.25)'],
    ['margin', '0'],
  ]);

  emitRule('.d-subtitle', [
    ['font-family', 'var(--d-font-body, system-ui, sans-serif)'],
    ['font-weight', 'var(--d-weight-regular, 400)'],
    ['font-size', 'var(--d-text-lg, 1.125rem)'],
    ['line-height', 'var(--d-leading-snug, 1.375)'],
    ['color', 'var(--d-text-muted)'],
    ['margin', '0'],
  ]);

  emitRule('.d-prose', [
    ['font-family', 'var(--d-font-body, system-ui, sans-serif)'],
    ['font-size', 'var(--d-text-base, 1rem)'],
    ['line-height', 'var(--d-leading-relaxed, 1.625)'],
  ]);

  emitRule('.d-body', [
    ['font-family', 'var(--d-font-body, system-ui, sans-serif)'],
    ['font-size', 'var(--d-text-base, 1rem)'],
    ['line-height', 'var(--d-leading-normal, 1.5)'],
  ]);

  emitRule('.d-caption', [
    ['font-family', 'var(--d-font-body, system-ui, sans-serif)'],
    ['font-size', 'var(--d-text-sm, 0.875rem)'],
    ['line-height', 'var(--d-leading-normal, 1.5)'],
    ['color', 'var(--d-text-muted)'],
  ]);

  emitRule('.d-eyebrow', [
    ['font-family', 'var(--d-font-body, system-ui, sans-serif)'],
    ['font-size', 'var(--d-text-xs, 0.75rem)'],
    ['line-height', '1.2'],
    ['font-weight', 'var(--d-weight-semibold, 600)'],
    ['letter-spacing', 'var(--d-tracking-wider, 0.08em)'],
    ['text-transform', 'uppercase'],
    ['color', 'var(--d-accent)'],
  ]);

  emitRule('.d-numeric', [['font-variant-numeric', 'tabular-nums']]);

  emitRule('.d-mono-text', [
    ['font-family', 'var(--d-font-mono, ui-monospace, monospace)'],
    ['font-variant-numeric', 'tabular-nums'],
  ]);

  // Composite Card — .d-card family.
  // Structural companion to the decorator layer. Replaces hand-composed
  // flex/gap/padding on `carbon-card` etc. Pairs with a theme decorator
  // for visual polish (hover glow, gradient border).

  emitRule('.d-card', [
    ['display', 'flex'],
    ['flex-direction', 'column'],
    ['gap', '0.75rem'],
    ['padding', '1rem'],
    ['background', 'var(--d-surface)'],
    ['border', '1px solid var(--d-border)'],
    ['border-radius', 'var(--d-radius)'],
    ['box-shadow', 'var(--d-elevation-1, var(--d-shadow-sm))'],
  ]);

  emitRule('.d-card-header', [
    ['display', 'flex'],
    ['align-items', 'center'],
    ['justify-content', 'space-between'],
    ['gap', '0.5rem'],
    ['padding-bottom', '0.5rem'],
    ['border-bottom', '1px solid var(--d-border)'],
  ]);

  emitRule('.d-card-body', [
    ['display', 'flex'],
    ['flex-direction', 'column'],
    ['gap', '0.5rem'],
    ['flex', '1 1 auto'],
    ['min-width', '0'],
  ]);

  emitRule('.d-card-footer', [
    ['display', 'flex'],
    ['align-items', 'center'],
    ['justify-content', 'flex-end'],
    ['gap', '0.5rem'],
    ['padding-top', '0.5rem'],
    ['border-top', '1px solid var(--d-border)'],
  ]);

  emitRule('.d-card[data-padding="compact"]', [['padding', '0.625rem']]);
  emitRule('.d-card[data-padding="spacious"]', [['padding', '1.5rem']]);
  emitRule('.d-card[data-padding="none"]', [['padding', '0']]);

  emitRule('.d-card[data-interactive]', [
    ['cursor', 'pointer'],
    [
      'transition',
      'box-shadow var(--d-motion-fast, 150ms) var(--d-motion-ease-out, cubic-bezier(0,0,0.2,1)), border-color var(--d-motion-fast, 150ms) var(--d-motion-ease-out, cubic-bezier(0,0,0.2,1))',
    ],
  ]);
  emitRule('.d-card[data-interactive]:hover', [
    ['box-shadow', 'var(--d-elevation-2, var(--d-shadow))'],
    ['border-color', 'var(--d-primary)'],
  ]);

  // ── 17. Elevation Utility — .d-elevate[data-level] ──
  // Formal depth scale, cross-theme. Shadow values read
  // from --d-elevation-* tokens. Dark themes emit stronger alpha values
  // via mode-aware token defaults.

  emitRule('.d-elevate[data-level="0"]', [['box-shadow', 'var(--d-elevation-0, none)']]);
  emitRule('.d-elevate[data-level="1"]', [
    ['box-shadow', 'var(--d-elevation-1, 0 1px 2px rgba(0,0,0,0.06))'],
  ]);
  emitRule('.d-elevate[data-level="2"]', [
    ['box-shadow', 'var(--d-elevation-2, 0 2px 4px rgba(0,0,0,0.08))'],
  ]);
  emitRule('.d-elevate[data-level="3"]', [
    ['box-shadow', 'var(--d-elevation-3, 0 4px 12px rgba(0,0,0,0.10))'],
  ]);
  emitRule('.d-elevate[data-level="4"]', [
    ['box-shadow', 'var(--d-elevation-4, 0 8px 24px rgba(0,0,0,0.14))'],
  ]);
  emitRule('.d-elevate[data-level="5"]', [
    ['box-shadow', 'var(--d-elevation-5, 0 16px 48px rgba(0,0,0,0.18))'],
  ]);

  // Hotkey chord indicator.
  // When a user presses the prefix key of a chord hotkey (e.g., `g` in
  // `g m` → /metrics), they currently get no visual feedback — they have
  // to trust a 500-900ms chord window is open. This treatment is the
  // corner badge shown while the chord is armed. Apply
  // data-visible="true" when chord begins, remove when it times out or
  // resolves. data-prefix shows the pressed key.
  //
  // Usage:
  //   <div className="d-hotkey-indicator" data-visible={isArmed} data-prefix="g" />
  //
  // Enable via hotkey_semantics.show_chord_indicator.

  emitRule('.d-hotkey-indicator', [
    ['position', 'fixed'],
    ['bottom', '1.5rem'],
    ['right', '1.5rem'],
    ['padding', '0.5rem 0.75rem'],
    ['background', 'var(--d-surface-raised)'],
    ['border', '1px solid var(--d-border)'],
    ['border-radius', 'var(--d-radius)'],
    ['box-shadow', 'var(--d-elevation-3, 0 4px 12px rgba(0,0,0,0.10))'],
    ['font-family', 'var(--d-font-mono, ui-monospace, monospace)'],
    ['font-size', '0.875rem'],
    ['color', 'var(--d-text)'],
    ['opacity', '0'],
    ['transform', 'translateY(8px)'],
    ['pointer-events', 'none'],
    ['z-index', '60'],
    [
      'transition',
      'opacity var(--d-motion-fast, 150ms) var(--d-motion-ease-out, cubic-bezier(0,0,0.2,1)), transform var(--d-motion-fast, 150ms) var(--d-motion-ease-out, cubic-bezier(0,0,0.2,1))',
    ],
  ]);
  emitRule('.d-hotkey-indicator[data-visible="true"]', [
    ['opacity', '1'],
    ['transform', 'translateY(0)'],
  ]);
  emitRule('.d-hotkey-indicator::before', [
    ['content', "'Chord: '"],
    ['color', 'var(--d-text-muted)'],
    ['margin-right', '0.25rem'],
  ]);
  emitRule('.d-hotkey-indicator::after', [
    ['content', "attr(data-prefix) '…'"],
    ['color', 'var(--d-accent)'],
    ['font-weight', '600'],
  ]);
  // Data-viz primitives.
  // Last hand-rolled territory before this PR. Each primitive replaces
  // a category of inline SVG / CSS that scaffolds previously composed
  // ad-hoc. All read from token vars so themes can tune appearance.

  // Timeline rail — vertical timeline with dotted markers
  emitRule('.d-timeline-rail', [
    ['position', 'relative'],
    ['padding-left', '2rem'],
  ]);
  emitRule('.d-timeline-rail::before', [
    ['content', "''"],
    ['position', 'absolute'],
    ['left', '0.5rem'],
    ['top', '0.5rem'],
    ['bottom', '0.5rem'],
    ['width', '2px'],
    ['background', 'var(--d-border)'],
  ]);
  emitRule('.d-timeline-dot', [
    ['position', 'relative'],
    ['margin-bottom', '1rem'],
  ]);
  emitRule('.d-timeline-dot::before', [
    ['content', "''"],
    ['position', 'absolute'],
    ['left', '-1.5rem'],
    ['top', '0.5rem'],
    ['width', '0.625rem'],
    ['height', '0.625rem'],
    ['border-radius', '50%'],
    ['background', 'var(--d-border)'],
    ['border', '2px solid var(--d-bg)'],
    ['box-sizing', 'border-box'],
  ]);
  emitRule('.d-timeline-dot[data-state="active"]::before', [['background', 'var(--d-primary)']]);
  emitRule('.d-timeline-dot[data-state="done"]::before', [['background', 'var(--d-success)']]);
  emitRule('.d-timeline-dot[data-state="error"]::before', [['background', 'var(--d-error)']]);
  emitRule('.d-timeline-dot[data-state="warning"]::before', [['background', 'var(--d-warning)']]);

  // Sparkline — small inline trend SVG. Author renders the SVG; treatments
  // style stroke + area + trend variants.
  emitRule('.d-sparkline', [
    ['display', 'inline-block'],
    ['vertical-align', 'middle'],
    ['height', 'var(--d-sparkline-height, 1.5rem)'],
    ['width', 'var(--d-sparkline-width, 5rem)'],
  ]);
  emitRule('.d-sparkline-path', [
    ['fill', 'none'],
    ['stroke', 'var(--d-primary)'],
    ['stroke-width', '1.5'],
    ['stroke-linecap', 'round'],
    ['stroke-linejoin', 'round'],
  ]);
  emitRule('.d-sparkline-area', [
    ['fill', 'color-mix(in srgb, var(--d-primary) 15%, transparent)'],
    ['stroke', 'none'],
  ]);
  emitRule('.d-sparkline[data-trend="up"] .d-sparkline-path', [['stroke', 'var(--d-success)']]);
  emitRule('.d-sparkline[data-trend="up"] .d-sparkline-area', [
    ['fill', 'color-mix(in srgb, var(--d-success) 15%, transparent)'],
  ]);
  emitRule('.d-sparkline[data-trend="down"] .d-sparkline-path', [['stroke', 'var(--d-error)']]);
  emitRule('.d-sparkline[data-trend="down"] .d-sparkline-area', [
    ['fill', 'color-mix(in srgb, var(--d-error) 15%, transparent)'],
  ]);

  // Intent radar — concentric ring backdrop for confidence/score wheels
  emitRule('.d-intent-radar', [
    ['position', 'relative'],
    ['width', 'var(--d-radar-size, 200px)'],
    ['height', 'var(--d-radar-size, 200px)'],
  ]);
  emitRule('.d-intent-radar-ring', [
    ['position', 'absolute'],
    ['border-radius', '50%'],
    ['border', '1px solid var(--d-border)'],
    ['inset', '0'],
  ]);
  emitRule('.d-intent-radar-ring[data-level="2"]', [['inset', '12.5%']]);
  emitRule('.d-intent-radar-ring[data-level="3"]', [['inset', '25%']]);
  emitRule('.d-intent-radar-ring[data-level="4"]', [['inset', '37.5%']]);
  emitRule('.d-intent-radar-ring[data-level="5"]', [['inset', '50%']]);
  emitRule('.d-intent-radar-axis', [
    ['position', 'absolute'],
    ['top', '50%'],
    ['left', '50%'],
    ['width', '50%'],
    ['height', '1px'],
    ['background', 'var(--d-border)'],
    ['transform-origin', '0 0'],
    ['transform', 'rotate(var(--d-radar-axis-angle, 0deg))'],
  ]);

  // Waveform — audio/signal waveform path container
  emitRule('.d-waveform', [
    ['display', 'block'],
    ['width', '100%'],
    ['height', 'var(--d-waveform-height, 3rem)'],
    ['overflow', 'hidden'],
  ]);
  emitRule('.d-waveform-path', [
    ['fill', 'color-mix(in srgb, var(--d-primary) 30%, transparent)'],
    ['stroke', 'var(--d-primary)'],
    ['stroke-width', '1'],
  ]);
  emitRule('.d-waveform[data-state="active"] .d-waveform-path', [
    ['fill', 'color-mix(in srgb, var(--d-success) 30%, transparent)'],
    ['stroke', 'var(--d-success)'],
  ]);

  // QR placeholder — pure CSS placeholder pattern for QR codes
  emitRule('.d-qr-placeholder', [
    ['display', 'block'],
    ['width', 'var(--d-qr-size, 8rem)'],
    ['height', 'var(--d-qr-size, 8rem)'],
    [
      'background',
      'repeating-linear-gradient(0deg, var(--d-text) 0 4px, transparent 4px 8px), repeating-linear-gradient(90deg, var(--d-text) 0 4px, transparent 4px 8px)',
    ],
    ['background-color', 'var(--d-surface)'],
    ['border-radius', 'var(--d-radius-sm)'],
    ['border', '8px solid var(--d-surface)'],
    ['outline', '1px solid var(--d-border)'],
  ]);

  // Conic ring — gauge / confidence ring built with conic-gradient
  emitRule('.d-conic-ring', [
    ['--d-conic-value', '0.5'],
    ['width', 'var(--d-conic-size, 4rem)'],
    ['height', 'var(--d-conic-size, 4rem)'],
    ['border-radius', '50%'],
    [
      'background',
      'conic-gradient(var(--d-conic-color, var(--d-primary)) 0deg, var(--d-conic-color, var(--d-primary)) calc(var(--d-conic-value) * 360deg), var(--d-border) calc(var(--d-conic-value) * 360deg), var(--d-border) 360deg)',
    ],
    ['position', 'relative'],
    ['display', 'inline-flex'],
    ['align-items', 'center'],
    ['justify-content', 'center'],
  ]);
  emitRule('.d-conic-ring::before', [
    ['content', "''"],
    ['position', 'absolute'],
    ['inset', 'var(--d-conic-thickness, 0.5rem)'],
    ['border-radius', '50%'],
    ['background', 'var(--d-bg)'],
  ]);
  emitRule('.d-conic-ring > *', [
    ['position', 'relative'],
    ['z-index', '1'],
  ]);
  emitRule('.d-conic-ring[data-state="success"]', [['--d-conic-color', 'var(--d-success)']]);
  emitRule('.d-conic-ring[data-state="warning"]', [['--d-conic-color', 'var(--d-warning)']]);
  emitRule('.d-conic-ring[data-state="error"]', [['--d-conic-color', 'var(--d-error)']]);

  // Heatmap cell — single intensity cell. Author sets --d-heatmap-intensity (0..1).
  emitRule('.d-heatmap-cell', [
    ['--d-heatmap-intensity', '0'],
    ['display', 'inline-block'],
    ['width', 'var(--d-heatmap-cell-size, 0.875rem)'],
    ['height', 'var(--d-heatmap-cell-size, 0.875rem)'],
    ['border-radius', '2px'],
    [
      'background',
      'color-mix(in srgb, var(--d-primary) calc(var(--d-heatmap-intensity) * 100%), var(--d-surface))',
    ],
    ['border', '1px solid var(--d-border)'],
    ['vertical-align', 'middle'],
  ]);
  emitRule('.d-heatmap-cell[data-status="error"]', [
    [
      'background',
      'color-mix(in srgb, var(--d-error) calc(var(--d-heatmap-intensity) * 100%), var(--d-surface))',
    ],
  ]);
  emitRule('.d-heatmap-cell[data-status="success"]', [
    [
      'background',
      'color-mix(in srgb, var(--d-success) calc(var(--d-heatmap-intensity) * 100%), var(--d-surface))',
    ],
  ]);

  // ── Theme-scoped overrides (e.g. backdrop-filter) ──
  if (themeOverrideRules.length > 0) {
    lines.push('/* ── Theme-scoped Treatment Overrides ── */');
    lines.push('');
    for (const rule of themeOverrideRules) {
      lines.push(rule);
      lines.push('');
    }
  }

  // ── Keyframes (inside treatments layer) ──

  lines.push('/* ── Keyframes ── */');
  lines.push('');
  lines.push('@keyframes decantr-pulse {');
  lines.push('  0%, 100% { opacity: 1; }');
  lines.push('  50% { opacity: 0.5; }');
  lines.push('}');
  lines.push('');
  lines.push('@keyframes d-fade-in {');
  lines.push('  from { opacity: 0; }');
  lines.push('  to { opacity: 1; }');
  lines.push('}');
  lines.push('');
  lines.push('@keyframes d-slide-up {');
  lines.push('  from { opacity: 0; transform: translateY(12px); }');
  lines.push('  to { opacity: 1; transform: translateY(0); }');
  lines.push('}');
  lines.push('');
  lines.push('@keyframes d-scale-in {');
  lines.push('  from { opacity: 0; transform: scale(0.96); }');
  lines.push('  to { opacity: 1; transform: scale(1); }');
  lines.push('}');
  lines.push('');
  lines.push('@keyframes d-pulse {');
  lines.push('  0%, 100% { opacity: 1; }');
  lines.push('  50% { opacity: 0.5; }');
  lines.push('}');
  lines.push('');
  lines.push('@keyframes d-pulse-ring {');
  lines.push('  0% { box-shadow: 0 0 0 0 color-mix(in srgb, var(--d-primary) 40%, transparent); }');
  lines.push('  100% { box-shadow: 0 0 0 12px transparent; }');
  lines.push('}');
  lines.push('');
  lines.push('@keyframes d-shimmer {');
  lines.push('  0% { background-position: -200% 0; }');
  lines.push('  100% { background-position: 200% 0; }');
  lines.push('}');
  lines.push('');
  lines.push('@keyframes d-float {');
  lines.push('  0%, 100% { transform: translateY(0); }');
  lines.push('  50% { transform: translateY(-4px); }');
  lines.push('}');
  lines.push('');
  lines.push('/* Respect user motion preferences — disable all declarative motion */');
  lines.push('@media (prefers-reduced-motion: reduce) {');
  lines.push('  .d-enter-fade, .d-enter-slide-up, .d-enter-scale, .d-stagger-children > *,');
  lines.push('  .d-pulse, .d-pulse-ring, .d-shimmer, .d-float {');
  lines.push('    animation: none !important;');
  lines.push('  }');
  lines.push('  .d-glow-hover, .d-scale-hover, .d-lift-hover, .d-ripple::after {');
  lines.push('    transition: none !important;');
  lines.push('  }');
  lines.push('  .d-scale-hover:hover, .d-lift-hover:hover {');
  lines.push('    transform: none !important;');
  lines.push('  }');
  lines.push('}');
  lines.push('');
  lines.push('} /* end @layer treatments */');

  const decoratorRules: string[] = [];
  if (themeDecoratorDefinitions) {
    // Emit a base rule plus optional state-variant pseudo-class rules.
    // Pseudo-class fields (:hover / :focus-visible / :active) are additive —
    // absent fields produce no rule, preserving prior behavior for themes
    // that haven't declared state variants yet.
    const emitProps = (selector: string, props: Record<string, string>) => {
      const entries = Object.entries(props);
      if (entries.length === 0) return;
      decoratorRules.push(`${selector} {`);
      for (const [prop, value] of entries) {
        decoratorRules.push(`  ${prop}: ${value};`);
        if (prop === 'animation') {
          const animationName = value.split(/\s+/)[0]?.trim();
          if (animationName) decoratorAnimationNames.add(animationName);
        }
      }
      decoratorRules.push('}');
      decoratorRules.push('');
    };
    for (const [className, definition] of Object.entries(themeDecoratorDefinitions)) {
      emitProps(`.${className}`, definition?.suggested_properties ?? {});
      emitProps(`.${className}:hover`, definition?.hover_properties ?? {});
      emitProps(`.${className}:focus-visible`, definition?.focus_properties ?? {});
      emitProps(`.${className}:active`, definition?.active_properties ?? {});
    }
  }

  const decoratorKeyframes: string[] = [];
  if (decoratorAnimationNames.has('carbon-fade-slide')) {
    decoratorKeyframes.push('@keyframes carbon-fade-slide {');
    decoratorKeyframes.push('  from { opacity: 0; transform: translateY(12px); }');
    decoratorKeyframes.push('  to { opacity: 1; transform: translateY(0); }');
    decoratorKeyframes.push('}');
    decoratorKeyframes.push('');
  }
  if (decoratorAnimationNames.has('pulse')) {
    decoratorKeyframes.push('@keyframes pulse {');
    decoratorKeyframes.push('  0%, 100% { opacity: 1; }');
    decoratorKeyframes.push('  50% { opacity: 0.5; }');
    decoratorKeyframes.push('}');
    decoratorKeyframes.push('');
  }

  const decoratorComments = themeDecorators
    ? Object.entries(themeDecorators)
        .map(([name, description]) => `  /* .${name}: ${description} */`)
        .join('\n')
    : '  /* No theme decorators available. */';
  const decoratorBody =
    decoratorRules.length > 0
      ? `${decoratorRules.join('\n')}${decoratorKeyframes.length > 0 ? `\n${decoratorKeyframes.join('\n')}` : ''}${decoratorComments ? `\n${decoratorComments}` : ''}`
      : `${decoratorComments}\n  /* Canonical decorator CSS should be derived from theme decorator definitions when available. */`;
  const decoratorBlock = `\n@layer decorators {\n${decoratorBody}\n}\n`;
  lines.push(decoratorBlock);

  return lines.join('\n');
}

/**
 * Generate personality-derived CSS utility classes based on keyword analysis.
 * Scans personality array for known keywords and emits matching utility rules.
 */
export function generatePersonalityCSS(
  personality: string[],
  themeData: { motion?: { entrance?: string }; palette?: Record<string, Record<string, string>> },
): string {
  const text = personality.join(' ').toLowerCase();
  const rules: string[] = [];

  // Neon glow utilities
  if (text.includes('neon') || text.includes('glow')) {
    const glowColor = 'var(--d-accent-glow, rgba(0, 212, 255, 0.3))';
    rules.push(`.neon-glow { box-shadow: 0 0 20px ${glowColor}; }`);
    rules.push(
      `.neon-glow-hover:hover { box-shadow: 0 0 24px ${glowColor}; transition: box-shadow var(--d-duration-hover, 0.15s) var(--d-easing, ease); }`,
    );
    rules.push(`.neon-text-glow { text-shadow: 0 0 12px ${glowColor}; }`);
    rules.push(
      `.neon-border-glow { border-color: var(--d-accent); box-shadow: 0 0 8px ${glowColor}; }`,
    );
  }

  // Monospace data utility
  if (text.includes('monospace') || text.includes('mono')) {
    rules.push(
      `.mono-data { font-family: var(--d-font-mono, ui-monospace, monospace); font-variant-numeric: tabular-nums; }`,
    );
  }

  // Status ring utilities with size variants.
  if (text.includes('pulse') || text.includes('ring') || text.includes('status')) {
    rules.push(
      `.status-ring { width: 48px; height: 48px; border-radius: 50%; border: 2px solid var(--d-border); display: flex; align-items: center; justify-content: center; position: relative; transition: border-color 0.2s ease, box-shadow 0.2s ease; }`,
    );
    // Size variants — sm (32px), md (48px default), lg (64px). Before this,
    // authors set `style={{ width: 32px }}` on every usage that needed a
    // smaller ring.
    rules.push(`.status-ring[data-size="sm"] { width: 32px; height: 32px; border-width: 1.5px; }`);
    rules.push(`.status-ring[data-size="md"] { width: 48px; height: 48px; border-width: 2px; }`);
    rules.push(`.status-ring[data-size="lg"] { width: 64px; height: 64px; border-width: 2.5px; }`);
    rules.push(`.status-ring[data-status="active"] { border-color: var(--d-success); }`);
    rules.push(
      `.status-ring[data-status="error"] { border-color: var(--d-error); box-shadow: 0 0 12px color-mix(in srgb, var(--d-error) 25%, transparent); }`,
    );
    rules.push(`.status-ring[data-status="warning"] { border-color: var(--d-warning); }`);
    rules.push(`.status-ring[data-status="idle"] { border-color: var(--d-text-muted); }`);
    rules.push(
      `.status-ring[data-status="processing"] { border-color: var(--d-primary); animation: pulse-ring 2s ease-in-out infinite; }`,
    );
    rules.push(
      `@keyframes pulse-ring { 0% { opacity: 0.6; transform: scale(1); } 100% { opacity: 0; transform: scale(1.3); } }`,
    );
    rules.push(
      `.status-ring[data-status="active"]::after { content: ''; position: absolute; inset: -4px; border-radius: 50%; border: 2px solid var(--d-success); opacity: 0; animation: pulse-ring 2s ease-out infinite; }`,
    );
  }

  // Entrance animation
  if (themeData.motion?.entrance) {
    rules.push(
      `.entrance-fade { animation: decantr-entrance var(--d-duration-entrance, 0.2s) var(--d-easing, ease-out); }`,
    );
    rules.push(
      `@keyframes decantr-entrance { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: translateY(0); } }`,
    );
  }

  if (rules.length === 0) return '';
  return (
    '\n@layer utilities {\n\n/* ── Personality-Derived Utilities ── */\n\n' +
    rules.join('\n\n') +
    '\n\n} /* end @layer utilities */\n'
  );
}
