← Files DataARCHIVED FILE

tests/data-app-custom-layout-browser.smoke.mjs

118 KB · Sep 30, 2026 · 23:19 UTC

↓ Download file

import assert from "node:assert/strict";
import { cpSync, mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs";
import { tmpdir } from "node:os";
import { dirname, join, resolve } from "node:path";
import { fileURLToPath, pathToFileURL } from "node:url";

import { chromium } from "playwright-core";

import { installDashboardBrowserMocks, resolveChromiumExecutable, runDataAppFixtureBuild } from "./browser-helpers.mjs";
import { prepareDataApp } from "../scripts/prepare-data-app.mjs";

const pluginRoot = resolve(dirname(fileURLToPath(import.meta.url)), "..");
const template = join(pluginRoot, "templates/data-app/base");
const reviewDirectory = process.env.DATA_APP_REVIEW_DIR && resolve(process.env.DATA_APP_REVIEW_DIR);
if (reviewDirectory) mkdirSync(reviewDirectory, { recursive: true });

async function assertComponentLabGeometry(browser) {
  const directory = mkdtempSync(join(tmpdir(), "data-lab-layout-"));
  const page = await browser.newPage();
  try {
    const { build } = await import(pathToFileURL(join(template, "node_modules/vite/dist/node/index.js")));
    await build({ root: template, configFile: join(template, "vite.config.js"), logLevel: "error",
      build: { outDir: directory, emptyOutDir: true, rolldownOptions: { input: join(template, "examples/component-lab/index.html") } } });
    await installDashboardBrowserMocks(page);
    await page.goto(pathToFileURL(join(directory, "examples/component-lab/index.html")).href);
    assert.equal(await page.locator(".page-rulers, .page-ruler, .ruler-guide").count(), 0);
    for (const width of [1920, 1440, 768, 390]) {
      await page.setViewportSize({ width, height: 900 });
      const grouped = page.locator(".library-chart-grid .bar-family-grouped-list");
      await grouped.scrollIntoViewIfNeeded();
      const values = await grouped.locator(".bar-family-grouped-bar").evaluateAll(bars => bars.map(bar => {
        const track=bar.querySelector(".bar-family-grouped-track").getBoundingClientRect();
        const value=bar.querySelector(".bar-family-grouped-value").getBoundingClientRect();
        const fill=bar.querySelector(".bar-family-grouped-track > span").getBoundingClientRect();
        return {gap:value.left-track.right, trackHeight:track.height, fillHeight:fill.height,
          alignment:Math.abs((track.top+track.bottom-value.top-value.bottom)/2)};
      }));
      assert.equal(values.length,10);
      for(const value of values) {
        assert(value.gap>=10,`Grouped value overlaps the track at ${width}px`);
        assert.equal(value.trackHeight,12);assert.equal(value.fillHeight,12);
        assert(value.alignment<1,`Grouped value not centered at ${width}px`);
      }
      const first=grouped.locator(".bar-family-grouped-bar").first();
      const geometry = () => first.evaluate(element => {
        const rect = element.getBoundingClientRect();
        const group = element.closest(".bar-family-grouped-list").getBoundingClientRect();
        return { x: rect.x - group.x, y: rect.y - group.y, width: rect.width, height: rect.height,
          groupWidth: group.width, groupHeight: group.height };
      });
      const before=await geometry();await first.hover();
      const after = await geometry();
      assert.ok(Object.keys(before).every(key => Math.abs(after[key] - before[key]) <= 1),
        `Hover must not change grouped-bar geometry: ${JSON.stringify({ width, before, after })}`);
      const segment=page.locator('[data-component-id="library-chart-bar-segmented"]');
      const composition = await segment.evaluate(card => {
        const bounds = card.getBoundingClientRect();
        const root = card.querySelector(".bar-family-segmented");
        const rows = [...card.querySelectorAll(".bar-family-segment-annotations > div")].map(row => row.getBoundingClientRect());
        const peers = [...card.parentElement.children].map(peer => peer.getBoundingClientRect()).filter(peer => Math.abs(peer.top - bounds.top) < 1);
        return { rootWidth: root.clientWidth, firstTop: rows[0].top, secondTop: rows[1].top,
          bottom: bounds.bottom, rowBottom: Math.max(...peers.map(peer => peer.bottom)),
          contained: rows.every(row => row.left >= bounds.left && row.right <= bounds.right) };
      });
      assert(Math.abs(composition.bottom - composition.rowBottom) < 1, "Composition card fills its grid row");
      assert.equal(Math.abs(composition.firstTop - composition.secondTop) < 1, composition.rootWidth > 560,
        "Composition annotations use one column in narrow cards, two when labels have room");
      assert(composition.contained, "Composition annotations stay inside the card");
      await page.evaluate(()=>window.scrollTo(0,0));
      const sidebar=page.locator(".library-navigation");
      if(width>760) {
        assert((await sidebar.boundingBox()).x<2,"Inventory sidebar must dock to the page edge");
        const scrollInset = await sidebar.evaluate(sidebar => sidebar.getBoundingClientRect().right - sidebar.querySelector(".library-nav-items").getBoundingClientRect().right);
        assert(scrollInset < 2, "Sidebar scrollbar belongs at the divider, not inside its content padding");
        assert(await sidebar.locator(".library-nav-items").evaluate(nav=>nav.scrollHeight>nav.clientHeight),"Sidebar owns its overflow");
      } else assert(await sidebar.getByRole("button",{name:/Components/}).isVisible());
      assert.equal(await page.evaluate(()=>document.documentElement.scrollWidth>innerWidth+1),false);
    }
  } finally { await page.close();rmSync(directory,{recursive:true,force:true}); }
}

async function assertReferenceLayoutContainment(browser) {
  const directory = mkdtempSync(join(tmpdir(), "data-reference-layout-"));
  try {
    for (const example of ["fleet-operations", "acme-workflow", "business-performance", "infrastructure-capacity", "finance", "product-tracker"]) {
      const { output } = await prepareDataApp({ output: join(directory, example), example, allowDraft: true });
      const build = runDataAppFixtureBuild(output, { pluginRoot });
      assert.equal(build.status, 0, build.stdout + build.stderr);
      const page = await browser.newPage();
      const errors = [];
      page.on("pageerror", error => errors.push(error.message));
      await installDashboardBrowserMocks(page);
      await page.goto(pathToFileURL(join(output, "dist/index.html")).href, { waitUntil: "load" });
      await page.waitForFunction(() => document.querySelector('main [data-component-id]')
        && !document.querySelector('main [aria-busy="true"]'));
      for (const width of [390, 768, 1024, ...(example === "finance" ? [1200] : []), 1440, 1599, 1600, 2400]) {
        await page.setViewportSize({ width, height: 900 });
        if (example === "finance") {
          // Wait for ResizeObserver to update the chart before measuring its SVG labels.
          await page.waitForFunction(() => {
            const chart = document.querySelector(".finance-combined-chart");
            const svg = chart?.querySelector("svg");
            return svg && Math.abs(svg.viewBox.baseVal.width - chart.getBoundingClientRect().width) < 1;
          });
        }
        const frame = await page.locator(example === "fleet-operations" ? ".fleet-operations-page"
          : example === "finance" ? ".finance-example-page" : 'main[data-data-app-content="dashboard"]').evaluate(element => {
          const rect = element.getBoundingClientRect(), styles = getComputedStyle(element);
          const gutter = parseFloat(styles.getPropertyValue("--data-app-layout-gutter")) || 0;
          const left = parseFloat(styles.paddingLeft) || 0, right = parseFloat(styles.paddingRight) || 0;
          const panelPadding = parseFloat(styles.getPropertyValue("--fleet-panel-padding-inline")) || 0;
          return { width: rect.width, left, right, gutter, panelPadding,
            viewport: element.closest(".dashboard-root").getBoundingClientRect().width };
        });
        if (["fleet-operations", "finance"].includes(example)) {
          assert.ok(Math.abs(frame.width - frame.viewport) <= 1, example + " preserves its full-width custom frame");
          if (example === "finance") {
            assert.equal(frame.left, 0, "Finance keeps its full-width viewport shell");
            assert.equal(frame.right, frame.left);
            const watchlist = await page.locator(".finance-watchlist-card").evaluate(card => {
              const box = card.getBoundingClientRect(), rail = card.parentElement;
              const list = card.querySelector(".finance-stock-list");
              const group = document.querySelector(".finance-hero").getBoundingClientRect();
              const main = document.querySelector(".finance-main-column").getBoundingClientRect();
              const support = document.querySelector(".finance-right-rail").getBoundingClientRect();
              return { left: box.left, bottom: box.bottom, variant: card.dataset.componentVariant,
                groupLeft: group.left, groupRight: group.right, mainWidth: main.width,
                watchlistGap: main.left - box.right, supportGap: support.left - main.right,
                railBorder: getComputedStyle(rail).borderRightWidth, overflow: getComputedStyle(list).overflowY,
                listBottom: list.getBoundingClientRect().bottom, viewportHeight: innerHeight };
            });
            assert.equal(watchlist.variant, "card", "Watchlist uses the shared card surface");
            assert.equal(watchlist.left - watchlist.groupLeft, width <= 820 ? 16 : width <= 1280 ? 24 : 32, "Watchlist floats inside the responsive gutter");
            assert.ok(Math.abs(watchlist.groupLeft - (frame.viewport - watchlist.groupRight)) <= 1, "The whole Finance group stays centered");
            assert.ok(watchlist.mainWidth <= 960 + 1, "Middle content is capped at 960px");
            if (width > 1280) {
              assert.equal(watchlist.watchlistGap, 32, "Watchlist remains close to the middle content");
              assert.equal(watchlist.supportGap, 32, "Supporting rail remains close to the middle content");
            }
            assert.equal(watchlist.railBorder, "0px", "No full-height sidebar divider");
            assert.ok(watchlist.bottom <= watchlist.viewportHeight, "Watchlist fits its viewport");
            assert.ok(watchlist.listBottom <= watchlist.bottom, "Stock list stays inside its card");
            if (width > 820) assert.equal(watchlist.overflow, "auto", "Watchlist owns its vertical scrolling");
            if (width <= 820) {
              const geometry = await page.locator(".finance-stock-list").evaluate(nav => ({
                cards: [...nav.children].map(card => ({ width: card.clientWidth, content: card.scrollWidth })),
                axes: [...document.querySelectorAll(".finance-combined-chart .finance-axis-label, .finance-position-value")]
                  .map(label => label.getBoundingClientRect().right),
              }));
              assert.ok(geometry.cards.every(card => card.content <= card.width + 1), "Watch cards must not overlap adjacent stocks");
              assert.ok(geometry.axes.every(right => right <= frame.viewport), "Price and volume labels remain inside the viewport");
            }
          } else {
            assert.equal(frame.gutter, 0, "Fleet viewport has no outer page gutter");
            assert.equal(frame.panelPadding, width <= 720 ? 24 : 64, "Fleet keeps its independent panel padding");
          }
        } else {
          assert.ok(frame.width <= 1440 + 64 + 1, example + " content cap at " + width);
          assert.equal(frame.left, width <= 650 ? 16 : 32, example + " left gutter at " + width);
          assert.equal(frame.right, frame.left, example + " symmetric gutters");
        }
        const header = await page.locator(".dashboard-topbar").boundingBox();
        assert.ok(Math.abs(header.width - frame.viewport) <= 1, example + " full-width shell header");
        if (reviewDirectory && [390, 1440].includes(width)) {
          await page.evaluate(() => document.fonts.ready);
          await page.screenshot({ path: join(reviewDirectory, `${example}-${width}.png`), animations: "disabled" });
        }
        if (example === "infrastructure-capacity" && width <= 650) {
          const legend = page.locator(".operating-envelope-card .chart-legend");
          const labels = await legend.locator("li:not([data-collapsed]) .chart-legend-button > span:last-child").evaluateAll(items =>
            items.map(item => ({ height: item.getBoundingClientRect().height, lineHeight: parseFloat(getComputedStyle(item).lineHeight) })));
          assert.ok(labels.length > 0);
          assert.ok(labels.every(label => label.height <= label.lineHeight + 1), "Regional labels wrap as legend items, not single-character columns");
          assert.ok(await page.getByRole("button", { name: "Show all 7 categories", exact: true }).isVisible());
        }
        if (example === "acme-workflow") {
          const navigator = page.getByRole("navigation", { name: "Dashboard sections", includeHidden: true });
          await page.waitForFunction(() => {
            const nav = document.querySelector(".section-navigator"), content = nav.parentElement;
            const left = content.getBoundingClientRect().left + (parseFloat(getComputedStyle(content).paddingLeft) || 0);
            return nav.dataset.fitsGutter === String(left >= 12 + nav.offsetWidth + 16);
          });
          assert.equal(await navigator.isVisible(), frame.viewport >= 1600, "Persistent navigator fits outside content from 1600px of usable width");
          if (await navigator.isVisible()) {
            await navigator.locator("button").hover();
            const menu = navigator.locator(".section-navigator-menu");
            await menu.waitFor({state:"visible"});
            const right = (await navigator.boundingBox()).x + (await navigator.boundingBox()).width;
            const contentLeft = await navigator.evaluate(nav => nav.parentElement.getBoundingClientRect().left + (parseFloat(getComputedStyle(nav.parentElement).paddingLeft) || 0));
            assert.ok(right + 16 <= contentLeft, "Persistent navigation must not overlap content; the open menu is a popover");
            await page.mouse.move(width / 2, 10);
            await menu.waitFor({ state: "hidden" });
          }
          continue;
        }
        if (example !== "fleet-operations") continue;
        // An open modal menu hides its trigger from the accessibility tree.
        // Retain the trigger locator while verifying its expanded state.
        const trigger = page.getByRole("button", { name: "Day", exact: true, includeHidden: true });
        await trigger.scrollIntoViewIfNeeded();
        const targets = await trigger.evaluate(button => [".filter-label", ".select-value", ".chevron", null].map(selector => {
          const box = (selector ? button.querySelector(selector) : button).getBoundingClientRect();
          const x = box.left + box.width / 2, y = selector ? box.top + box.height / 2 : box.bottom - 3;
          const hit = document.elementFromPoint(x, y);
          return { selector: selector ?? "bottom padding", x, y, belongsToTrigger: button.contains(hit),
            interceptedBy: hit?.className };
        }));
        for (const target of targets) {
          assert.ok(target.belongsToTrigger, `${width}px ${target.selector} covered by ${target.interceptedBy}`);
          await page.mouse.click(target.x, target.y);
          assert.equal(await trigger.getAttribute("aria-expanded"), "true", `Day opens from ${target.selector}`);
          await page.keyboard.press("Escape");
        }
        await trigger.click();
        const option = page.getByRole("menuitemradio").first();
        const chosen = (await option.innerText()).trim();
        await option.click();
        assert.ok((await trigger.innerText()).includes(chosen), "Selecting a day updates the shared trigger");
        const geometry = await page.locator(".fleet-dashboard-columns").evaluate(grid => {
          const delivery = grid.querySelector(".deliveries-column"), invoice = grid.querySelector(".invoice-column");
          const bounds = element => { const b = element.getBoundingClientRect(); return { top: b.top, bottom: b.bottom, left: b.left, right: b.right }; };
          return { delivery: bounds(delivery), invoice: bounds(invoice), sections: [...delivery.children].map(bounds),
            horizontalOverflow: document.documentElement.scrollWidth > window.innerWidth + 1 };
        });
        assert.equal(geometry.horizontalOverflow, false, `Fleet page width at ${width}px`);
        for (let index = 1; index < geometry.sections.length; index++)
          assert.ok(geometry.sections[index].top >= geometry.sections[index - 1].bottom - 1, `Fleet sections overlap at ${width}px`);
        assert.ok(width <= 1180 ? geometry.invoice.top >= geometry.delivery.bottom - 1
          : geometry.invoice.left >= geometry.delivery.right - 1, `Fleet panels overlap at ${width}px`);
      }
      if (example === "fleet-operations") {
        const tracks = await page.locator('.cost-comparison-bar').evaluateAll(bars => bars.map(bar => bar.getBoundingClientRect().width));
        assert.ok(tracks.length > 1 && tracks.every(width => Math.abs(width - tracks[0]) < 1),
          "Variance captions must not give each cost bar a different numeric scale");
        const route = page.locator('[data-component-id="route-exceptions"]').getByRole("button", { name: /^View invoices for / }).first();
        const customer = (await route.getAttribute("aria-label")).replace("View invoices for ", "");
        await route.click();
        const invoices = page.locator('[data-component-id="invoice-workspace"]');
        assert.equal(await invoices.getByRole("textbox", {name:"Search data",exact:true}).inputValue(), customer);
        assert.ok((await invoices.locator("tbody tr").allTextContents()).every(text => text.includes(customer)));
        await invoices.getByRole("textbox", {name:"Search data",exact:true}).fill("");
      }
      if (example === "finance") {
        assert.equal(await page.getByRole("complementary", {name:"Watchlist",exact:true}).count(), 1);
        const newsStocks = [
          ["COST", "Costco"], ["WM", "Waste Management"], ["GRMN", "Garmin"],
          ["AZO", "AutoZone"], ["FDX", "FedEx"],
          ["CTAS", "Cintas"], ["MKC", "McCormick"], ["FAST", "Fastenal"],
        ];
        for (const [ticker, company] of newsStocks) {
          await page.getByRole("button", {name: new RegExp(`^${ticker} ${company} `)}).click();
          assert.equal(await page.locator('.finance-security-title strong').innerText(), company);
          const links = await page.locator('.finance-story-list a').evaluateAll(items => items.map(item => item.href));
          assert.ok(links.length >= 4 && new Set(links).size === links.length, `${ticker} has four distinct sourced cards`);
        }
        await page.getByRole("button", {name:/^COST Costco /}).click();
        const analystGeometry = await page.locator('.finance-analyst-card').evaluate(card => {
          const content = card.querySelector('.finance-consensus-renderer').getBoundingClientRect();
          return { bottomGap: card.getBoundingClientRect().bottom - content.bottom,
            padding: parseFloat(getComputedStyle(card).paddingBottom) };
        });
        assert.ok(analystGeometry.bottomGap <= analystGeometry.padding + 2,
          "Supporting chart cards keep their intrinsic height, including beside a taller trade card");
        const notes = page.locator('.finance-story-list a');
        const surfaces = await page.locator('[data-component-id="finance-market-overview"], .finance-news-card').evaluateAll(cards =>
          cards.map(card => ({ background: getComputedStyle(card).getPropertyValue('--card-surface'),
            radius: getComputedStyle(card).borderRadius, smooth: Boolean(card.querySelector('.smooth-card-surface')) })));
        assert.ok(surfaces.length > 1 && surfaces.every(surface => surface.smooth));
        assert.ok(surfaces.every(surface => surface.background === surfaces[0].background && surface.radius === surfaces[0].radius),
          "News uses the same shared card surface as Market overview in every theme");
        const original = await notes.allTextContents();
        await page.getByRole("button", {name:"1M",exact:true}).click();
        const visible = await notes.allTextContents();
        assert.ok(visible.length > 0);
        assert.deepEqual(visible, original, "Real news retains publication dates independently of the synthetic price window");
        assert.ok((await notes.evaluateAll(links => links.map(link => link.href))).every(url => url.startsWith("https://")));
        await page.getByRole("button", {name:/^GRMN Garmin /}).click();
        assert.ok((await notes.allTextContents()).every(text => text.includes("Garmin")), "Company selection scopes the sourced news");
        await page.getByRole("button", {name:/^COST Costco /}).click();
        assert.ok(!(await page.locator('.finance-market-metrics').innerText()).includes("P/E"));
        await page.getByRole("button", {name:"1Y",exact:true}).click();
        await page.getByRole("button", {name:/^AZO AutoZone /}).click();
        await page.getByRole("spinbutton", {name:"Shares",exact:true}).fill("100");
        for (const theme of ["Classic", "Neutral", "Dark pixel", "Scientific blue", "Sticker pop"]) {
          await page.getByRole("button", {name:"More",exact:true}).click();
          await page.getByRole("menuitem", {name:"Switch theme",exact:true}).click();
          await page.getByRole("button", {name:`Apply ${theme}`,exact:true}).click();
          for (const width of [390, 768, 1024, 1200, 1440]) {
            await page.setViewportSize({width, height:900});
            // Let responsive SVG observers consume the new CSS grid dimensions.
            await page.evaluate(() => new Promise(resolve => requestAnimationFrame(() => requestAnimationFrame(resolve))));
            const planner = await page.locator('.finance-planner-card').evaluate(card => {
              const bounds = card.getBoundingClientRect();
              const content = [...card.querySelectorAll('.finance-order-side, .finance-share-input, .finance-outlook-slider, .finance-outlook-chart, .finance-outlook-values strong')];
              const values = [...card.querySelectorAll('.finance-outlook-values strong')].map(item => item.getBoundingClientRect());
              return { contained: content.every(item => {
                const box = item.getBoundingClientRect();
                return box.left >= bounds.left - 1 && box.right <= bounds.right + 1;
              }), overflow: card.scrollWidth > card.clientWidth + 1,
              valuesOverlap: values.length === 2 && values[0].right > values[1].left && values[0].bottom > values[1].top };
            });
            assert.deepEqual(planner, {contained:true, overflow:false, valuesOverlap:false},
              `${theme}/${width}: large scenario values must not enlarge the card's grid track`);
          }
        }
      }
      if (example === "infrastructure-capacity") {
        const densePlot = page.locator('#regional-pool-load-plot .recharts-wrapper');
        await densePlot.scrollIntoViewIfNeeded();
        const plotBounds = await densePlot.boundingBox();
        for (const x of [.4, .5, .6]) {
          await densePlot.hover({position: {x:plotBounds.width*x,y:80}});
          await page.waitForFunction(() => {
            const tip = document.querySelector('#regional-pool-load-plot .chart-tooltip');
            const bounds = tip?.getBoundingClientRect();
            return bounds?.width > 0 && bounds.top >= 0 && bounds.bottom <= innerHeight;
          });
          assert.equal(await densePlot.locator('.chart-tooltip > span').count(), 18);
        }
        const micro = page.locator('[data-component-id="available-trend"] .recharts-wrapper');
        await micro.scrollIntoViewIfNeeded();
        await micro.hover();
        assert.equal(await micro.locator('.chart-tooltip > span').evaluate(row => {
          const text = [...row.childNodes].find(node => node.nodeType === Node.TEXT_NODE && node.textContent.includes('Available'));
          const range = document.createRange(); range.selectNodeContents(text);
          return range.getClientRects().length;
        }), 1, "Short metric names must not split into fragments inside small-chart tooltips");
        await page.getByRole('button', {name:/^Queue recovery:/}).hover();
        assert.equal(await page.locator('.chart-mark-tooltip').count(), 0, "Recovery does not repeat an already visible percentage");
        const pool = page.getByRole("button", {name:"Accelerator pool",exact:true});
        await pool.click();
        await page.getByRole("menuitemradio", {name:"H100",exact:true}).click();
        assert.equal(await pool.evaluate(element => getComputedStyle(element).outlineStyle), "none",
          "Pointer menu selection restores focus without a keyboard ring");
        await page.keyboard.press("Tab");
        await page.keyboard.press("Shift+Tab");
        assert.equal(await pool.evaluate(element => getComputedStyle(element).outlineStyle), "solid",
          "Keyboard navigation retains a visible focus ring");
        await pool.click();
        await page.getByRole("menuitemradio", {name:"All",exact:true}).click();
        assert.equal(await pool.evaluate(element => getComputedStyle(element).outlineStyle), "none",
          "Returning to pointer input clears keyboard-only decoration");
        await page.getByRole("button", {name:"Inspect Japan H200",exact:true}).click();
        assert.match(await page.locator('.filter-trigger[aria-label="Region"]').innerText(), /Japan/);
        assert.match(await page.getByRole("button", {name:"Accelerator pool",exact:true}).innerText(), /H200/);
        await page.getByRole("button", {name:"Clear all",exact:true}).click();
        await page.getByRole("button", { name: "Regional operating envelope actions", exact: true }).click();
        await page.getByRole("menuitem", { name: "Edit chart", exact: true }).click();
        const editor = page.getByRole("dialog", { name: "Regional operating envelope", exact: true });
        await editor.locator('.explorer-chart[data-ready="true"]').waitFor();
        const strokes = await editor.locator(".recharts-line-curve").evaluateAll(paths => paths.map(path => getComputedStyle(path).stroke));
        assert.equal(strokes.length, 7);
        assert.ok(strokes.every(stroke => stroke !== "none" && stroke !== "rgba(0, 0, 0, 0)"),
          "Portaled previews inherit the chart's authored color tokens");
        assert.equal(await editor.locator(".dialog-header").evaluate(header => getComputedStyle(header).outlineStyle), "none",
          "Initial dialog focus must not outline the entire header");
        await editor.getByRole("button", { name: "Cancel", exact: true }).click();
      }
      assert.deepEqual(errors, [], `${example} has no browser errors`);
      await page.close();
    }
  } finally { rmSync(directory, { recursive: true, force: true }); }
}
const project = mkdtempSync(join(tmpdir(), "data-custom-layout-smoke-"));
cpSync(template, project, {
  recursive: true,
  filter: (path) => !path.includes("/node_modules") && !path.includes("/dist"),
});
writeFileSync(join(project, "src/content/dashboard/DashboardContent.jsx"), `
import React, { useState } from "react";

import { ChartRenderer, DataComponent, MetricCard, useDataApp } from "../../data-app-public.jsx";
import { SortableDashboardLayout } from "../shared/SortableDashboardLayout.jsx";

function Chart({ id, title, className }) {
  const { reviewedRows, chartProps } = useDataApp();
  const rows = reviewedRows("usage_summary");
  const chart = { type: "line", x: "week", y: "activeUsers" };
  return <DataComponent id={id} title={title} description={"Reviewed source-backed explanation for " + title + "."}
    queryId="usage_summary" kind="chart"
    chart={chart} sourceRows={rows} displayRows={rows} className={
      ["custom-layout-card", className].filter(Boolean).join(" ")
    }>
    <ChartRenderer spec={chart} rows={rows} height={180} {...chartProps(id)} />
  </DataComponent>;
}

export function DashboardContent() {
  const [showEarlierSection, setShowEarlierSection] = useState(false);
  return <article className="page custom-layout-page">
    <button type="button" onClick={() => setShowEarlierSection((current) => !current)}>
      Toggle earlier section
    </button>
    <SortableDashboardLayout scope="custom-smoke">
      {showEarlierSection && <section><p>Conditionally available earlier section</p></section>}
      <section className="custom-metrics" aria-label="Key metrics">
        <MetricCard id="metric-one" title="First metric" description="Reviewed explanation for the first metric."
          queryId="usage_summary" value="20" />
        <MetricCard id="metric-two" title="Second metric" description="Reviewed explanation for the second metric."
          queryId="usage_summary" value="30" />
        <MetricCard id="metric-three" title="Long reviewed cohort percentile across every selected product"
          description="Reviewed explanation for the third metric."
          queryId="usage_summary" value="40" />
      </section>
      <section id="reviewed-trend-grid" className="custom-chart-grid" aria-label="Reviewed trends">
        <Chart id="wide-trend" kind="chart" title="Wide trend" className="editorial-featured-column" />
        <Chart id="narrow-trend" kind="chart" title="Narrow trend" className="editorial-support-column" />
        <Chart id="left-trend" kind="chart" title="Left trend" className="chart-span-6" />
        <Chart id="right-trend" kind="chart" title="Right trend" className="chart-span-6" />
        <Chart id="full-trend" kind="chart" title="Full trend" className="chart-span-12" />
      </section>
      <section className="bespoke-chart-grid" aria-label="Bespoke visualizations">
        <Chart id="bespoke-one" kind="chart" title="Bespoke one" />
        <Chart id="bespoke-two" kind="chart" title="Bespoke two" />
      </section>
      <section className="visually-ordered-chart-grid" aria-label="Explicitly positioned visualizations">
        <Chart id="dom-first-visually-right" kind="chart" title="Visually right" className="authored-right-position" />
        <Chart id="dom-second-visually-left" kind="chart" title="Visually left" className="authored-left-position" />
      </section>
    </SortableDashboardLayout>
  </article>;
}
`);
writeFileSync(join(project, "src/content/dashboard/dashboard.css"), `
.custom-layout-page { display: grid; gap: 20px; padding: 24px; }
.custom-metrics { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 12px; }
.custom-metrics .data-metric-card { min-height: 104px; gap: 11px; padding: 16px 18px;
  background: color-mix(in srgb, var(--chart-1) 8%, var(--surface)); }
.custom-metrics .component-title { overflow: hidden; font-size: 13px; font-weight: 450; }
.custom-metrics .data-metric-value { font-size: 35px; font-weight: 650; letter-spacing: -1px; }
.custom-chart-grid { display: grid; grid-template-columns: repeat(12, minmax(0, 1fr)); gap: 14px; }
.custom-chart-grid .component-title { font-size: 15px; font-weight: 610; letter-spacing: -.6px; }
.bespoke-chart-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr));
  grid-template-areas: "featured side"; gap: 14px; }
.visually-ordered-chart-grid { display: grid; grid-template-columns: repeat(12, minmax(0, 1fr)); gap: 14px; }
.authored-right-position { grid-column: 7 / span 6; grid-row: 1; }
.authored-left-position { grid-column: 1 / span 6; grid-row: 1; }
.chart-span-8 { grid-column: span 8; }
.editorial-featured-column { grid-column: span 8; }
.editorial-support-column { grid-column: span 4; }
.chart-span-6 { grid-column: span 6; }
.chart-span-4 { grid-column: span 4; }
.chart-span-12 { grid-column: 1 / -1; }
.custom-layout-card { min-width: 0; padding: 14px; overflow: hidden; border: 1px solid var(--border); }
@media (max-width: 650px) {
  .custom-metrics, .custom-chart-grid, .bespoke-chart-grid { grid-template-columns: minmax(0, 1fr); }
  .chart-span-8, .chart-span-6, .chart-span-4, .chart-span-12,
  .editorial-featured-column, .editorial-support-column { grid-column: 1; }
}
`);

// Deliberately omit both example stylesheets: ordinary public components must
// carry their own presentation and data scope on either application surface.
async function assertDropdownInteractions(page) {
  const scope = page.getByRole("region", { name: "Dropdown behavior", exact: true });
  const values = async () => JSON.parse(await page.getByTestId("dropdown-values").textContent());
  const menu = scope.getByRole("button", { name: "Menu metric", exact: true });
  assert.match(await menu.innerText(), /Active users/u);
  await menu.locator(".filter-label").click();
  assert.equal(await page.getByRole("menu").getByText("Business", { exact: true }).isVisible(), true);
  await page.getByRole("menuitemradio", { name: "Retention rate", exact: true }).click();
  assert.equal((await values()).single, "retention");
  assert.equal(await page.getByRole("menu").count(), 0, "Scalar selection closes the menu");
  assert.match(await menu.innerText(), /Retention rate/u);

  const search = scope.getByRole("combobox", { name: "Search metric", exact: true });
  assert.equal(await search.inputValue(), "Active users");
  await search.fill("retention rate");
  const options = page.getByRole("listbox", { name: "Search metric", exact: true });
  assert.deepEqual(await options.getByRole("option").allTextContents(), ["Retention rate"]);
  await search.press("Enter");
  assert.equal((await values()).searched, "retention", "Keyboard search emits the raw reviewed choice");
  assert.equal(await search.inputValue(), "Retention rate");
  assert.equal(await search.getAttribute("aria-expanded"), "false");

  await scope.getByRole("button", { name: "Menu metrics", exact: true }).click();
  const retained = page.getByRole("menuitemcheckbox", { name: "Retention rate", exact: true });
  await retained.click();
  assert.equal(await retained.getAttribute("aria-checked"), "true");
  assert.deepEqual((await values()).multiple, ["retention"]);
  await page.getByRole("menuitemcheckbox", { name: "Revenue", exact: true }).click();
  assert.deepEqual((await values()).multiple, ["retention", "revenue"]);
  await retained.click();
  assert.deepEqual((await values()).multiple, ["revenue"]);
  await page.getByRole("menuitemcheckbox", { name: "All metrics", exact: true }).click();
  assert.deepEqual((await values()).multiple, []);
  await page.keyboard.press("Escape");

  const multi = scope.getByRole("combobox", { name: "Search metrics", exact: true });
  await multi.fill("active users");
  await multi.press("Enter");
  assert.deepEqual((await values()).searchedMultiple, ["active_users"]);
  assert.equal(await multi.getAttribute("aria-expanded"), "true", "Multiple selection keeps the menu open");
  const multiOptions = page.getByRole("listbox", { name: "Search metrics", exact: true });
  assert.equal(await multiOptions.getAttribute("aria-multiselectable"), "true");
  assert.equal(await multiOptions.getByRole("option", { name: "Active users", exact: true }).getAttribute("aria-selected"), "true");
  await multi.fill("revenue");
  await multi.press("Enter");
  assert.deepEqual((await values()).searchedMultiple, ["active_users", "revenue"]);
  await multiOptions.getByRole("option", { name: "Active users", exact: true }).click();
  assert.deepEqual((await values()).searchedMultiple, ["revenue"]);
  await multiOptions.getByRole("option", { name: "All metrics", exact: true }).click();
  assert.deepEqual((await values()).searchedMultiple, []);
  const visibleOption = multiOptions.getByRole("option", { name: "Revenue", exact: true });
  assert.equal(await visibleOption.evaluate(element => {
    const bounds = element.getBoundingClientRect();
    const hit = document.elementFromPoint(bounds.left + bounds.width / 2, bounds.top + bounds.height / 2);
    return element.contains(hit);
  }), true, "Options extending below the sticky filter bar remain clickable");
  await multi.press("Escape");
  assert.equal(await multi.inputValue(), "All metrics");
}

async function assertChartInteractions(page) {
  const scope = page.getByRole("region", { name: "Chart interaction regressions", exact: true });
  for (const id of ["hidden-date-line", "hidden-date-bar"]) {
    const chart = page.locator(`[data-component-id="${id}"]`);
    await chart.locator(".recharts-surface").waitFor({ state: "visible" });
    assert.equal(await chart.locator("[data-temporal-axis-tick]").count(), 0,
      `${id}: hiding date ticks must remove painted labels`);
    assert.ok(await chart.locator(".recharts-line-curve,.recharts-bar-rectangle").count() > 0,
      "Hiding the category labels must retain the chart marks");
  }
  await scope.getByRole("button", { name: "Show date labels", exact: true }).click();
  await page.waitForFunction(() => ["hidden-date-line", "hidden-date-bar"].every(id =>
    document.querySelector(`[data-component-id="${id}"] [data-temporal-axis-tick]`)));
  await scope.getByRole("button", { name: "Hide date labels", exact: true }).click();
  assert.equal(await scope.locator("[data-temporal-axis-tick]").count(), 0);

  const heatmap = page.locator('[data-component-id="heatmap-gaps"]');
  const cells = heatmap.locator("[data-heatmap-cell]");
  await cells.first().waitFor({ state: "visible" });
  assert.equal(await cells.count(), 4);
  const unknown = cells.filter({ hasText: "—" });
  assert.equal(await unknown.count(), 2, "Both null observations and absent combinations stay unobserved");
  for (const cell of await unknown.all()) {
    assert.equal(await cell.getAttribute("role"), null);
    assert.equal(await cell.getAttribute("tabindex"), null);
    await cell.locator(".chart-heatmap-cell").click();
    assert.equal(await page.getByRole("dialog", { name: "Selected chart data", exact: true }).count(), 0,
      "Clicking unobserved evidence must not open mark actions");
  }
  const observed = heatmap.locator(".chart-explore-mark");
  assert.equal(await observed.count(), 2);
  assert.equal(await observed.first().getAttribute("tabindex"), "0",
    "Keyboard entry starts at the first observed cell even when the first matrix cell is missing");
  await observed.first().focus();
  await observed.first().press("Enter");
  await page.getByRole("button", { name: "View cohort records", exact: true }).click();
  assert.equal(await page.getByTestId("selected-cohort").textContent(), "B / Week 1",
    "An observed zero remains actionable by keyboard");
  await observed.last().locator(".chart-heatmap-cell").click();
  await page.getByRole("button", { name: "View cohort records", exact: true }).click();
  assert.equal(await page.getByTestId("selected-cohort").textContent(), "A / Week 2",
    "Pointer activation selects the same reviewed row as keyboard activation");
}

async function assertIndependentComponents(browser) {
  const independent = mkdtempSync(join(tmpdir(), "data-independent-components-"));
  try {
    cpSync(template, independent, {
      recursive: true,
      filter: (path) => !path.includes("/node_modules") && !path.includes("/dist"),
    });
    for (const surface of ["dashboard", "report"]) {
      writeFileSync(join(independent, `src/content/${surface}/${surface}.css`), "");
      writeFileSync(join(independent, `src/content/${surface}/${surface === "dashboard" ? "Dashboard" : "Report"}Content.jsx`),
        `export { IndependentContent as ${surface === "dashboard" ? "Dashboard" : "Report"}Content } from "../shared/IndependentContent.jsx";\n`);
    }
    writeFileSync(join(independent, "src/content/shared/IndependentContent.jsx"), `
import React from "react";
import { ChartRenderer, DataComponent, DataTable, Dropdown, Filters, MetricCard, Section, SectionHeader,
  SortableItem, SortableRegion, useDataApp, useSectionFilters } from "../../data-app-public.jsx";

const queryId = "usage_summary";
const definitions = [
  { id: "segment", field: "segment", label: "Local product", defaultValue: "all", queryIds: [queryId] },
  { id: "region", field: "region", label: "Local geography", defaultValue: "all", queryIds: [queryId] },
];
const chart = { type: "line", x: "week", y: "activeUsers" };
const tableColumns = [
  { field: "account", label: "Account", presentation: "identity", secondaryField: "region" },
  { field: "activeUsers", label: "Active users" },
  { field: "retention", label: "Retention", presentation: "percent" },
  { field: "usageTrend", label: "Usage trend", presentation: "sparkline" },
  { field: "engagementScore", label: "Engagement", presentation: "bar", max: 100 },
  { field: "riskTier", label: "Risk", presentation: "status" },
];

function ScopedSection({ id, title }) {
  const { chartOverrides, chartProps } = useDataApp();
  const scoped = useSectionFilters(definitions);
  const rows = scoped.reviewedRows(queryId);
  const chartId = id + "-chart";
  const spec = chartOverrides[chartId] ?? { type: "bar", x: "segment", y: "activeUsers" };
  const breakdown = [spec.x, spec.series].filter(Boolean);
  return <Section id={id} title={title} columns={1} spacing="content"
    filters={<Filters {...scoped.filterProps} ariaLabel={title + " filters"} />}>
    <DataComponent id={id + "-value"} title={title + " value"} queryId={queryId}
      kind="metric" variant="card" {...scoped.componentProps(queryId)}>
      <output data-testid={id + "-rows"} data-rows={JSON.stringify(rows)} data-reviewed-value>
        {rows.map((row) => row.activeUsers).join(", ") || "No matching rows"}
      </output>
    </DataComponent>
    <DataComponent id={chartId} title={title + " chart"} queryId={queryId} kind="chart" chart={spec}
      {...scoped.componentProps(queryId, breakdown)}>
      <ChartRenderer spec={spec} rows={scoped.reviewedRows(queryId, breakdown)} height={120} {...chartProps(chartId)} />
    </DataComponent>
  </Section>;
}

function DropdownControls() {
  const [single, setSingle] = React.useState("active_users");
  const [searched, setSearched] = React.useState("active_users");
  const [multiple, setMultiple] = React.useState([]);
  const [searchedMultiple, setSearchedMultiple] = React.useState([]);
  const labels = { active_users: "Active users", retention: "Retention rate", revenue: "Revenue" };
  const choices = ["all", ...Object.keys(labels)];
  const groups = [{ label: "Usage", choices: choices.slice(0, 3) }, { label: "Business", choices: ["revenue"] }];
  const props = { choices, groups, formatChoice: choice => labels[choice], allLabel: "All metrics", showLabel: true };
  return <Filters sticky ariaLabel="Dropdown behavior" queries={{}} values={{}}>
    <Dropdown {...props} label="Menu metric" value={single} onChange={setSingle} />
    <Dropdown {...props} label="Search metric" searchable value={searched} onChange={setSearched} />
    <Dropdown {...props} label="Menu metrics" multiple value={multiple} onChange={setMultiple} />
    <Dropdown {...props} label="Search metrics" searchable multiple value={searchedMultiple} onChange={setSearchedMultiple} />
    <output hidden data-testid="dropdown-values" data-reviewed-value>{JSON.stringify({ single, searched, multiple, searchedMultiple })}</output>
  </Filters>;
}

function ChartRegressionControls() {
  const { queries } = useDataApp();
  const [showDates, setShowDates] = React.useState(false);
  const [selectedCohort, setSelectedCohort] = React.useState("");
  const dates = queries.interaction_dates.rows;
  const cohortRows = queries.interaction_cohorts.rows;
  const heatmap = { type: "heatmap", x: "age", y: "retentionRate", series: "cohort",
    missingValues: "gap", showValues: true, categoryOrder: ["Week 1", "Week 2"], seriesOrder: ["A", "B"] };
  return <section aria-label="Chart interaction regressions">
    <button type="button" onClick={() => setShowDates(value => !value)}>{showDates ? "Hide date labels" : "Show date labels"}</button>
    {["line", "bar"].map(type => {
      const id = "hidden-date-" + type;
      const spec = { type, x: "week", y: "activeUsers", showCategoryTicks: showDates, showLegend: false };
      return <DataComponent key={id} id={id} title={type + " date labels"} kind="chart" queryId="interaction_dates"
        chart={spec} sourceRows={dates} displayRows={dates}>
        <ChartRenderer spec={spec} rows={dates} height={180} />
      </DataComponent>;
    })}
    <DataComponent id="heatmap-gaps" title="Observed cohort evidence" kind="chart" queryId="interaction_cohorts"
      chart={heatmap} sourceRows={cohortRows} displayRows={cohortRows}>
      <ChartRenderer spec={heatmap} rows={cohortRows} height={220}
        getMarkActions={({ row }) => [{ label: "View cohort records",
          onSelect: () => setSelectedCohort(row.cohort + " / " + row.age) }]} />
    </DataComponent>
    <output data-testid="selected-cohort" data-reviewed-value>{selectedCohort}</output>
  </section>;
}

function DateSection() {
  const scoped = useSectionFilters([{ id: "week", field: "week", label: "Local dates", mode: "through",
    defaultValue: "all", queryIds: [queryId] }], { week: "2026-07-27" });
  return <Section id="local-dates" title="Dated evidence" spacing="content"
    filters={<Filters {...scoped.filterProps} ariaLabel="Local date filters" />}>
    <output data-testid="local-date-value" data-reviewed-value>{scoped.values.week}</output>
  </Section>;
}

export function IndependentContent() {
  const { snapshot, queries, filters, setFilter, reviewedRows, chartProps } = useDataApp();
  const rows = reviewedRows(queryId);
  return <article aria-label="Independent public components">
    {snapshot.surface === "report" && <DataComponent id="report-executive-summary"
      title="Executive summary" queryId={queryId} kind="custom"><p>Reviewed component test fixture.</p></DataComponent>}
    <Filters filters={snapshot.filters} queries={queries} values={filters} onChange={setFilter}
      ariaLabel="Page filters" clearLabel="Clear page" />
    <SectionHeader id="standalone-heading" title="Independent heading" />
    <DropdownControls />
    <ChartRegressionControls />
    <Section id="cards" title="Card geometry" columns={2}>
      <DataComponent id="standard-card" title="Standard card" queryId={queryId} kind="custom" variant="card">
        <p data-reviewed-value>Standard padding</p>
      </DataComponent>
      <DataComponent id="spacious-card" title="Spacious card" queryId={queryId} kind="custom" variant="card" padding="spacious">
        <p data-reviewed-value>Spacious padding</p>
      </DataComponent>
    </Section>
    <Section id="metrics" title="Independent metrics" columns={2} kind="metrics" spacing="metrics">
      <MetricCard id="standalone-metric" title="Standalone metric" queryId={queryId} value="100" />
      <DataComponent id="plain-metric" title="Plain metric" queryId={queryId} kind="metric">
        <p data-reviewed-value>100</p>
      </DataComponent>
    </Section>
    <Section id="plain-chart-section" title="Plain evidence" spacing="after-metrics">
      <DataComponent id="plain-chart" title="Plain chart" queryId={queryId} kind="chart" chart={chart}>
        <ChartRenderer spec={chart} rows={rows} height={120} {...chartProps("plain-chart")} />
      </DataComponent>
    </Section>
    <ScopedSection id="local-a" title="First section" />
    <ScopedSection id="local-b" title="Second section" />
    <DataComponent id="shared-funnel" title="Conversion funnel" queryId="funnel" kind="chart"
      variant="card" chart={{ type: "funnel", x: "stage", y: "count" }}
      sourceRows={queries.funnel.rows} displayRows={queries.funnel.rows}>
      <ChartRenderer spec={{ type: "funnel", x: "stage", y: "count" }} rows={queries.funnel.rows}
        height={240} {...chartProps("shared-funnel")} />
    </DataComponent>
    <DataComponent id="funnel-gaps" title="Missing-stage funnel" queryId="funnel_quality" kind="chart"
      chart={{ type: "funnel", x: "stage", y: "count" }}>
      <ChartRenderer spec={{ type: "funnel", x: "stage", y: "count", colors: { A: "red", B: "green", C: "blue" } }}
        rows={queries.funnel_quality.rows} height={180} />
    </DataComponent>
    <DataComponent id="funnel-ratios" title="Ratio funnel" queryId="funnel_quality" kind="chart"
      chart={{ type: "funnel", x: "stage", y: "conversionRate" }}>
      <ChartRenderer spec={{ type: "funnel", x: "stage", y: "conversionRate" }}
        rows={queries.funnel_quality.rows} height={180} />
    </DataComponent>
    <DataComponent id="funnel-repeated" title="Repeated-stage funnel" queryId="funnel_repeated" kind="chart"
      chart={{ type: "funnel", x: "stage", y: "count" }} sourceRows={queries.funnel_repeated.rows}>
      <ChartRenderer spec={{ type: "funnel", x: "stage", y: "count" }}
        rows={queries.funnel_repeated.rows} height={240} {...chartProps("funnel-repeated")} />
    </DataComponent>
    <DateSection />
    <Section id="rich-table-section" title="Independent rich table" spacing="content">
      <DataComponent id="rich-table" title="Reviewed accounts" queryId="rich_table" kind="table">
        <DataTable rows={reviewedRows("rich_table")} columns={tableColumns} searchable={false} />
      </DataComponent>
    </Section>
    <Section id="no-spacing" title="No extra spacing" spacing="none"
      filters={<Filters filters={[]} />}><p>Fixed composition.</p></Section>
    <Section id="continuation-spacing" title="Continued evidence" spacing="continuation">
      <div>Reviewed continuation content.</div>
    </Section>
    {snapshot.surface === "dashboard" && <SortableRegion id="independent:canvas" label="Independent canvas"
      variant="canvas" spacing="standard" columns={12} rows={[
        { id: "canvas-metrics", items: ["canvas-one", "canvas-two"], kind: "metrics", spacing: "metrics",
          header: <SectionHeader id="canvas-heading" title="Canvas metrics" filters={<Filters filters={[]} />} /> },
        { id: "canvas-content", items: ["canvas-three"], spacing: "after-metrics" },
        { id: "canvas-continuation", items: ["canvas-four"], spacing: "continuation" },
      ]}>
      <SortableItem id="canvas-one" kind="metric" span={6}><MetricCard id="canvas-one" title="Canvas one" queryId={queryId} value="40" /></SortableItem>
      <SortableItem id="canvas-two" kind="metric" span={6}><MetricCard id="canvas-two" title="Canvas two" queryId={queryId} value="60" /></SortableItem>
      <SortableItem id="canvas-three" kind="custom" span={12}><DataComponent id="canvas-three" title="Canvas content"
        queryId={queryId} kind="custom" variant="card"><p>Reviewed canvas content.</p></DataComponent></SortableItem>
      <SortableItem id="canvas-four" kind="custom" span={12}><DataComponent id="canvas-four" title="Continued canvas content"
        queryId={queryId} kind="custom" variant="card"><p>Reviewed continuation content.</p></DataComponent></SortableItem>
    </SortableRegion>}
  </article>;
}
`);
    const snapshot = JSON.parse(readFileSync(join(template, "src/data.json"), "utf8"));
    snapshot.filters = [{ id: "segment", field: "segment", label: "Page product", defaultValue: "all" }];
    snapshot.queries = { funnel_quality: { source: snapshot.queries.usage_summary.source, rows: [
      { stage: "A", count: 100, conversionRate: 1 }, { stage: "B", count: null, conversionRate: .6 },
      { stage: "C", count: 25, conversionRate: .312345 },
    ] }, funnel: { source: snapshot.queries.usage_summary.source, rows: [
      { stage: "Visited", count: 100000 }, { stage: "Signed up", count: 75000 },
      { stage: "Started", count: 60000 }, { stage: "Invited", count: 45000 },
      { stage: "Shared", count: 30000 }, { stage: "Returned", count: 20000 },
      { stage: "Purchased", count: 12000 }, { stage: "Activated", count: 6000 },
    ] }, rich_table: { source: snapshot.queries.account_health.source, rows: [
      { account: "Alpha", region: "North America", activeUsers: 1234, retention: .92,
        usageTrend: [2, 4, 8], engagementScore: 75, riskTier: "High risk" },
      { account: "Beta", region: "EMEA", activeUsers: 840, retention: .75,
        usageTrend: [9, 6, 3], engagementScore: 90, riskTier: "Moderate" },
      { account: "Gamma", region: "APAC", activeUsers: 320, retention: .6,
        usageTrend: [3, 5, 7], engagementScore: 30, riskTier: "Low risk" },
      ...[0, null, "", "unknown"].map((engagementScore, index) => ({
        account: `Incomplete ${index}`, engagementScore,
      })),
    ] }, usage_summary: { ...snapshot.queries.usage_summary, source: {
      ...snapshot.queries.usage_summary.source,
      evidenceFlow: [{ title: "Reviewed population", detail: "All products in the captured source." }],
    }, rows: [
      { week: "2026-07-27", segment: "all", region: "all", activeUsers: 100 },
      { week: "2026-07-27", segment: "Studio", region: "North America", activeUsers: 40 },
      { week: "2026-07-27", segment: "Search", region: "EMEA", activeUsers: 60 },
    ] } };

    snapshot.queries.interaction_dates = { source: snapshot.queries.usage_summary.source, rows: [
      { week: "2026-07-27", activeUsers: 10 }, { week: "2026-07-28", activeUsers: 14 },
      { week: "2026-07-29", activeUsers: 12 },
    ] };
    snapshot.queries.interaction_cohorts = { source: snapshot.queries.usage_summary.source, rows: [
      { age: "Week 1", cohort: "A", retentionRate: null },
      { age: "Week 2", cohort: "A", retentionRate: .5 },
      { age: "Week 1", cohort: "B", retentionRate: 0 },
    ] };
    snapshot.queries.funnel_repeated = { ...snapshot.queries.funnel, rows: [
      { stage: "UnbrokenStageName".repeat(6), count: 1e20 }, { stage: null, count: 80 },
      { stage: "UnbrokenStageName".repeat(6), count: 60 }, { stage: "Last", count: 20 },
    ] };
    for (const surface of ["dashboard", "report"]) {
      writeFileSync(join(independent, "src/data.json"), JSON.stringify({ ...snapshot, surface }));
      const build = runDataAppFixtureBuild(independent, { pluginRoot });
      assert.equal(build.status, 0, `${surface} independent build: ${build.stdout}\n${build.stderr}`);
      const page = await browser.newPage({ viewport: { width: 1440, height: 1100 }, hasTouch: true });
      const errors = [];
      page.on("pageerror", (error) => errors.push(error.message));
      await installDashboardBrowserMocks(page);
      await page.goto(pathToFileURL(join(independent, "dist/index.html")).href, { waitUntil: "load" });
      if (surface === "dashboard") {
        for (const [width, top, bottom] of [[1440, 24, 96], [390, 18, 56]]) {
          await page.setViewportSize({ width, height: 1100 });
          await page.locator("main > article").waitFor();
          const edges = await page.locator("main").evaluate((main) => {
            const page = main.getBoundingClientRect();
            const content = main.firstElementChild.getBoundingClientRect();
            return { top: content.top - page.top, bottom: page.bottom - content.bottom };
          });
          assert.deepEqual(edges, { top, bottom },
            `Dashboard page edges must retain breathing room at ${width}px without example CSS`);
        }
        await page.setViewportSize({ width: 1440, height: 1100 });
      }
      if (surface === "dashboard") await assertDropdownInteractions(page);
      await assertChartInteractions(page);
      const component = (id) => page.locator(`[data-component-id="${id}"]`);
      const section = (id) => page.locator(`[data-editable-id="${id}"]`).locator("xpath=ancestor::section[1]");
      const localRows = async (id) => JSON.parse(await page.getByTestId(`${id}-rows`).getAttribute("data-rows"));
      const selectProduct = async (region, label, value, keyboard = false) => {
        const trigger = page.getByRole("region", { name: region, exact: true }).getByRole("button", { name: label, exact: true });
        if (keyboard) {
          // The nonmodal source drawer covers pointer access to the page. Drive
          // the existing controlled filter by keyboard without dismissing it.
          await trigger.focus();
          await trigger.press("Enter");
          const choice = page.getByRole("menuitemradio", { name: value, exact: true });
          await choice.focus();
          await choice.press("Enter");
        } else {
          await trigger.click();
          await page.getByRole("menuitemradio", { name: value, exact: true }).click();
        }
      };
      for (const id of ["standalone-heading", "cards", "metrics", "local-a", "local-b"]) {
        assert.equal(await page.locator(`[data-editable-id="${id}"]`).count(), 1,
          `${surface} section headings expose their authored stable editing identity`);
      }
      assert.equal(await page.locator('[data-editable-id="standalone-heading"]').locator("..").locator(".filters").count(), 0,
        "SectionHeader must support a heading without a filter slot");

      for (const [theme, radius] of [["Classic", 20], ["Neutral", 16], ["Dark pixel", 0], ["Scientific blue", 8], ["Sticker pop", 24]]) {
        if (!(await page.getByRole("region", { name: "Theme picker" }).isVisible())) {
          const menu = page.getByRole("menu", { name: "More", exact: true });
          if (!(await menu.isVisible())) await page.getByRole("button", { name: "More", exact: true }).click();
          await menu.getByRole("menuitem", { name: "Switch theme", exact: true }).click();
        }
        await page.getByRole("button", { name: `Apply ${theme}`, exact: true }).click();
        const controlHeights = await page.locator("main .filter-trigger").evaluateAll((controls) =>
          controls.map((control) => ({ label: control.textContent, height: control.getBoundingClientRect().height }))
            .filter((control) => control.height > 0));
        assert.ok(controlHeights.length > 0, `${surface}/${theme} must render shared filters`);
        for (const control of controlHeights) {
          assert.ok(control.height >= 32 && control.height <= 44,
            `${surface}/${theme}/${control.label} has an unusable control height: ${control.height}`);
        }
        for (const [id, padding] of [["standard-card", [16, 20, 16, 20]], ["spacious-card", [20, 20, 20, 20]],
          ["standalone-metric", [20, 20, 20, 20]]]) {
          const geometry = await component(id).evaluate((element) => {
            const style = getComputedStyle(element);
            return { radius: parseFloat(style.borderTopLeftRadius),
              padding: [style.paddingTop, style.paddingRight, style.paddingBottom, style.paddingLeft].map(parseFloat),
              variant: element.dataset.componentVariant };
          });
          assert.deepEqual(geometry, { radius, padding, variant: "card" },
            `${surface}/${theme}/${id} must retain shared geometry without example styles`);
        }
        for (const id of ["plain-metric", "plain-chart"]) {
          const geometry = await component(id).evaluate((element) => {
            const style = getComputedStyle(element);
            return { padding: style.padding, border: style.borderTopWidth, radius: style.borderTopLeftRadius,
              background: style.backgroundColor, shadow: style.boxShadow, surfaces: element.querySelectorAll(".smooth-card-surface").length };
          });
          assert.deepEqual(geometry, { padding: "0px", border: "0px", radius: "0px",
            background: "rgba(0, 0, 0, 0)", shadow: "none", surfaces: 0 },
          `${surface}/${theme}/${id} must stay unframed`);
        }
      }
      await page.keyboard.press("Escape");
      for (const [id, padding, gap] of [["cards", 40, 20], ["metrics", 16, 12],
        ["plain-chart-section", 32, 20], ["local-a", 20, 20], ["no-spacing", 0, 20],
        ["continuation-spacing", 20, 20]]) {
        const geometry = await section(id).evaluate((element) => {
          const style = getComputedStyle(element);
          return { padding: parseFloat(style.paddingTop), gap: parseFloat(style.columnGap) };
        });
        assert.deepEqual(geometry, { padding, gap }, `${surface}/${id} shared spacing`);
        if (id !== "no-spacing") {
          const headerGap = await section(id).evaluate((element) => {
            const header = element.querySelector(":scope > .data-section-header");
            return header.nextElementSibling.getBoundingClientRect().top - header.getBoundingClientRect().bottom;
          });
          assert.equal(headerGap, 20, `${surface}/${id} visible heading-to-content gap`);
        }
      }
      if (surface === "dashboard") {
        const canvas = await page.locator('[data-sortable-row="canvas-metrics"]').evaluate((element) => {
          const style = getComputedStyle(element);
          const header = element.querySelector(".sortable-row-header");
          return { padding: parseFloat(style.paddingTop), gap: parseFloat(style.columnGap),
            headerGap: element.querySelector(".sortable-item").getBoundingClientRect().top - header.getBoundingClientRect().bottom,
            heading: element.querySelector('[data-editable-id="canvas-heading"]')?.textContent };
        });
        assert.deepEqual(canvas, { padding: 16, gap: 12, headerGap: 20, heading: "Canvas metrics" },
          "Canvas row metadata must use the shared metric spacing and heading presentation");
        const continuationGap = await page.evaluate(() =>
          document.querySelector('[data-component-id="canvas-four"]').getBoundingClientRect().top
          - document.querySelector('[data-component-id="canvas-three"]').getBoundingClientRect().bottom);
        assert.equal(continuationGap, 20, "Continuation cards must have a real 20px edge-to-edge gap");
      }

      const richTable = component("rich-table");
      const accountHeader = richTable.locator("th").first();
      await accountHeader.getByRole("button").click();
      assert.equal(await accountHeader.getAttribute("aria-sort"), "ascending");
      await accountHeader.getByRole("button").click();
      assert.equal(await accountHeader.getAttribute("aria-sort"), "descending");
      assert.match(await richTable.locator("tbody tr").first().innerText(), /Incomplete 3/u);
      await accountHeader.getByRole("button").click();
      assert.match(await richTable.locator("tbody tr").first().innerText(), /Alpha/u);
      const tableRegion = richTable.getByRole("region", { name: "Reviewed data table", exact: true });
      await page.setViewportSize({ width: 390, height: 1100 });
      await page.waitForFunction(() => document.querySelector('[data-component-id="rich-table"] .table-wrap')?.tabIndex === 0);
      assert.equal(await tableRegion.evaluate(element => element.scrollWidth > element.clientWidth), true);
      await page.setViewportSize({ width: 1440, height: 1100 });
      await page.waitForFunction(() => !document.querySelector('[data-component-id="rich-table"] .table-wrap')?.hasAttribute("tabindex"));
      const richGeometry = await richTable.evaluate((element) => {
        const style = (selector) => getComputedStyle(element.querySelector(selector));
        const bounds = (selector) => {
          const { width, height } = element.querySelector(selector).getBoundingClientRect();
          return { width, height };
        };
        const identity = element.querySelector(".table-identity");
        return {
          identity: { display: style(".table-identity").display,
            secondarySize: style(".table-identity > span").fontSize,
            secondaryBelow: identity.lastElementChild.getBoundingClientRect().top
              >= identity.firstElementChild.getBoundingClientRect().bottom },
          percentage: { text: element.querySelector(".table-cell-percent").textContent,
            align: style(".table-cell-percent").textAlign },
          numericAlign: style("td.numeric").textAlign,
          sparkline: bounds(".table-sparkline"),
          trendColors: [...element.querySelectorAll(".table-sparkline")].map((entry) => getComputedStyle(entry).color),
          distribution: bounds(".table-data-bar-track"),
          marker: bounds(".table-distribution-marker"),
          bars: [...element.querySelectorAll(".table-data-bar-track")][0].querySelectorAll(".table-data-bar-segment").length,
          paintedBars: [...element.querySelectorAll(".table-data-bar-segment")].every((bar) => {
            const rect = bar.getBoundingClientRect();
            return rect.width > 0 && rect.height > 0 && getComputedStyle(bar).backgroundColor !== "rgba(0, 0, 0, 0)";
          }),
          statuses: [...element.querySelectorAll(".table-status")].map((entry) => ({
            tone: entry.dataset.status, display: getComputedStyle(entry).display,
            padding: getComputedStyle(entry).padding, size: getComputedStyle(entry).fontSize,
            color: getComputedStyle(entry).color, background: getComputedStyle(entry).backgroundColor,
          })),
        };
      });
      assert.deepEqual(richGeometry.identity, { display: "grid", secondarySize: "12px", secondaryBelow: true },
        `${surface} identity cells must stack their secondary labels without dashboard CSS`);
      assert.deepEqual(richGeometry.percentage, { text: "92%", align: "right" });
      assert.equal(richGeometry.numericAlign, "right");
      assert.deepEqual(richGeometry.sparkline, { width: 112, height: 28 }, `${surface} rich-table sparkline dimensions`);
      assert.notEqual(richGeometry.trendColors[0], richGeometry.trendColors[1],
        "Positive and negative reviewed sparklines must retain distinct theme colors");
      assert.deepEqual(richGeometry.distribution, { width: 112, height: 22 });
      assert.deepEqual(richGeometry.marker, { width: 2, height: 26 });
      assert.equal(richGeometry.bars, 12);
      assert.equal(richGeometry.paintedBars, true, `${surface} distribution cells need actual visible bars`);
      assert.deepEqual(richGeometry.statuses.slice(0, 3).map(({ tone }) => tone), ["negative", "warning", "positive"]);
      assert.equal(new Set(richGeometry.statuses.slice(0, 3).map(({ color }) => color)).size, 3);
      assert.ok(richGeometry.statuses.slice(3).every(({ tone }) => tone === "neutral"),
        "Missing statuses must remain neutral rather than acquire a risk color");
      for (const status of richGeometry.statuses) {
        assert.equal(status.display, "inline-flex");
        assert.equal(status.padding, "2px 8px");
        assert.equal(status.size, "12px");
        assert.notEqual(status.background, "rgba(0, 0, 0, 0)");
      }
      const trendVisual = richTable.locator(".table-cell-sparkline .table-visual-trigger").first();
      await trendVisual.hover({ position: { x: 2, y: 10 } });
      const trendTooltip = page.getByRole("tooltip").filter({ hasText: "Usage trend" });
      assert.equal(await trendTooltip.locator("strong").innerText(), "2");
      await trendVisual.hover({ position: { x: 110, y: 10 } });
      assert.equal(await trendTooltip.locator("strong").innerText(), "8",
        "Rich-table hover must track the reviewed observation");
      await page.mouse.move(0, 0);
      await trendVisual.focus();
      await trendTooltip.waitFor({ state: "visible" });
      assert.equal(await trendTooltip.locator("strong").innerText(), "8",
        "Keyboard focus must expose the latest reviewed sparkline value");
      assert.equal(await trendVisual.getAttribute("aria-describedby"), await trendTooltip.getAttribute("id"));
      assert.equal(await trendTooltip.evaluate((element) => element.parentElement === document.body), true);
      const distributionVisual = richTable.locator(".table-cell-bar .table-visual-trigger").first();
      await distributionVisual.focus();
      const distributionTooltip = page.getByRole("tooltip").filter({ hasText: "Engagement" });
      assert.match(await distributionTooltip.innerText(), /75.*75th percentile/u,
        "Keyboard focus must explain the reviewed engagement score and distribution position");
      const distributionCells = richTable.locator(".table-cell-bar");
      await distributionCells.nth(3).locator(".table-visual-trigger").focus();
      assert.match(await distributionTooltip.innerText(), /0.*25th percentile/u, "Zero is a reviewed score");
      for (const index of [4, 5, 6]) {
        await distributionCells.nth(index).locator(".table-visual-trigger").focus();
        assert.equal(await distributionTooltip.locator("strong").innerText(), "No reviewed value");
        assert.equal(await distributionCells.nth(index).locator(".table-distribution-marker").count(), 0);
      }
      await distributionVisual.evaluate((element) => element.blur());

      assert.deepEqual((await localRows("local-a")).map((row) => row.activeUsers), [100]);
      await selectProduct("First section filters", "Local product", "Studio");
      assert.deepEqual((await localRows("local-a")).map((row) => row.activeUsers), [40],
        "Local exact filtering must retain detail hidden by the page All aggregate");
      assert.deepEqual((await localRows("local-b")).map((row) => row.activeUsers), [100],
        "A local change must not mutate another section with the same filter ID");
      await component("local-a-value").getByRole("button", { name: "First section value actions" }).click();
      await page.getByRole("menuitem", { name: "Copy data", exact: true }).click();
      const copied = await page.evaluate(() => window.__dashboardClipboard.at(-1));
      assert.match(copied, /Studio/u, "Component copy must use locally displayed rows");
      assert.doesNotMatch(copied, /Search/u, "Component copy must not leak unselected detail rows");
      await component("local-a-value").getByRole("button", { name: "First section value actions" }).click();
      await page.getByRole("menuitem", { name: "View data source", exact: true }).click();
      const inspector = page.getByRole("complementary", { name: "Data source for First section value" });
      await inspector.getByRole("tab", { name: "Evidence flow", exact: true }).click();
      assert.match(await inspector.innerText(), /Local product: Studio/u,
        "Source evidence must retain the local scope metadata");
      assert.match(await inspector.innerText(), /All products in the captured source/u,
        "Current scope must supplement, not rewrite, the authored source evidence");
      assert.equal(await inspector.locator('.source-trace[data-evidence-origin="provided"]').count(), 1);
      assert.match(await inspector.innerText(), /Current component filters/u,
        "Authored evidence must distinguish current component scope from the original population");
      await inspector.getByRole("tab", { name: "Data preview", exact: true }).click();
      assert.equal(await inspector.locator("tbody tr").count(), 1,
        "Source inspection must show exactly the locally displayed reviewed rows");
      assert.match(await inspector.locator("tbody").innerText(), /Studio/u);
      await inspector.evaluate((element) => { element.dataset.smokeOpenInstance = "original"; });
      await selectProduct("First section filters", "Local product", "Search", true);
      assert.deepEqual((await localRows("local-a")).map((row) => row.activeUsers), [60]);
      assert.equal(await inspector.getAttribute("data-smoke-open-instance"), "original",
        "A scope change must update the existing source drawer without remounting it");
      assert.match(await inspector.locator("tbody").innerText(), /Search/u,
        "The currently open source preview must follow local rows");
      assert.doesNotMatch(await inspector.locator("tbody").innerText(), /Studio/u);
      await inspector.getByRole("tab", { name: "Evidence flow", exact: true }).click();
      assert.match(await inspector.innerText(), /Local product: Search/u,
        "The currently open source evidence must follow local scope metadata");
      assert.doesNotMatch(await inspector.innerText(), /Local product: Studio/u,
        "An open authored evidence flow must not retain its previous section filter");
      await selectProduct("First section filters", "Local product", "Studio", true);
      assert.match(await inspector.innerText(), /Local product: Studio/u);
      await inspector.getByRole("button", { name: "Close data source" }).click();

      await component("local-a-chart").getByRole("button", { name: "First section chart actions" }).click();
      await page.getByRole("menuitem", { name: "Edit chart", exact: true }).click();
      const editor = page.getByRole("dialog", { name: "First section chart", exact: true });
      await editor.locator('.explorer-chart[data-ready="true"]').waitFor();
      const editorMotion = await editor.evaluate(element => ({ animation: getComputedStyle(element).animationName,
        transform: getComputedStyle(element).transform, x: element.getBoundingClientRect().x, y: element.getBoundingClientRect().y }));
      assert.equal(editorMotion.animation, "none", "Fullscreen editor must not inherit centered dialog motion");
      assert.equal(editorMotion.transform, "none");
      assert.equal(editorMotion.x, 0); assert.equal(editorMotion.y, 0);
      await page.emulateMedia({ reducedMotion: "reduce" });
      assert.equal(await editor.locator(".explorer-controls").evaluate(element => getComputedStyle(element).animationName), "none");
      await page.emulateMedia({ reducedMotion: "no-preference" });
      assert.match(await editor.locator(".explorer-chart svg").textContent(), /Studio/u,
        "The chart editor preview must start from the local section rows");
      assert.doesNotMatch(await editor.locator(".explorer-chart svg").textContent(), /Search/u);
      await editor.getByRole("textbox", { name: "X axis title", exact: true }).fill("Scoped product");
      await editor.getByRole("button", { name: "Save", exact: true }).click();
      await editor.waitFor({ state: "hidden" });
      assert.match(await component("local-a-chart").innerText(), /Scoped product/u,
        "The authored local chart must apply its saved shared chart override");
      await component("local-a-chart").getByRole("button", { name: "First section chart actions" }).click();
      await page.getByRole("menuitem", { name: "Copy data", exact: true }).click();
      const chartCopy = await page.evaluate(() => window.__dashboardClipboard.at(-1));
      assert.match(chartCopy, /Studio/u);
      assert.doesNotMatch(chartCopy, /Search/u, "Saving a local chart must preserve scoped copy rows");

      await component("standard-card").locator('.smooth-card-surface[data-ready="true"]').waitFor({ state: "attached" });
      await page.emulateMedia({ media: "print" });
      const printed = await component("standard-card").evaluate((element) => {
        const style = getComputedStyle(element);
        return { svg: getComputedStyle(element.querySelector(".smooth-card-surface")).display,
          nativeBackground: style.backgroundColor, nativeBorder: style.borderTopColor,
          borderWidth: style.borderTopWidth };
      });
      assert.equal(printed.svg, "none", "Print must not paint stale screen-sized smooth card SVGs");
      assert.notEqual(printed.nativeBackground, "rgba(0, 0, 0, 0)", "Print must paint the native card background");
      assert.notEqual(printed.nativeBorder, "rgba(0, 0, 0, 0)", "Print must paint the native card border");
      assert.equal(printed.borderWidth, "1px");
      const printedFilter = page.getByRole("region", { name: "First section filters", exact: true })
        .getByRole("button", { name: "Local product", exact: true });
      assert.equal(await printedFilter.isVisible(), true, "Printed local filter values must remain visible");
      assert.match(await printedFilter.innerText(), /Studio/u);
      await page.emulateMedia({ media: null });

      const funnel = component("shared-funnel");
      assert.deepEqual(await funnel.locator(".chart-funnel-stage-name").allTextContents(),
        ["Visited", "Signed up", "Started", "Invited", "Shared", "Returned", "Purchased", "Activated"]);
      assert.deepEqual(await funnel.locator(".chart-funnel-stage-share").allTextContents(),
        ["100%", "75%", "60%", "45%", "30%", "20%", "12%", "6%"]);
      assert.equal(await funnel.locator(".chart-funnel-caption").count(), 0);
      const stageColors = () => funnel.locator('stop[data-stage-stop="start"]').evaluateAll(
        (stops) => stops.map((stop) => getComputedStyle(stop).stopColor));
      const restingColors = await stageColors();
      assert.equal(new Set(restingColors).size, 8, "Stages need distinct tonal shades");
      const valueType = (element) => {
        const style = getComputedStyle(element);
        return [style.fontFamily, style.fontSize, style.lineHeight, style.fontWeight, style.letterSpacing];
      };
      const funnelValueType = await funnel.locator(".chart-funnel-stage-value").first().evaluate(valueType);
      const metricValueType = await component("standalone-metric").locator(".metric-value").evaluate(valueType);
      assert.equal(funnelValueType[0], metricValueType[0]);
      assert.equal(funnelValueType[3], metricValueType[3], "Responsive values retain shared KPI family and weight");
      await component("plain-chart").locator(".recharts-wrapper").hover();
      const sharedTooltipType = await component("plain-chart").locator(".chart-tooltip").evaluate(valueType);
      const signup = funnel.getByRole("button", { name: "Signed up: 75,000, 75% of Visited", exact: true });
      await signup.hover();
      let funnelTooltip = funnel.getByRole("tooltip");
      await funnelTooltip.waitFor();
      assert.deepEqual(await funnelTooltip.locator(".chart-tooltip").evaluate(valueType), sharedTooltipType,
        "Funnel tooltip typography must match shared Recharts tooltips on both surfaces");
      assert.match(await funnelTooltip.innerText(), /75,000/u, "Funnel tooltips show exact rather than compact counts");
      assert.match(await funnelTooltip.innerText(), /Drop-off.*25,000/su);
      assert.equal(await funnelTooltip.locator(".chart-tooltip-heading b").innerText(), "75,000");
      assert.match(await funnelTooltip.innerText(), /Visited → Signed up.*75%/su);
      assert.match(await funnelTooltip.innerText(), /Drop-off.*−25,000/su);
      assert.doesNotMatch(await funnelTooltip.innerText(), /of Visited|Exact count/u);
      assert.deepEqual((await stageColors()).map((color, index) => color !== restingColors[index]),
        [false, true, false, false, false, false, false, false], "Only the active ribbon segment should highlight");
      assert.equal(await signup.evaluate((element) => getComputedStyle(element).backgroundColor), "rgba(0, 0, 0, 0)",
        "Hover must not paint an unrelated full-column background");
      await signup.click();
      await page.getByRole("dialog", { name: "Selection actions", exact: true }).waitFor();
      assert.equal(await page.locator(".dashboard-ask-selected-region").count(), 1,
        "Funnel stages must still support mark-level Ask selection");
      await page.keyboard.press("Escape");
      await funnel.getByRole("button", { name: "Started: 60,000, 60% of Visited", exact: true }).focus();
      assert.match(await funnelTooltip.innerText(), /Signed up → Started.*80%/su,
        "Step conversion must use the previous stage denominator, not the first stage");
      assert.doesNotMatch(await funnelTooltip.innerText(), /60%/u);
      await page.keyboard.press("Escape");
      assert.equal(await funnelTooltip.count(), 0);
      for (const [width, layout, size] of [[1152, "horizontal", "32px"], [1040, "compact", "24px"], [360, "vertical", "24px"]]) {
        await funnel.locator(".chart-funnel").evaluate((element, value) => { element.style.width = `${value}px`; }, width);
        await page.waitForFunction(({ width, layout }) => {
          const element = document.querySelector('[data-component-id="shared-funnel"] .chart-funnel');
          return element.dataset.funnelLayout === layout && Math.abs(element.clientWidth - width) < 1;
        }, { width, layout });
        assert.equal(await funnel.locator(".chart-funnel-stage-value").first().evaluate((element) => getComputedStyle(element).fontSize), size);
        assert.equal(await funnel.locator(".chart-funnel-ribbon").isVisible(), layout !== "vertical");
        if (layout === "vertical") {
          const widths = await funnel.locator(".chart-funnel-stage-bar-fill").evaluateAll((elements) => elements.map((element) => element.getBoundingClientRect().width));
          assert.ok(Math.abs(widths[1] / widths[0] - .75) < .001, "Vertical bar length must preserve stage proportions");
          assert.equal(await funnel.locator(".chart-funnel-stage-bar-fill").first().evaluate((element) => getComputedStyle(element).borderTopLeftRadius), "6px",
            "Sticker pop (the last applied theme) keeps its capped bar radius in vertical rendering");
        }
      }
      await funnel.locator(".chart-funnel").evaluate((element) => { element.style.removeProperty("width"); });
      await funnel.getByRole("button", { name: "Conversion funnel actions", exact: true }).click();
      await page.getByRole("menuitem", { name: "Edit chart", exact: true }).click();
      const funnelEditor = page.getByRole("dialog", { name: "Conversion funnel", exact: true });
      await funnelEditor.locator('.explorer-chart[data-ready="true"]').waitFor();
      await funnelEditor.getByRole("button", { name: "Cancel", exact: true }).hover();
      const funnelColors = await funnelEditor.evaluate((element) => ({
        marks: [...element.querySelectorAll('stop[data-stage-stop="start"]')].map((stop) => getComputedStyle(stop).stopColor),
        controls: [...element.querySelectorAll(".explorer-color-trigger > i")].map((swatch) => getComputedStyle(swatch).backgroundColor),
      }));
      assert.equal(funnelColors.marks.length, 8);
      assert.deepEqual(funnelColors.controls, funnelColors.marks, "Funnel editor swatches must describe the colors actually rendered");
      await funnelEditor.getByRole("button", { name: "Cancel", exact: true }).click();
      await funnelEditor.waitFor({ state: "hidden" });
      const repeated = component("funnel-repeated");
      await repeated.getByRole("button", { name: "Repeated-stage funnel actions", exact: true }).click();
      await page.getByRole("menuitem", { name: "Edit chart", exact: true }).click();
      const repeatedEditor = page.getByRole("dialog", { name: "Repeated-stage funnel", exact: true });
      await repeatedEditor.locator('.explorer-chart[data-ready="true"]').waitFor();
      await repeatedEditor.getByRole("button", { name: "Cancel", exact: true }).hover();
      const repeatedColors = await repeatedEditor.evaluate((element) => ({
        marks: [...element.querySelectorAll('stop[data-stage-stop="start"]')].map((stop) => getComputedStyle(stop).stopColor),
        controls: [...element.querySelectorAll(".explorer-color-trigger > i")].map((swatch) => getComputedStyle(swatch).backgroundColor),
      }));
      assert.deepEqual(repeatedColors.controls, [repeatedColors.marks[0], repeatedColors.marks[3]],
        "Repeated names use their first occurrence tint; unnamed stages still occupy a tint position");
      await repeatedEditor.getByRole("button", { name: "Cancel", exact: true }).click();
      await repeatedEditor.waitFor({ state: "hidden" });
      const gaps = component("funnel-gaps");
      assert.equal(await gaps.locator(".chart-funnel-band").count(), 2, "Missing values must leave a real break in the ribbon");
      assert.deepEqual(await gaps.locator("linearGradient").evaluate((gradient) => ({
        units: gradient.getAttribute("gradientUnits"), width: gradient.x2.baseVal.value,
      })), { units: "userSpaceOnUse", width: 300 }, "Disconnected paths must use one color coordinate system, not restart the gradient");
      assert.equal(await gaps.locator(".chart-funnel-stage-value").nth(1).textContent(), "—");
      const ratios = component("funnel-ratios");
      await ratios.getByRole("button", { name: "B: 60%, 60% of A", exact: true }).focus();
      assert.match(await ratios.getByRole("tooltip").innerText(), /A → B.*60%/su);
      assert.match(await ratios.getByRole("tooltip").innerText(), /Drop-off.*−40 pp/su);
      await ratios.locator(".chart-funnel-stage").nth(2).focus();
      assert.equal(await ratios.locator(".chart-tooltip-heading b").innerText(), "31.2345%",
        "Rounded ratio labels must expose the precise reviewed percentage");
      await gaps.locator(".chart-funnel-stage").nth(2).focus();
      assert.equal(await gaps.locator(".chart-tooltip-heading b").innerText(), "25");
      assert.match(await gaps.getByRole("tooltip").innerText(), /B → C.*—.*Drop-off.*—/su);
      await page.keyboard.press("Escape");
      await page.setViewportSize({ width: 390, height: 844 });
      await signup.tap();
      const pinned = funnel.getByRole("dialog", { name: "Signed up details", exact: true });
      await pinned.waitFor();
      assert.equal(await page.getByRole("dialog", { name: "Selection actions", exact: true }).count(), 0,
        "A touch inspection must not automatically open Ask selection");
      assert.equal(await pinned.evaluate((element) => element.contains(document.activeElement)), true);
      await pinned.getByRole("button", { name: "Done", exact: true }).tap();
      await pinned.waitFor({ state: "hidden" });
      assert.equal(await signup.evaluate((element) => element === document.activeElement), true,
        "Dismissal returns focus to the inspected stage");
      assert.equal(await funnelTooltip.count(), 0, "Restoring focus must not immediately reopen details");
      await signup.tap();
      await pinned.waitFor();
      await page.keyboard.press("Escape");
      await pinned.waitFor({ state: "hidden" });
      assert.equal(await signup.evaluate((element) => element === document.activeElement), true);
      await signup.tap();
      await pinned.waitFor();
      await pinned.getByRole("button", { name: "Ask about this stage", exact: true }).tap();
      await page.getByRole("dialog", { name: "Selection actions", exact: true }).waitFor();
      assert.equal(await page.locator(".dashboard-ask-selected-region").count(), 1);
      await page.keyboard.press("Escape");
      await signup.tap();
      await pinned.waitFor();
      const outside = funnel.getByRole("combobox", { name: "Conversion funnel actions", exact: true });
      await page.getByRole("heading", { name: "Independent heading", exact: true }).tap();
      await pinned.waitFor({ state: "hidden" });
      await outside.focus();
      await page.keyboard.press("Tab");
      await funnelTooltip.waitFor();
      assert.match(await funnelTooltip.innerText(), /Visited/u,
        "Keyboard entry after touch dismissal must not inherit stale touch modality");
      await page.keyboard.press("Escape");
      await repeated.locator(".chart-funnel-stage").first().focus();
      assert.equal(await repeated.getByRole("tooltip").evaluate((element) => {
        const bounds = element.getBoundingClientRect();
        return [...element.querySelectorAll(".chart-tooltip, strong, span, b")].every((child) => {
          const rect = child.getBoundingClientRect();
          return rect.left >= bounds.left - 1 && rect.right <= bounds.right + 1;
        });
      }), true, "Long stage names and exact large values must fit within the mobile tooltip");
      assert.equal(await repeated.getByRole("tooltip").locator(".chart-tooltip > span").count(), 0,
        "The first stage has no previous stage to compare");
      const lastStage = funnel.getByRole("button", { name: "Activated: 6,000, 6% of Visited", exact: true });
      await lastStage.focus();
      await funnelTooltip.waitFor();
      assert.match(await funnelTooltip.innerText(), /Activated/u, "Keyboard focus must reveal the last vertical stage details");
      assert.equal(await funnel.locator(".chart-funnel").evaluate((element) => {
        const bounds = element.getBoundingClientRect();
        const tip = element.querySelector('[role="tooltip"]').getBoundingClientRect();
        return tip.left >= bounds.left - 1 && tip.right <= bounds.right + 1
          && tip.top >= bounds.top - 1 && tip.bottom <= bounds.bottom + 1;
      }), true, "Mobile tooltip must stay inside the visible chart, not the scrolled canvas");
      const scrolling = await funnel.locator(".chart-funnel-scroll").evaluate((element) => ({
        overflowing: element.scrollWidth > element.clientWidth, scrolled: element.scrollLeft > 0,
        pageOverflow: document.documentElement.scrollWidth > document.documentElement.clientWidth,
      }));
      assert.deepEqual(scrolling, { overflowing: false, scrolled: false, pageOverflow: false },
        "Narrow funnels must show all stages vertically without horizontal scrolling");
      await page.keyboard.press("Escape");
      await page.evaluate(() => {
        const serialize = XMLSerializer.prototype.serializeToString;
        XMLSerializer.prototype.serializeToString = function (element) {
          const markup = serialize.call(this, element);
          if (element.tagName.toLowerCase() === "svg") window.__funnelExportSvg = markup;
          return markup;
        };
        const write = navigator.clipboard.write;
        navigator.clipboard.write = async (items) => {
          window.__funnelClipboardBlob = await items[0].getType("image/png");
          return write(items);
        };
      });
      await funnel.getByRole("combobox", { name: "Conversion funnel actions", exact: true })
        .selectOption({ label: "Copy as image" });
      await page.waitForFunction(() => window.__dashboardClipboard.at(-1)?.type === "image/png");
      const funnelImage = await page.evaluate(() => ({ ...window.__dashboardClipboard.at(-1),
        text: [...new DOMParser().parseFromString(window.__funnelExportSvg, "image/svg+xml").querySelectorAll("text")]
          .map((text) => text.textContent) }));
      assert.ok(funnelImage.height > funnelImage.width, "Narrow PNG must export every vertical stage rather than a hidden ribbon");
      for (const expected of ["Visited", "100K", "100%", "Activated", "6K", "6%"]) {
        assert.ok(funnelImage.text.includes(expected), `${surface} funnel image must include ${expected}`);
      }
      assert.ok(!funnelImage.text.includes("Percent of Visited"), "Removed footer must not survive in exports");
      await page.emulateMedia({ media: "print" });
      const printBounds = await funnel.evaluate((element) => {
        const viewport = element.querySelector(".chart-funnel-scroll").getBoundingClientRect();
        const stages = [...element.querySelectorAll(".chart-funnel-stage")].map((stage) => stage.getBoundingClientRect());
        return { allVisible: stages.every((stage) => stage.left >= viewport.left - 1 && stage.right <= viewport.right + 1),
          overflow: getComputedStyle(element.querySelector(".chart-funnel-scroll")).overflowX };
      });
      assert.deepEqual(printBounds, { allVisible: true, overflow: "visible" }, "Print must include every stage in the responsive layout");
      await page.emulateMedia({ media: null });
      await page.setViewportSize({ width: 1440, height: 1100 });
      for (const [width, layout] of [[1152, "horizontal"], [1040, "compact"]]) {
        await funnel.locator(".chart-funnel").evaluate((element, value) => { element.style.width = `${value}px`; }, width);
        await page.waitForFunction((layout) => document.querySelector('[data-component-id="shared-funnel"] .chart-funnel').dataset.funnelLayout === layout, layout);
        let ltrPixels;
        for (const direction of ["ltr", "rtl"]) {
          await funnel.evaluate((element, value) => { element.dir = value; }, direction);
          const stageGeometry = await funnel.locator(".chart-funnel").evaluate((element) => {
            const ribbon = element.querySelector(".chart-funnel-ribbon");
            const bounds = ribbon.getBoundingClientRect();
            const paths = [...ribbon.querySelectorAll(".chart-funnel-band")];
            return [...element.querySelectorAll(".chart-funnel-stage")].map((stage) => {
              const box = stage.getBoundingClientRect();
              const x = box.left + box.width / 2;
              let height = 0;
              for (let y = 0; y < 200; y++) {
                const point = new DOMPoint(x, bounds.top + (y + .5) / 200 * bounds.height);
                if (paths.some((path) => path.isPointInFill(point.matrixTransform(path.getScreenCTM().inverse())))) height++;
              }
              return { x, height };
            });
          });
          assert.equal(stageGeometry[0].x > stageGeometry.at(-1).x, direction === "rtl",
            `${layout} stage labels must follow inherited ${direction} direction`);
          for (const [index, share] of [1, .75, .6, .45, .3, .2, .12, .06].entries()) {
            assert.ok(Math.abs(stageGeometry[index].height - share * 180) <= 2,
              `${layout} ${direction} ribbon beneath stage ${index} must encode its own reviewed value`);
          }
          const beforeCopy = await page.evaluate(() => window.__dashboardClipboard.length);
          await funnel.getByRole("button", { name: "Conversion funnel actions", exact: true }).click();
          await page.getByRole("menuitem", { name: "Copy as image", exact: true }).click();
          await page.waitForFunction((count) => window.__dashboardClipboard.length > count, beforeCopy);
          const exported = await page.evaluate(() => {
            const svg = new DOMParser().parseFromString(window.__funnelExportSvg, "image/svg+xml");
            return { ...window.__dashboardClipboard.at(-1), paths: svg.querySelectorAll("path").length,
              text: [...svg.querySelectorAll("text")].map((element) => element.textContent) };
          });
          assert.ok(exported.paths > 0 && exported.width >= width * 2 && exported.height < exported.width,
            `${layout} exports must retain the visible ribbon at its full width`);
          assert.ok(exported.text.includes("Visited") && exported.text.includes("Activated"));
          const pixels = await funnel.evaluate(async (element) => {
            const image = await createImageBitmap(window.__funnelClipboardBlob);
            const canvas = document.createElement("canvas");
            canvas.width = image.width; canvas.height = image.height;
            const context = canvas.getContext("2d"); context.drawImage(image, 0, 0);
            const scene = element.querySelector(".chart-funnel-canvas").getBoundingClientRect();
            const ribbon = element.querySelector(".chart-funnel-ribbon").getBoundingClientRect();
            const scale = image.width / Math.ceil(Math.max(element.getBoundingClientRect().width, scene.width) + 40);
            const stages = [...element.querySelectorAll(".chart-funnel-stage")];
            const samples = [[0, .15], [1, .25], [stages.length - 1, .15]].map(([index, y]) => {
              const stage = stages[index].getBoundingClientRect();
              return [...context.getImageData(Math.round((20 + stage.left + stage.width / 2 - scene.left) * scale),
                Math.round((48 + ribbon.top - scene.top + ribbon.height * y) * scale), 1, 1).data];
            });
            image.close();
            return samples;
          });
          if (direction === "ltr") ltrPixels = pixels;
          else assert.ok(pixels.every((pixel, index) => pixel.every((channel, color) =>
            Math.abs(channel - ltrPixels[index][color]) <= 2)),
            `${layout} RTL PNG must preserve each label's ribbon thickness and gradient color, not the LTR picture`);
        }
      }
      await funnel.locator(".chart-funnel").evaluate((element) => { element.style.width = "360px"; });
      await page.waitForFunction(() => document.querySelector('[data-component-id="shared-funnel"] .chart-funnel').dataset.funnelLayout === "vertical");
      const rtlBars = await funnel.locator(".chart-funnel-stage-bar-fill").evaluateAll((bars) => bars.map((bar) => {
        const bounds = bar.getBoundingClientRect();
        return { width: bounds.width, end: bounds.right - bar.parentElement.getBoundingClientRect().right };
      }));
      assert.ok(rtlBars.every(({ end }) => Math.abs(end) < 1), "Vertical RTL bars remain anchored at inline start");
      assert.ok(Math.abs(rtlBars[1].width / rtlBars[0].width - .75) < .001, "Vertical RTL proportions remain unchanged");
      await funnel.evaluate((element) => { element.removeAttribute("dir"); });
      await funnel.locator(".chart-funnel").evaluate((element) => { element.style.removeProperty("width"); });
      const copiedImages = await page.evaluate(() => window.__dashboardClipboard.length);
      await component("plain-chart").getByRole("button", { name: "Plain chart actions", exact: true }).click();
      await page.getByRole("menuitem", { name: "Copy as image", exact: true }).click();
      await page.waitForFunction((count) => window.__dashboardClipboard.length > count, copiedImages);
      assert.equal(await page.evaluate(() => window.__dashboardClipboard.at(-1).type), "image/png",
        "Existing Recharts images must still copy after the funnel export path is added");

      await selectProduct("Page filters", "Page product", "Search");
      assert.deepEqual(await localRows("local-a"), [], "Conflicting global and local exact filters must intersect");
      assert.deepEqual((await localRows("local-b")).map((row) => row.activeUsers), [60]);
      assert.equal(await page.getByRole("region", { name: "First section filters", exact: true }).locator(".clear-filters").count(), 0,
        "An active section selection should reset via its dropdown, without a separate clear action");
      await selectProduct("First section filters", "Local product", "All");
      assert.deepEqual((await localRows("local-a")).map((row) => row.activeUsers), [60],
        "Local All must not undo the exact page filter with the same ID");
      assert.equal(await page.getByRole("button", { name: "Clear page", exact: true }).count(), 1,
        "Clearing the section must leave the page filter active");
      await page.getByRole("button", { name: "Clear page", exact: true }).click();
      assert.deepEqual((await localRows("local-a")).map((row) => row.activeUsers), [100]);
      await page.getByRole("region", { name: "Local date filters", exact: true })
        .getByRole("button", { name: "Date range", exact: true }).click();
      await page.getByRole("menuitem", { name: "All available dates", exact: true }).click();
      assert.equal(await page.getByTestId("local-date-value").textContent(), "all",
        "A local date picker's All available dates action must restore literal All, not an exact latest date");
      assert.equal(await page.getByRole("region", { name: "Local date filters", exact: true })
        .getByRole("button", { name: "Clear section", exact: true }).count(), 0,
      "Local date controls should not add a separate reset button");

      const heading = page.locator('[data-editable-id="local-a"]');
      const headingActions = (id) => page.locator(`[data-editable-id="${id}"]`).locator("..")
        .getByRole("button", { name: "Section heading actions", exact: true });
      const headingMenu = headingActions("local-a");
      assert.equal(await headingMenu.count(), 0, "Heading controls belong only in Edit mode");
      await selectProduct("First section filters", "Local product", "Studio");
      await page.getByRole("button", { name: "Edit text and layout", exact: true }).click();
      const menuGeometry = await headingMenu.evaluate((button) => {
        const bounds = button.getBoundingClientRect();
        const header = button.closest(".data-section-header").getBoundingClientRect();
        return { opacity: getComputedStyle(button).opacity,
          contained: bounds.left >= header.left && bounds.right <= header.right
            && bounds.top >= header.top && bounds.bottom <= header.bottom };
      });
      assert.deepEqual(menuGeometry, { opacity: "1", contained: true }, "Heading actions must be visible inside their own header");
      await heading.fill("Edited section heading");
      await heading.press("Enter");
      await headingMenu.click();
      await page.getByRole("menuitem", { name: "Hide heading", exact: true }).click();
      assert.equal(await heading.isVisible(), false, `${surface} hides the heading`);
      assert.equal(await component("local-a-value").isVisible(), true, "Hiding a heading must not hide its content");
      const localFilter = page.getByRole("region", { name: "First section filters", exact: true });
      assert.equal(await localFilter.isVisible(), true, "Hiding a heading must not hide its active filters");
      assert.match(await localFilter.innerText(), /Studio/u);
      assert.deepEqual((await localRows("local-a")).map((row) => row.activeUsers), [40]);
      await page.getByRole("button", { name: `Undo ${surface} change`, exact: true }).click();
      assert.equal(await heading.isVisible(), true);
      assert.equal(await heading.textContent(), "Edited section heading", "Undo hide preserves the edited title");
      await page.getByRole("button", { name: `Redo ${surface} change`, exact: true }).click();
      assert.equal(await heading.isVisible(), false);
      await page.getByRole("button", { name: "Save", exact: true }).click();
      await page.getByRole("button", { name: "Edit text and layout", exact: true }).waitFor();
      await page.reload({ waitUntil: "load" });
      assert.equal(await heading.isVisible(), false, "Heading visibility survives reload");
      assert.equal(await headingMenu.count(), 0);
      assert.equal(await heading.textContent(), "Edited section heading", "Hidden titles retain saved edits");
      assert.equal(await localFilter.isVisible(), true);
      await page.getByRole("button", { name: "Edit text and layout", exact: true }).click();
      await headingActions("standalone-heading").click();
      await page.getByRole("menuitem", { name: "Hide heading", exact: true }).click();
      assert.equal(await page.locator('[data-editable-id="standalone-heading"]').locator("..").isVisible(), false,
        "A hidden standalone heading without filters must collapse entirely");
      await headingActions("no-spacing").click();
      await page.getByRole("menuitem", { name: "Hide heading", exact: true }).click();
      assert.equal(await section("no-spacing").locator(".data-section-header").isVisible(), false,
        "A filter slot rendering no controls must not keep a hidden heading's empty grid track");
      let hiddenCount = 3;
      if (surface === "dashboard") {
        await headingActions("canvas-heading").click();
        await page.getByRole("menuitem", { name: "Hide heading", exact: true }).click();
        const row = page.locator('[data-sortable-row="canvas-metrics"]');
        assert.equal(await row.locator(".sortable-row-header").isVisible(), false,
          "Hiding a canvas heading must also collapse its outer grid wrapper");
        const leadingGap = await row.evaluate((element) =>
          element.querySelector(".sortable-item").getBoundingClientRect().top
          - element.getBoundingClientRect().top - parseFloat(getComputedStyle(element).paddingTop));
        assert.equal(leadingGap, 0, "Hidden canvas headings must leave no empty grid track or extra gap");
        hiddenCount += 1;
      }
      await page.getByRole("button", { name: `Restore hidden (${hiddenCount})`, exact: true }).click();
      assert.equal(await heading.isVisible(), true);
      assert.equal(await heading.textContent(), "Edited section heading");
      assert.equal(await page.locator('[data-editable-id="standalone-heading"]').isVisible(), true);
      if (surface === "dashboard") assert.equal(await page.locator('[data-editable-id="canvas-heading"]').isVisible(), true);
      await page.getByRole("button", { name: "Save", exact: true }).click();
      await page.getByRole("button", { name: "Edit text and layout", exact: true }).waitFor();
      assert.equal(await headingMenu.count(), 0, "View mode must remove heading actions again");

      await page.setViewportSize({ width: 390, height: 844 });
      const mobileMetrics = await section("metrics").evaluate((element) => {
        const [first, second] = element.querySelectorAll("[data-component-id]");
        const a = first.getBoundingClientRect();
        const b = second.getBoundingClientRect();
        return { tracks: getComputedStyle(element).gridTemplateColumns.split(" ").length,
          gap: b.top - a.bottom, aligned: a.left === b.left && a.width === b.width };
      });
      assert.deepEqual(mobileMetrics, { tracks: 1, gap: 12, aligned: true },
        `${surface} mobile metrics must use one actual track and a 12px KPI gap`);
      if (surface === "dashboard") {
        await page.getByRole("combobox", { name: "More" }).selectOption("edit");
        const mobileCanvas = await page.locator('[data-sortable-row="canvas-metrics"]').evaluate((element) => {
          const [first, second] = element.querySelectorAll(":scope > .sortable-item");
          const a = first.getBoundingClientRect();
          const b = second.getBoundingClientRect();
          return { tracks: getComputedStyle(element).gridTemplateColumns.split(" ").length,
            gap: b.top - a.bottom, aligned: a.left === b.left && a.width === b.width };
        });
        assert.deepEqual(mobileCanvas, { tracks: 1, gap: 12, aligned: true },
          "Mobile canvas metrics must stack into one track with a real 12px gap");
        const continuationGap = await page.evaluate(() =>
          document.querySelector('[data-component-id="canvas-four"]').closest('.sortable-item').getBoundingClientRect().top
          - document.querySelector('[data-component-id="canvas-three"]').closest('.sortable-item').getBoundingClientRect().bottom);
        assert.equal(continuationGap, 20, "Mobile editing blocks, including their touch handles, retain a real 20px gap");
        const singletonHandle = page.locator('[data-sortable-item-id="canvas-three"] [data-block-resize-handle]');
        assert.equal(await singletonHandle.isVisible(), false,
          "Mobile singleton cards must not show a desktop resize handle");
      }
      await page.getByRole("region", { name: "First section filters", exact: true }).scrollIntoViewIfNeeded();
      const mobile = await section("local-a").evaluate((element) => {
        const title = element.querySelector(".data-section-title").getBoundingClientRect();
        const controls = element.querySelector(".filters").getBoundingClientRect();
        return { wraps: controls.top >= title.bottom,
          inside: controls.left >= 0 && controls.right <= innerWidth,
          overflow: document.documentElement.scrollWidth > innerWidth + 1 };
      });
      assert.deepEqual(mobile, { wraps: true, inside: true, overflow: false },
        `${surface} shared section filters must wrap without viewport overflow`);
      assert.deepEqual(errors, [], `${surface} independent components should not emit browser errors`);
      await page.close();
    }
  } finally {
    rmSync(independent, { recursive: true, force: true });
  }
}

let browser;
try {
  const build = runDataAppFixtureBuild(project, { pluginRoot });
  assert.equal(build.status, 0, `${build.stdout}\n${build.stderr}`);
  browser = await chromium.launch({ executablePath: resolveChromiumExecutable(), headless: true });
  const page = await browser.newPage({ viewport: { width: 390, height: 1100 }, hasTouch: true });
  const failures = [];
  page.on("pageerror", (error) => failures.push(error.message));
  await installDashboardBrowserMocks(page);
  await page.goto(pathToFileURL(join(project, "dist/index.html")).href, { waitUntil: "load" });

  const charts = page.locator('[data-sortable-region]').filter({
    has: page.locator('[data-sortable-item-id="wide-trend"]'),
  });
  const originalChartRegionId = await charts.getAttribute("data-sortable-region");
  const metrics = page.locator('[data-sortable-region]').filter({
    has: page.locator('[data-sortable-item-id="metric-one"]'),
  });
  const bespoke = page.locator('[data-sortable-region]').filter({
    has: page.locator('[data-sortable-item-id="bespoke-one"]'),
  });
  const visualOrder = page.locator('[data-sortable-region]').filter({
    has: page.locator('[data-sortable-item-id="dom-first-visually-right"]'),
  });
  await page.setViewportSize({ width: 1440, height: 1100 });
  await page.waitForFunction(() => document.querySelector(
    '[data-sortable-region="dashboard:custom-smoke:reviewed-trend-grid"]')?.dataset.sortableVariant === "canvas");
  assert.equal(await charts.getAttribute("data-sortable-variant"), "canvas",
    "A grid first mounted in a narrow preview must gain resizing when there is room");
  assert.equal(await charts.evaluate((element) => {
    const first = element.querySelector('[data-sortable-item-id="wide-trend"]').getBoundingClientRect();
    const second = element.querySelector('[data-sortable-item-id="narrow-trend"]').getBoundingClientRect();
    return second.left - first.right;
  }), 14,
    "Promoting an authored canvas must preserve its deliberate 14px chart gap");
  assert.equal(originalChartRegionId, "dashboard:custom-smoke:reviewed-trend-grid",
    "An authored wrapper ID must contribute to the stable namespaced sortable identity");
  assert.equal(await charts.getAttribute("id"), "reviewed-trend-grid",
    "Adaptive sortable layouts must preserve the authored wrapper's actual HTML identity");
  assert.equal(await metrics.getAttribute("data-sortable-variant"), "canvas",
    "Ordinary authored metric rows should inherit smooth canvas movement and resizing");
  assert.equal(await bespoke.getAttribute("data-sortable-variant"), "freeform",
    "Genuinely bespoke grid-area layouts should retain their authored freeform composition");
  assert.equal(await visualOrder.getAttribute("data-sortable-variant"), "canvas",
    "Explicitly positioned ordinary grids should retain smooth canvas interactions");
  assert.deepEqual(await visualOrder.locator('[data-sortable-item-id]').evaluateAll((items) =>
    items.map((item) => item.dataset.sortableItemId)),
  ["dom-second-visually-left", "dom-first-visually-right"],
  "Canvas promotion must preserve measured left-to-right visual placement rather than DOM order");
  assert.equal(await page.locator('[data-sortable-item-id="wide-trend"]').getAttribute("data-sortable-span"), "8");
  assert.equal(await page.locator('[data-sortable-item-id="narrow-trend"]').getAttribute("data-sortable-span"), "4");
  assert.equal(await page.locator('[data-sortable-item-id="wide-trend"]').evaluate((item) =>
    item.classList.contains("editorial-featured-column")), true,
  "Nonstandard authored grid-placement classes must survive insertion of sortable wrappers");
  assert.equal(await page.locator('[data-sortable-item-id="full-trend"]').getAttribute("data-sortable-span"), "12");

  for (const id of ["metric-one", "metric-three", "wide-trend"]) {
    const component = page.locator(`[data-component-id="${id}"]`);
    const trigger = component.getByRole("button", { name: "More information" });
    assert.equal(await trigger.evaluate((button) => {
      const bounds = button.getBoundingClientRect();
      return document.elementFromPoint(bounds.left + bounds.width / 2, bounds.top + bounds.height / 2)
        ?.closest("button") === button;
    }), true, `${id} information icon must remain reachable instead of hiding under component actions`);
    await trigger.hover();
    const tooltip = page.locator('[role="tooltip"][data-tooltip-portal="true"]');
    await tooltip.waitFor({ state: "visible" });
    const tooltipState = await tooltip.evaluate((description) => {
      const bounds = description.getBoundingClientRect();
      return {
        portaled: description.parentElement === document.body,
        readable: description.textContent.trim().length > 15,
        insideViewport: bounds.left >= 0 && bounds.right <= window.innerWidth
          && bounds.top >= 0 && bounds.bottom <= window.innerHeight,
      };
    });
    assert.deepEqual(tooltipState, { portaled: true, readable: true, insideViewport: true },
      `${id} information tooltip should escape clipped titles and cards without leaving the viewport`);
    assert.equal(await trigger.getAttribute("aria-describedby"), await tooltip.getAttribute("id"),
      `${id} information tooltip should remain connected to its accessible trigger`);
    await trigger.focus();
    await trigger.press("Escape");
    await tooltip.waitFor({ state: "hidden" });
    await page.mouse.move(0, 0);
  }

  await page.getByRole("button", { name: "Edit text and layout" }).click();
  assert.equal(await charts.locator('[data-block-resize-handle][data-resize-neighbor]:not([hidden])').count(), 2,
    "Each authored chart row should expose its actual adjacent-card resize divider");
  assert.equal(await metrics.locator('[data-block-resize-handle][data-resize-neighbor]:not([hidden])').count(), 2,
    "Authored metric rows should expose adjacent metric resize dividers");

  async function assertFaithfulPreview(sourceId, targetId) {
    const item = page.locator(`[data-sortable-item-id="${sourceId}"]`);
    await item.scrollIntoViewIfNeeded();
    await item.evaluate(() => new Promise((resolve) => requestAnimationFrame(() => requestAnimationFrame(resolve))));
    const component = item.locator("[data-component-id]");
    const origin = await component.evaluate((element) => {
      const bounds = element.getBoundingClientRect();
      const header = (element.querySelector(".component-header") ?? element).getBoundingClientRect();
      for (const y of [bounds.top + 7, header.top + header.height * .35, header.top + header.height * .75]) {
        for (const fraction of [.75, .55, .35, .15]) {
          const x = bounds.left + bounds.width * fraction;
          const hit = document.elementFromPoint(x, y);
          if (hit && element.contains(hit)
            && !hit.closest("button, a, input, textarea, select, [contenteditable='true'], [role='button']")) {
            return { x, y };
          }
        }
      }
      return null;
    });
    assert.ok(origin, `${sourceId} should expose a safe direct-manipulation drag surface`);
    const target = await page.locator(`[data-sortable-item-id="${targetId}"]`).boundingBox();
    await page.mouse.move(origin.x, origin.y);
    await page.mouse.down();
    await page.mouse.move(target.x + target.width * .7, target.y + 18, { steps: 12 });
    await page.locator(".block-drag-preview").waitFor({ state: "visible", timeout: 5000 });
    const mismatches = await page.evaluate((id) => {
      const source = document.querySelector(`[data-sortable-item-id="${id}"]`);
      const preview = document.querySelector(".block-drag-preview");
      const selectors = [".dashboard-component", ".component-title", ".data-metric-value", ".chart-frame",
        ".chart-legend", "svg path"];
      const properties = ["font-family", "font-size", "font-weight", "line-height", "letter-spacing",
        "color", "background-color", "padding", "gap", "fill", "stroke"];
      return selectors.flatMap((selector) => {
        const original = source.querySelector(selector);
        const clone = preview.querySelector(selector);
        if (!original || !clone) return [];
        const sourceStyles = getComputedStyle(original);
        const cloneStyles = getComputedStyle(clone);
        return properties.filter((property) => sourceStyles.getPropertyValue(property)
          !== cloneStyles.getPropertyValue(property))
          .map((property) => ({ selector, property,
            source: sourceStyles.getPropertyValue(property),
            preview: cloneStyles.getPropertyValue(property) }));
      });
    }, sourceId);
    assert.deepEqual(mismatches, [],
      `${sourceId} drag preview should preserve authored typography, spacing, card styling, and chart marks`);
    await page.keyboard.press("Escape");
    await page.mouse.up();
    await page.locator(".block-drag-preview").waitFor({ state: "hidden" });
    await item.locator("..").evaluate(async (row) => {
      await Promise.all([...row.querySelectorAll("[data-sortable-item-id]")]
        .flatMap((entry) => entry.getAnimations().map((animation) => animation.finished.catch(() => {}))));
      await new Promise((resolve) => requestAnimationFrame(() => requestAnimationFrame(resolve)));
    });
  }

  await assertFaithfulPreview("metric-one", "metric-two");
  await assertFaithfulPreview("wide-trend", "narrow-trend");

  const source = page.locator('[data-sortable-item-id="wide-trend"]');
  const neighbor = page.locator('[data-sortable-item-id="narrow-trend"]');
  const handle = source.locator('[data-block-resize-handle]');
  const sourceBefore = await source.boundingBox();
  const neighborBefore = await neighbor.boundingBox();
  const control = await handle.boundingBox();
  const dividerAlignment = await handle.evaluate((element) => {
    const current = element.closest("[data-sortable-item-id]").getBoundingClientRect();
    const adjacent = element.closest("[data-sortable-item-id]").nextElementSibling.getBoundingClientRect();
    const bounds = element.getBoundingClientRect();
    return {
      horizontal: bounds.left + bounds.width / 2 - (current.right + adjacent.left) / 2,
      vertical: bounds.top + bounds.height / 2
        - (Math.max(current.top, adjacent.top) + Math.min(current.bottom, adjacent.bottom)) / 2,
    };
  });
  assert.ok(Math.abs(dividerAlignment.horizontal) <= 1,
  "The authored chart resize grip should sit in the exact center of the gap between adjacent cards");
  assert.ok(Math.abs(dividerAlignment.vertical) <= 1,
  "The authored chart resize grip should sit at the exact vertical midpoint of its adjacent cards");
  await page.mouse.move(control.x + control.width / 2, control.y + control.height / 2);
  await page.mouse.down();
  await page.mouse.move(control.x + control.width / 2 - 115, control.y + control.height / 2, { steps: 12 });
  await page.mouse.up();
  const sourceAfter = await source.boundingBox();
  const neighborAfter = await neighbor.boundingBox();
  for (const item of [source, neighbor]) {
    const painted = await item.locator(".recharts-surface").first().boundingBox();
    assert.ok(painted.width > 100 && painted.height > 100,
      "Resized charts must have a painted viewport, not only data paths inside a zero-width SVG");
  }
  assert.ok(sourceAfter.width < sourceBefore.width - 60,
    "Dragging an authored chart divider should reduce the selected card width");
  assert.ok(neighborAfter.width > neighborBefore.width + 60,
    "The actual adjacent chart should grow as its neighbor shrinks");

  await page.getByRole("button", { name: "Toggle earlier section" }).click();
  assert.equal(await charts.getAttribute("data-sortable-region"), originalChartRegionId,
    "An earlier conditional section must not change a later region's stable identity");
  assert.ok(Math.abs((await source.boundingBox()).width - sourceAfter.width) < 3,
    "Adding an earlier section must preserve owner-adjusted chart widths");
  await page.getByRole("button", { name: "Toggle earlier section" }).click();
  assert.equal(await charts.getAttribute("data-sortable-region"), originalChartRegionId,
    "Removing an earlier conditional section must not discard a region's saved layout");

  await page.getByRole("button", { name: "Save", exact: true }).click();
  await page.getByRole("button", { name: "Edit text and layout", exact: true }).waitFor();
  await page.reload({ waitUntil: "load" });
  await source.waitFor({ state: "visible" });
  assert.ok(Math.abs((await source.boundingBox()).width - sourceAfter.width) < 3,
    "Owner-adjusted authored chart widths must survive reload");
  assert.deepEqual(failures, [], "Adaptive authored dashboard layouts should not emit browser errors");
  console.log(JSON.stringify({ phase: "authored-canvas", status: "passed", narrowFirstMount: true,
    pointerResize: true, resizedWidthPersisted: true, paintedChartsAfterResize: true }));
  await assertComponentLabGeometry(browser);
  await assertIndependentComponents(browser);
  await assertReferenceLayoutContainment(browser);
  console.log(JSON.stringify({ status: "passed", chartRows: 3, chartResizeHandles: 2,
    metricResizeHandles: 2, bespokeFallback: "freeform", resizedWidthPersisted: true,
    dragPreviewMatchesSource: true, clippedTooltipsEscaped: true,
    independentSurfaces: ["dashboard", "report"], independentThemes: ["Classic", "Dark pixel", "Scientific blue"],
    localFilterSourceParity: true, mobileMetricGap: 12 }));
} finally {
  await browser?.close();
  rmSync(project, { recursive: true, force: true });
}

SHA-256: 61529b5c7d4f85ec07ebf374e60b50be8b19058a58d0c6d7a7928f5ffd7b121b