From 66a8f8078c600da30b939fca54948e5993ac04a7 Mon Sep 17 00:00:00 2001 From: Wassim Chegham Date: Thu, 10 Sep 2026 13:32:18 +0200 Subject: [PATCH 1/6] Redesign Scope documentation with an interactive benchmark playground Refresh the landing page and guide navigation, add a five-agent simulated flow, and preserve static GitHub Pages routes and accessibility. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> --- .github/workflows/static.yml | 4 +- website/.gitignore | 1 + website/README.md | 122 ++- website/astro.config.mjs | 57 +- website/src/components/FlowDemo.astro | 95 +++ website/src/components/Header.astro | 32 + website/src/components/Home.astro | 118 +++ website/src/components/PageTitle.astro | 7 + website/src/components/SiteTitle.astro | 25 +- .../docs/getting-started/install-cli.md | 5 +- .../docs/guides/prioritizing-requests.mdx | 2 +- .../docs/guides/submitting-requests-api.mdx | 4 +- website/src/content/docs/index.mdx | 211 +---- .../src/content/docs/reference/rest-api.md | 6 +- website/src/content/docs/resources/faq.md | 2 +- .../src/content/docs/resources/glossary.md | 22 +- website/src/plugins/remark-base-links.mjs | 28 + website/src/scripts/flow-demo.ts | 228 ++++++ website/src/scripts/sample-agents.ts | 13 + website/src/styles/landing.css | 734 ++++++------------ 20 files changed, 923 insertions(+), 793 deletions(-) create mode 100644 website/.gitignore create mode 100644 website/src/components/FlowDemo.astro create mode 100644 website/src/components/Header.astro create mode 100644 website/src/components/Home.astro create mode 100644 website/src/components/PageTitle.astro create mode 100644 website/src/plugins/remark-base-links.mjs create mode 100644 website/src/scripts/flow-demo.ts create mode 100644 website/src/scripts/sample-agents.ts diff --git a/.github/workflows/static.yml b/.github/workflows/static.yml index ca6213942..83c00b064 100644 --- a/.github/workflows/static.yml +++ b/.github/workflows/static.yml @@ -60,8 +60,8 @@ jobs: uses: actions/configure-pages@v5 - name: Build site env: - SITE: ${{ steps.pages.outputs.origin }} - BASE_PATH: ${{ steps.pages.outputs.base_path }} + SITE: ${{ steps.pages.outputs.origin || 'https://microsoft.github.io' }} + BASE_PATH: ${{ github.ref != 'refs/heads/main' && '/scope' || steps.pages.outputs.base_path }} run: pnpm run build - name: Upload artifact if: github.ref == 'refs/heads/main' diff --git a/website/.gitignore b/website/.gitignore new file mode 100644 index 000000000..97e663b17 --- /dev/null +++ b/website/.gitignore @@ -0,0 +1 @@ +.astro/ diff --git a/website/README.md b/website/README.md index 157407545..8d33de08f 100644 --- a/website/README.md +++ b/website/README.md @@ -7,7 +7,7 @@ End-user documentation site for **Scope**, built with and published to GitHub Pages. The product and this documentation site live in -[scope-core](https://github.com/growth-ecosystems/scope-core). +[microsoft/scope](https://github.com/microsoft/scope). ## Project structure @@ -16,6 +16,7 @@ The product and this documentation site live in ├── public/ # static assets ├── src/ │ ├── assets/ +│ ├── components/ # Astro landing, playground, header, page title │ ├── content/docs/ # all user-facing pages (.md / .mdx) │ │ ├── introduction/ │ │ ├── getting-started/ @@ -24,7 +25,10 @@ The product and this documentation site live in │ │ └── resources/ │ ├── openapi/scope-openapi.json # artifact generated from the API registry │ ├── plugins/ +│ │ ├── remark-base-links.mjs # project-base-safe Markdown and MDX links │ │ └── remark-http-snippets.mjs # turns ```http blocks into multi-language tabs +│ ├── scripts/flow-demo.ts # progressive-enhancement playground controller +│ ├── styles/landing.css # shared brand tokens + scoped landing styles │ └── content.config.ts ├── astro.config.mjs # sidebar, plugins, starlight-openapi config ├── AGENTS.md # conventions & guardrails for contributors / AI agents @@ -39,7 +43,7 @@ Sidebar order is defined in `astro.config.mjs`, not by directory order. | Command | Action | | :--------------------- | :--------------------------------------------------------- | | `pnpm install` | Install dependencies | -| `pnpm dev` | Start local dev server at `localhost:4321` | +| `pnpm dev` | Start dev server at the worktree's `DOC_PORT` (fallback: 4300) | | `pnpm build` | Build the production site to `./dist/` | | `pnpm preview` | Preview the production build locally | | `pnpm refresh:openapi` | Generate the OpenAPI snapshot from `scope-core` | @@ -68,12 +72,120 @@ where to look in scope-core for any given topic. ## Deployment -Pushed builds deploy to GitHub Pages via +Changes merged to `main` deploy to GitHub Pages via [../.github/workflows/static.yml](../.github/workflows/static.yml). The workflow builds from this `website/` directory (via a `working-directory` default and `website/**` path filters). `site` -and `base` are driven by `actions/configure-pages` outputs with safe -localhost defaults. +and `base` use `actions/configure-pages` outputs on `main`. Pull +requests build with the `/scope` project base but do not deploy. +Root/custom-domain Pages deployments retain an empty base. Output is +explicitly static: no SSR adapter, server, or API credentials are needed. + +To reproduce the project-site build locally, run from `website/`: + +```sh +SITE=https://microsoft.github.io BASE_PATH=/scope pnpm build +SITE=https://microsoft.github.io BASE_PATH=/scope pnpm preview +``` + +Open `/scope/` on the preview server. Use the production preview to +exercise Pagefind search; its index is generated at build time. + +Author Markdown links as `/getting-started/access/`, for example. +The base-link remark plugin prefixes Markdown links, reference +definitions, images, and literal MDX `href`/`src` attributes. +Astro components must construct internal URLs with +`import.meta.env.BASE_URL`. External URLs, protocol-relative URLs, +fragments, and relative links are left unchanged. The generated API +landing route is `/reference/api/`, not `/reference/api/operations/`. + +## Experience design + +The landing page is a product introduction and an entry point into the +documentation, not a replacement for the documentation reader. +Starlight retains search, theme selection, the mobile sidebar, the +table of contents, code examples, and previous/next navigation. + +- **Visual language:** restrained indigo, neutral surfaces, readable + system fonts, a dotted flow canvas, and shared light/dark tokens. + Green and red communicate criterion outcomes, always with text. +- **Navigation:** a landing header with direct documentation and demo + links, plus task-oriented guide groups: run experiments, design a + benchmark, and connect tools. Existing document URLs are preserved. +- **Onboarding:** a concrete example before terminology, followed by + separate Portal, CLI, and API entry points. Access requirements are + explicit rather than promising instant access to a hosted service. +- **Motion:** confined to the example experiment, not a permanently + animated logo or documentation chrome. + +### Interactive playground + +[FlowDemo.astro](src/components/FlowDemo.astro) renders the full diagram +and an initial task prompt as static HTML. +[flow-demo.ts](src/scripts/flow-demo.ts) progressively enhances it using +a custom element. It makes no network requests and adds no framework +or animation-library dependencies. + +Two invented scenarios illustrate task submission, five sample agent profiles, +a three-node criteria dependency graph, and per-criterion evidence. +The example results deliberately differ by scenario. They are labeled +as simulations, not measurements or agent rankings. Keep that +distinction if adding scenarios. + +The sample roster is GitHub Copilot, Claude Code, Cursor, OpenAI Codex, +and OpenCode. These are the five highest-adoption individually named +coding agents in the [JetBrains May-July 2026 survey report](https://blog.jetbrains.com/research/2026/08/ai-coding-agent-adoption-2026/); +the report also lists a combined JetBrains AI/Junie category, which is +not a single agent. Display order is not rank order. + +[sample-agents.ts](src/scripts/sample-agents.ts) is shared by the static +diagram and the results renderer. Connector branches and the profile +count derive from that roster. Results use one row per agent, with +invented pass/fail/skipped outcomes that respect the criteria chain. +The playground does not claim that all sample agents are supported +Scope integrations; the supported-agent links remain separate. + +Playback runs once when the playground enters view. Users can pause, +reset, replay, select a scenario, or inspect any step with a button. +Leaving the viewport or hiding the tab stops playback. Reduced-motion +users get manual **Next step** controls and no animated connectors. +Without JavaScript, the static diagram and explanation remain visible, +and nonfunctional playback controls stay hidden. + +### Review findings and recommendations + +The September 2026 review covered all 29 handwritten pages, navigation +into the generated API reference, onboarding, landing design, motion, +themes, responsive layout, and GitHub Pages paths. It was a UX and +documentation review, not an endpoint-by-endpoint API correctness audit. + +| Finding in the previous site | Change | +| --- | --- | +| Abstract hero and repetitive feature sections made the value hard to grasp. | Concrete product framing, an explorable example, and three evidence-focused cards. | +| Static agent scores looked like real comparative claims and did not explain the flow. | Clearly fictional scenarios with inspectable stages and dependency-aware outcomes. | +| A flat list of 14 guides mixed onboarding, configuration, and advanced integrations. | Task-oriented groups with advanced sections collapsed initially. | +| Hard-coded root links escaped a GitHub Pages project base. | Base-aware Astro links, a Markdown/MDX transform, and project-path PR builds. | +| Seven API-reference links pointed to a nonexistent operations index. | Links now target the generated API landing page. | +| The custom hero hid Starlight's skip-link destination. | One visible heading with the native `_top` anchor and a homepage-only title override. | +| The glossary described an optional DAG and included copy errors. | DAG-only terminology, corrected prose, and capability cross-links. | +| The custom install-directory example set the variable on the downloader, not the installer. | Apply `SCOPE_INSTALL_DIR` to the receiving `bash` process. | + +Recommended content follow-ups: + +- Reconcile the VS Code capability matrix with the documented worker + ID policy. The introduction and reference currently describe three + agents, while the worker ID list names only two. The landing's + supported-agent strip names only the two documented ACP workers; + its separately labeled fictional playground includes five examples. +- Walk the first-run guide against a current deployment, then add + maintained screenshots. Its claims about preseeded catalogs, model + availability, and UI labels should not be assumed for every deployment. +- Explain release-repository access during CLI onboarding. The legacy + `growth-ecosystems/scope-doc` reference is still used by the installer + and publishing workflow, so changing it just because the documentation + moved would be incorrect. A release migration is a separate change. +- Add a real, reproducible sample-results walkthrough when an approved + dataset is available. Keep real evidence separate from the playground. ## Learn more diff --git a/website/astro.config.mjs b/website/astro.config.mjs index a8d4ae9a6..c4baa67a8 100644 --- a/website/astro.config.mjs +++ b/website/astro.config.mjs @@ -9,6 +9,7 @@ import { readFileSync } from 'node:fs'; import { join } from 'node:path'; import { execSync } from 'node:child_process'; import remarkHttpSnippets from './src/plugins/remark-http-snippets.mjs'; +import remarkBaseLinks from './src/plugins/remark-base-links.mjs'; // https://astro.build/config // `site` and `base` are driven by the GitHub Pages deployment URL in CI @@ -47,13 +48,15 @@ function readDotEnv(name) { return undefined; } const docPort = Number(readDotEnv('DOC_PORT')) || 4300; +const base = process.env.BASE_PATH || '/'; export default defineConfig({ site: process.env.SITE || `http://localhost:${docPort}`, - base: process.env.BASE_PATH || '/', + base, + output: 'static', server: { port: docPort }, markdown: { - remarkPlugins: [remarkHttpSnippets], + remarkPlugins: [remarkHttpSnippets, [remarkBaseLinks, { base }]], }, integrations: [ starlight({ @@ -66,7 +69,10 @@ export default defineConfig({ customCss: ['./src/styles/landing.css'], components: { SiteTitle: './src/components/SiteTitle.astro', + Header: './src/components/Header.astro', + PageTitle: './src/components/PageTitle.astro', }, + social: [{ icon: 'github', label: 'GitHub', href: 'https://github.com/microsoft/scope' }], plugins: [ starlightOpenAPI([ { @@ -95,24 +101,42 @@ export default defineConfig({ { label: 'Guides', items: [ - { label: 'Submitting requests (Portal)', slug: 'guides/submitting-requests-portal' }, - { label: 'Submitting requests (REST API)', slug: 'guides/submitting-requests-api' }, - { label: 'Submitting requests (CLI)', slug: 'guides/submitting-requests-cli' }, - { label: 'Managing task prompts', slug: 'guides/managing-task-prompts' }, - { label: 'Defining evaluation criteria', slug: 'guides/defining-criteria' }, - { label: 'Defining profiles', slug: 'guides/defining-profiles' }, - { label: 'Working with prompt features', slug: 'guides/prompt-features' }, - { label: 'Choosing a coding agent', slug: 'guides/choosing-a-coding-agent' }, - { label: 'Choosing software stacks', slug: 'guides/software-stacks' }, - { label: 'Prioritizing & pausing requests', slug: 'guides/prioritizing-requests' }, - { label: 'Importing MCP servers', slug: 'guides/importing-mcp-servers' }, - { label: 'Importing skills', slug: 'guides/importing-skills' }, - { label: 'Importing VS Code extensions', slug: 'guides/importing-extensions' }, - { label: 'Using MCP servers, skills & extensions', slug: 'guides/mcp-skills-extensions' }, + { + label: 'Run experiments', + items: [ + { label: 'Submit from the Portal', slug: 'guides/submitting-requests-portal' }, + { label: 'Submit from the CLI', slug: 'guides/submitting-requests-cli' }, + { label: 'Submit through the API', slug: 'guides/submitting-requests-api' }, + { label: 'Prioritize & pause', slug: 'guides/prioritizing-requests' }, + ], + }, + { + label: 'Design your benchmark', + collapsed: true, + items: [ + { label: 'Task prompts', slug: 'guides/managing-task-prompts' }, + { label: 'Evaluation criteria', slug: 'guides/defining-criteria' }, + { label: 'Agent profiles', slug: 'guides/defining-profiles' }, + { label: 'Prompt features', slug: 'guides/prompt-features' }, + { label: 'Choose a coding agent', slug: 'guides/choosing-a-coding-agent' }, + { label: 'Software stacks', slug: 'guides/software-stacks' }, + ], + }, + { + label: 'Connect tools & skills', + collapsed: true, + items: [ + { label: 'Import MCP servers', slug: 'guides/importing-mcp-servers' }, + { label: 'Import skills', slug: 'guides/importing-skills' }, + { label: 'Import VS Code extensions', slug: 'guides/importing-extensions' }, + { label: 'Use tools, skills & extensions', slug: 'guides/mcp-skills-extensions' }, + ], + }, ], }, { label: 'Reference', + collapsed: true, items: [ { label: 'REST API overview', slug: 'reference/rest-api' }, { label: 'Profile schema', slug: 'reference/profile-schema' }, @@ -124,6 +148,7 @@ export default defineConfig({ ...openAPISidebarGroups, { label: 'Resources', + collapsed: true, items: [ { label: 'FAQ', slug: 'resources/faq' }, { label: 'Data collection and privacy', slug: 'resources/data-collection' }, diff --git a/website/src/components/FlowDemo.astro b/website/src/components/FlowDemo.astro new file mode 100644 index 000000000..68b942c36 --- /dev/null +++ b/website/src/components/FlowDemo.astro @@ -0,0 +1,95 @@ +--- +import { sampleAgents } from '../scripts/sample-agents'; + +const stages = ['Define a scenario', 'Run the agents', 'Evaluate the work', 'Explore the results']; +const rowHeight = 96; +const rowGap = 12; +const graphHeight = sampleAgents.length * rowHeight + (sampleAgents.length - 1) * rowGap; +const center = graphHeight / 2; +const incoming = sampleAgents.map((_, index) => { + const y = index * (rowHeight + rowGap) + rowHeight / 2; + const direction = Math.sign(y - center); + return direction === 0 ? `M210 ${center} H270` + : `M210 ${center} H228 Q240 ${center} 240 ${center + direction * 12} V${y - direction * 12} Q240 ${y} 252 ${y} H270`; +}).join(' '); +const outgoing = sampleAgents.map((_, index) => { + const y = index * (rowHeight + rowGap) + rowHeight / 2; + const direction = Math.sign(center - y); + return direction === 0 ? `M490 ${center} H550` + : `M490 ${y} H508 Q520 ${y} 520 ${y + direction * 12} V${center - direction * 12} Q520 ${center} 532 ${center} H550`; +}).join(' '); +const wires = [incoming, outgoing, `M770 ${center} H830`]; +--- + + +
+
Scope playgroundSimulated
+ +
+
+
EXPERIMENT / task-board{sampleAgents.length} sample profiles / same criteria
+
+ +
+ +
+ {sampleAgents.map((agent) => ( + + ))} +
+ + +
+
+
+
+
+
+ {stages.map((stage, index) => )} +
+
+
+
Step 01 / Define

Give every agent the same starting line.

Create a task board with add, complete, and filter actions. Define the expected behavior before the agents start.

+
+ TASK PROMPT / EXAMPLE +

Build a task board. Users can add tasks, mark them complete, and filter by status. An empty title must not create a task.

+
+
+

Illustrative demo only. No agents are running. Agent names are examples, not a list of supported Scope integrations. These are not real scores or usage rankings. Select any step to explore.

+

+ +
+ + diff --git a/website/src/components/Header.astro b/website/src/components/Header.astro new file mode 100644 index 000000000..b54c273f3 --- /dev/null +++ b/website/src/components/Header.astro @@ -0,0 +1,32 @@ +--- +import DefaultHeader from '@astrojs/starlight/components/Header.astro'; +import Search from '@astrojs/starlight/components/Search.astro'; +import ThemeSelect from '@astrojs/starlight/components/ThemeSelect.astro'; +import SiteTitle from './SiteTitle.astro'; + +const isHome = Astro.locals.starlightRoute.entry.id === ''; +const base = import.meta.env.BASE_URL.replace(/\/?$/, '/'); +--- + +{isHome ? ( +
+ + +
+
+) : } + + diff --git a/website/src/components/Home.astro b/website/src/components/Home.astro new file mode 100644 index 000000000..e9235b052 --- /dev/null +++ b/website/src/components/Home.astro @@ -0,0 +1,118 @@ +--- +import FlowDemo from './FlowDemo.astro'; + +const base = import.meta.env.BASE_URL.replace(/\/?$/, '/'); +const paths = [ + { + number: '01', + title: 'Start in the Portal', + description: 'Get access, submit your first task, and follow the results in your browser.', + href: 'getting-started/first-run/', + label: 'Your first run', + tag: 'New to Scope', + }, + { + number: '02', + title: 'Work from your terminal', + description: 'Install the CLI and make benchmarks part of your development workflow.', + href: 'getting-started/install-cli/', + label: 'Set up the CLI', + tag: 'For developers', + }, + { + number: '03', + title: 'Build it into your tools', + description: 'Explore request examples and the searchable, generated API reference.', + href: 'reference/rest-api/', + label: 'Explore the API', + tag: 'For integrations', + }, +]; +--- + +
+
+
The agentic experience, measured
+

Your product.
Their agents. The whole picture.

+

+ How do coding agents really handle your product? Give them the same + task, define what good looks like, and see the evidence. That's Scope. +

+ +

Your tasks. Your criteria. Repeatable experiments.

+
+ Built to evaluate + GitHub Copilot + + Claude Code + Meet the agents +
+
+ +
+
+

From a prompt to a picture

One task. Follow every step.

+
+ +
+ +
+
+

Beyond a pass or fail

Find the why behind the result.

+

A score is a starting point. Understand the task, the setup, and the path an agent took.

+
+ +
+ +
+
+

Make your next move

Less searching. More building.

+ Learn the core concepts +
+ + +
+ +
+

Bring your own question

+

What will your next
benchmark reveal?

+

Start with one task you care about. Scope helps you see the rest.

+ Get started + You'll need access to a Scope deployment. No account is needed for this demo. +
+ +
diff --git a/website/src/components/PageTitle.astro b/website/src/components/PageTitle.astro new file mode 100644 index 000000000..91e2e2eb8 --- /dev/null +++ b/website/src/components/PageTitle.astro @@ -0,0 +1,7 @@ +--- +import DefaultPageTitle from '@astrojs/starlight/components/PageTitle.astro'; +--- + +{Astro.locals.starlightRoute.entry.id === '' + ? + : } diff --git a/website/src/components/SiteTitle.astro b/website/src/components/SiteTitle.astro index f49dc076e..b6482220e 100644 --- a/website/src/components/SiteTitle.astro +++ b/website/src/components/SiteTitle.astro @@ -14,9 +14,6 @@ const { siteTitle, siteTitleHref } = Astro.locals.starlightRoute; role="img" aria-label={config.logo?.alt} > - {/* Single ECG pulse. It stays put; its amplitude - oscillates low <-> high around the baseline, so the - wave "beats" without moving sideways. */} diff --git a/website/src/content/docs/getting-started/install-cli.md b/website/src/content/docs/getting-started/install-cli.md index 1cb38a3a2..5c7f164a2 100644 --- a/website/src/content/docs/getting-started/install-cli.md +++ b/website/src/content/docs/getting-started/install-cli.md @@ -26,9 +26,8 @@ This downloads and installs the latest release to `SCOPE_INSTALL_DIR` environment variable: ```bash -SCOPE_INSTALL_DIR=~/bin \ - gh api repos/growth-ecosystems/scope-doc/contents/install-cli.sh \ - -H "Accept: application/vnd.github.raw" | bash +gh api repos/growth-ecosystems/scope-doc/contents/install-cli.sh \ + -H "Accept: application/vnd.github.raw" | SCOPE_INSTALL_DIR=~/bin bash ``` ## Add to PATH diff --git a/website/src/content/docs/guides/prioritizing-requests.mdx b/website/src/content/docs/guides/prioritizing-requests.mdx index 1916af4a0..779b36220 100644 --- a/website/src/content/docs/guides/prioritizing-requests.mdx +++ b/website/src/content/docs/guides/prioritizing-requests.mdx @@ -30,7 +30,7 @@ queue position updates as soon as you save. The Portal exposes Priority is editable while a request is **pending** or **paused**. The exact endpoint shape (single vs bulk) is in the -[REST API reference](/reference/api/operations/). At a glance: +[REST API reference](/reference/api/). At a glance: - Single-request priority change. - Bulk priority change for a list of request IDs. diff --git a/website/src/content/docs/guides/submitting-requests-api.mdx b/website/src/content/docs/guides/submitting-requests-api.mdx index 2a1a533a1..1d7c18db8 100644 --- a/website/src/content/docs/guides/submitting-requests-api.mdx +++ b/website/src/content/docs/guides/submitting-requests-api.mdx @@ -25,7 +25,7 @@ https://your-scope.example.com/api-docs An auto-generated reference of every endpoint, built from the same OpenAPI spec, also lives in this site at -[REST API reference](/reference/api/operations/). +[REST API reference](/reference/api/). This page covers the common workflows. @@ -201,7 +201,7 @@ idempotency on top by caching the returned `id` if you need it. `profileId`) so a later edit to the profile doesn't change what your pipeline runs. - **Poll sparingly**: prefer the SSE log stream to status polling. -- **Use the reference**: the [REST API reference](/reference/api/operations/) +- **Use the reference**: the [REST API reference](/reference/api/) is the source of truth for exact request and response shapes. Your deployment may also provide Swagger UI at `/api-docs`. diff --git a/website/src/content/docs/index.mdx b/website/src/content/docs/index.mdx index d6095bf58..3aa222695 100644 --- a/website/src/content/docs/index.mdx +++ b/website/src/content/docs/index.mdx @@ -1,215 +1,10 @@ --- title: Scope -description: The benchmark for agentic coding. Measure how coding agents behave on your tasks — across agents, at scale. +description: See how coding agents handle your product. Run repeatable tasks, evaluate against your criteria, and understand what happened. template: splash tableOfContents: false --- -import { Card, CardGrid } from '@astrojs/starlight/components'; +import Home from '../../components/Home.astro'; -
- -{/* ============================ HERO ============================ */} -
-
-

Evaluate the agentic experience of your products

- -

- Run one scenario across GitHub Copilot, Claude Code, and VS Code. - Score every run against criteria you define, and see how your - agentic experience holds up across all of them — at scale. -

- - -
- - {/* Static "scenario coverage" proof panel */} - -
- -{/* ============================ HOW IT WORKS ============================ */} -
-
- How it works -

One task, every agent, measured the same way

-

Scope submits your task to each agent, scores every run against the criteria you define, and lines the results up side by side.

-
- -
-
- 01 -

Submit a task

-

Hand one coding task to GitHub Copilot, Claude Code, or VS Code with the Copilot driver extension — with the profile you want.

-
-
- 02 -

Score against criteria

-

Each run is evaluated against your criteria DAG. Gate child criteria on their parents, or leave them as independent roots.

-
-
- 03 -

Compare trajectories

-

See not just whether it worked, but how each agent got there — the tools it reached for and where it got stuck.

-
-
-
- -{/* ============================ FEATURES ============================ */} -
-
- What you can do -

Not “did it work?” — how did it get there?

-

Scope drives existing agents against tasks you control, then captures what they asked for, what tools they reached for, and where they got stuck.

-
- -
-
- 01 -

Submit a coding task

-

Hand a task to GitHub Copilot, Claude Code, or VS Code with the Copilot driver extension.

-
-
- 02 -

Save reusable profiles

-

Bundle worker, model, version, MCP servers, skills, and extensions to re-run a setup consistently.

-
-
- 03 -

Define criteria as a DAG

-

Describe what “good” means. Gate child criteria on their parents, or leave them as independent roots.

-
-
- 04 -

Watch runs live

-

Stream logs straight from the worker as each run executes, attempt by attempt.

-
-
- 05 -

Slice with prompt features

-

Scope detects characteristics on your prompts so you can compare across heterogeneous tasks.

-
-
- 06 -

Automate everything

-

Submit runs, manage profiles and criteria, and fetch results through the REST API or the CLI.

-
-
-
- -{/* ============================ CHANNELS ============================ */} -
-
- Three ways to drive it -

Portal, REST API, or CLI

-
- -
-
- Point & click -

Portal

-

Submit requests, configure profiles and criteria, and watch runs stream — all from the browser.

- Submit from the Portal → -
-
- Integrate -

REST API

-

Wire Scope into your pipelines and tooling with a single authenticated request.

- Read the API guide → -
-
- Terminal -

CLI

-

Run benchmarks from the terminal with real-time log streaming.

- Install the CLI → -
-
-
- -{/* ============================ DOCS ============================ */} -
-
- Documentation -

Explore the docs

-
- - - - Understand what Scope measures and when to reach for it. [Read the introduction](/introduction/what-is-scope/). - - - Run a task end to end from the Portal in a few minutes. [Get started](/getting-started/first-run/). - - - Automate request submission and integrate Scope into your tools. [API guide](/guides/submitting-requests-api/). - - - Endpoint reference, configuration schemas, and worker capabilities. [Browse the reference](/reference/rest-api/). - - -
- -{/* ============================ CTA ============================ */} -
-

Stop guessing which agent is better. Measure it.

-

Spin up your first benchmark in minutes — from the Portal, the API, or the CLI.

- -
- -
+ diff --git a/website/src/content/docs/reference/rest-api.md b/website/src/content/docs/reference/rest-api.md index 4da51a13b..0176a117c 100644 --- a/website/src/content/docs/reference/rest-api.md +++ b/website/src/content/docs/reference/rest-api.md @@ -6,7 +6,7 @@ description: Overview of the Scope REST API and pointer to the auto-generated en The Scope REST API mirrors what you can do in the Portal and the `scope` CLI. The full per-endpoint reference is **auto-generated from the committed OpenAPI snapshot** and lives under -[REST API reference](/reference/api/operations/). +[REST API reference](/reference/api/). For interactive exploration, your deployment may provide Swagger UI and a raw OpenAPI document: @@ -75,7 +75,7 @@ Generate and fetch per-request evaluation reports. The API also exposes `agents`, `models`, `mcp-servers`, `skills`, `extensions`, `insights`, and `report-templates`. See the generated -[REST API reference](/reference/api/operations/) for endpoint-level +[REST API reference](/reference/api/) for endpoint-level details. ## Request status & outcome @@ -118,5 +118,5 @@ published reference. ## See also -- [REST API reference (auto-generated)](/reference/api/operations/) +- [REST API reference (auto-generated)](/reference/api/) - [Submitting requests (REST API)](/guides/submitting-requests-api/) diff --git a/website/src/content/docs/resources/faq.md b/website/src/content/docs/resources/faq.md index 1e3828a05..4f59149b7 100644 --- a/website/src/content/docs/resources/faq.md +++ b/website/src/content/docs/resources/faq.md @@ -77,6 +77,6 @@ profiles, and more — all from the terminal. See ## Where's the API reference? -The auto-generated [REST API reference](/reference/api/operations/) is +The auto-generated [REST API reference](/reference/api/) is built from the committed OpenAPI snapshot. A narrative overview of the resource groups is at the [REST API overview](/reference/rest-api/). diff --git a/website/src/content/docs/resources/glossary.md b/website/src/content/docs/resources/glossary.md index 4b6b6a3e1..e1cfefad0 100644 --- a/website/src/content/docs/resources/glossary.md +++ b/website/src/content/docs/resources/glossary.md @@ -6,7 +6,7 @@ description: Definitions of the core Scope concepts. ## Request What you submit to Scope. A request bundles a task prompt, a -criteria set, and a profile (or inline runtime configuration). MS +criteria graph, and a profile (or inline runtime configuration). Scope creates one or more runs per request. See [Submitting requests (Portal)](/guides/submitting-requests-portal/). @@ -19,17 +19,18 @@ new run on the same request. Logs and reports are produced per run. ## Task prompt The text instructions sent to the agent. Stored in a shared catalog, -de-duplicated by text: when you submit a request with task text MS +de-duplicated by text: when you submit a request with task text Scope has seen before, the request links to the existing record -rather than creating a duplicate. The entity prompt-feature detection -runs against. See [Managing task prompts](/guides/managing-task-prompts/). +rather than creating a duplicate. Prompt-feature detection runs +against this text. See [Managing task prompts](/guides/managing-task-prompts/). ## Criteria / Criterion A criterion is a single, observable statement the judge evaluates the -run's output against. A **criteria set** is a named, reusable -collection of criteria, optionally arranged as a DAG. Referenced from -a request by ID. See [Defining evaluation criteria](/guides/defining-criteria/). +run's output against. Criteria form a **directed acyclic graph (DAG)**. +Each criterion can depend on other criteria; a criterion without +dependencies is a root of the graph. See +[Defining evaluation criteria](/guides/defining-criteria/). ## Judge @@ -56,8 +57,7 @@ code, skill commits, and extension versions. ## Worker -The runtime that drives an AI coding agent during a run. Scope -ships three workers — see +The runtime that drives an AI coding agent during a run. See [Coding agents & capabilities](/reference/workers/). ## ACP (Agent Client Protocol) @@ -79,8 +79,8 @@ commit hash so re-runs are reproducible. ## Extension -A VS Code extension installed for the duration of a run. Only the VS -VS Code Copilot coding agent supports extensions. +A VS Code extension installed for the duration of a run. See +[Coding agents & capabilities](/reference/workers/) for compatibility. ## Prompt feature diff --git a/website/src/plugins/remark-base-links.mjs b/website/src/plugins/remark-base-links.mjs new file mode 100644 index 000000000..667cd1cd6 --- /dev/null +++ b/website/src/plugins/remark-base-links.mjs @@ -0,0 +1,28 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +import { visit } from 'unist-util-visit'; + +/** Keep authored root-relative documentation links under the Pages project base. */ +export default function remarkBaseLinks({ base = '/' } = {}) { + const prefix = `/${base.split('/').filter(Boolean).join('/')}`; + const withBase = (url) => { + if (prefix === '/' || !url.startsWith('/') || url.startsWith('//')) return url; + if (url === prefix || url.startsWith(`${prefix}/`)) return url; + return `${prefix}${url}`; + }; + return (tree) => { + visit(tree, (node) => { + if (node.type === 'link' || node.type === 'definition' || node.type === 'image') { + node.url = withBase(node.url); + } + if (node.type === 'mdxJsxFlowElement' || node.type === 'mdxJsxTextElement') { + for (const attribute of node.attributes) { + if (attribute.type === 'mdxJsxAttribute' && ['href', 'src'].includes(attribute.name) && typeof attribute.value === 'string') { + attribute.value = withBase(attribute.value); + } + } + } + }); + }; +} diff --git a/website/src/scripts/flow-demo.ts b/website/src/scripts/flow-demo.ts new file mode 100644 index 000000000..9bf2c936b --- /dev/null +++ b/website/src/scripts/flow-demo.ts @@ -0,0 +1,228 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +import { sampleAgents, type SampleProfile } from './sample-agents'; + +interface DemoScenario { + id: string; + title: string; + short: string; + prompt: string; + edge: string; + context: string; + passedCriteria: Record; +} + +const scenarios: Record = { + board: { + id: 'task-board', + title: 'Build a task board', + short: 'A small app. Real acceptance criteria.', + prompt: 'Build a task board. Users can add tasks, mark them complete, and filter by status. An empty title must not create a task.', + edge: 'Handles empty input', + context: 'Create a task board with add, complete, and filter actions. Define the expected behavior before the agents start.', + passedCriteria: { A: 3, B: 1, C: 2, D: 3, E: 0 }, + }, + api: { + id: 'search-api', + title: 'Add a search API', + short: 'One endpoint. The details matter.', + prompt: 'Add a paginated search endpoint. Return matching items, validate the page size, and return an empty list when nothing matches.', + edge: 'Handles no matches', + context: 'Add search with pagination and input validation. Give every sample profile the same task and the same acceptance criteria.', + passedCriteria: { A: 1, B: 3, C: 3, D: 0, E: 2 }, + }, +}; + +const headings = [ + 'Give every agent the same starting line.', + 'Different agents. A repeatable setup.', + 'Success has a dependency graph.', + 'The result is only the beginning.', +]; + +class ScopeFlow extends HTMLElement { + private stage = 0; + private scenario = scenarios.board; + private timer: ReturnType | undefined; + private playing = false; + private observer: IntersectionObserver | undefined; + private events: AbortController | undefined; + private motion = window.matchMedia('(prefers-reduced-motion: reduce)'); + private visible = false; + private interacted = false; + + connectedCallback() { + this.events = new AbortController(); + const { signal } = this.events; + this.querySelectorAll('button, select').forEach((control) => { control.disabled = false; }); + this.addEventListener('click', (event) => { + if (!(event.target instanceof Element)) return; + const button = event.target.closest('button'); + if (!button) return; + this.interacted = true; + if (button.hasAttribute('data-play')) { + if (this.motion.matches) { + this.stop(); + this.stage = (this.stage + 1) % 4; + this.render(); + } else if (this.playing) { + this.stop(); + } else { + if (this.stage === 3) this.stage = 0; + this.playing = true; + this.render(); + this.schedule(); + } + } else if (button.hasAttribute('data-reset')) { + this.stop(); + this.stage = 0; + this.render(); + } else { + const step = button.dataset.step ?? button.dataset.node; + if (step !== undefined) { + this.stop(); + this.stage = Number(step); + this.render(); + } + } + }, { signal }); + this.querySelector('select')?.addEventListener('change', (event) => { + if (!(event.target instanceof HTMLSelectElement)) return; + const scenario = scenarios[event.target.value]; + if (!scenario) throw new Error('Unknown Scope demo scenario'); + this.interacted = true; + this.stop(); + this.scenario = scenario; + this.stage = 0; + this.render(); + }, { signal }); + this.motion.addEventListener('change', () => this.stop(), { signal }); + document.addEventListener('visibilitychange', () => { + if (document.hidden) this.stop(); + }, { signal }); + this.observer = new IntersectionObserver(([entry]) => { + this.visible = entry.isIntersecting; + if (!this.visible) { + this.stop(); + } else if (!this.interacted && !this.motion.matches && !document.hidden) { + this.interacted = true; + this.playing = true; + this.render(); + this.schedule(); + } + }, { threshold: 0.25 }); + this.observer.observe(this); + this.render(false); + } + + disconnectedCallback() { + clearTimeout(this.timer); + this.observer?.disconnect(); + this.events?.abort(); + } + + private schedule() { + clearTimeout(this.timer); + if (!this.playing || !this.visible || document.hidden) return; + this.timer = setTimeout(() => { + this.stage += 1; + if (this.stage === 3) this.playing = false; + this.render(); + if (this.playing) this.schedule(); + }, 2400); + } + + private stop() { + clearTimeout(this.timer); + this.playing = false; + this.render(false); + } + + private text(selector: string, value: string) { + const element = this.querySelector(selector); + if (!element) throw new Error(`Missing Scope demo element: ${selector}`); + element.textContent = value; + } + + private render(announce = true) { + this.dataset.stage = String(this.stage); + this.dataset.playing = String(this.playing); + this.text('[data-experiment]', this.scenario.id); + this.text('[data-task-title]', this.scenario.title); + this.text('[data-task-short]', this.scenario.short); + this.text('[data-edge-label]', this.scenario.edge); + this.text('[data-play]', this.motion.matches ? (this.stage === 3 ? 'Start again' : 'Next step') : this.playing ? 'Pause demo' : this.stage === 3 ? 'Replay demo' : this.stage === 0 ? 'Play demo' : 'Resume demo'); + this.querySelectorAll('[data-step], [data-node]').forEach((element) => { + const index = Number(element.dataset.step ?? element.dataset.node); + if (index === this.stage) element.setAttribute('aria-current', 'step'); + else element.removeAttribute('aria-current'); + element.dataset.complete = String(index < this.stage); + }); + this.querySelectorAll('[data-wire]').forEach((element) => { + element.dataset.active = String(Number(element.dataset.wire) <= this.stage); + }); + this.querySelectorAll('[data-agent-status]').forEach((element) => { + element.textContent = this.stage === 0 ? 'Ready' : this.stage === 1 ? 'Working' : 'Complete'; + }); + this.text('[data-stage-label]', `Step 0${this.stage + 1} / ${['Define', 'Execute', 'Evaluate', 'Understand'][this.stage]}`); + this.text('[data-detail-title]', headings[this.stage]); + this.text('[data-detail-body]', [ + this.scenario.context, + 'Each sample profile brings its own agent configuration. In Scope, profiles capture the setup; logs and iterations show the work.', + 'In this example, tests depend on a successful build, and the edge-case criterion depends on passing tests. A failed parent leaves its child skipped.', + 'Inspect criterion feedback rather than choosing an agent from a single score. These invented outcomes only demonstrate how to read the evidence.', + ][this.stage]); + const panel = this.querySelector('[data-detail-panel]'); + if (!panel) throw new Error('Missing Scope demo detail panel'); + panel.replaceChildren(); + if (this.stage === 0) { + this.appendText(panel, 'span', 'TASK PROMPT / EXAMPLE', 'flow-code-label'); + this.appendText(panel, 'p', this.scenario.prompt); + } else if (this.stage === 1) { + this.appendText(panel, 'span', 'SIMULATED ACTIVITY', 'flow-code-label'); + for (const line of ['01 Load task and profile configuration', '02 Agent edits the workspace', '03 Capture logs and iteration evidence']) { + this.appendText(panel, 'p', line, 'flow-log-line'); + } + } else { + const table = document.createElement('table'); + table.className = 'flow-results'; + const caption = table.createCaption(); + caption.textContent = 'Invented criterion outcomes, not an agent comparison'; + const row = table.createTHead().insertRow(); + for (const label of ['Sample agent', 'Builds', 'Tests pass', this.scenario.edge]) { + const cell = document.createElement('th'); + cell.scope = 'col'; + cell.textContent = label; + row.append(cell); + } + const body = table.createTBody(); + for (const agent of sampleAgents) { + const row = body.insertRow(); + const header = document.createElement('th'); + header.scope = 'row'; + this.appendText(header, 'span', agent.name); + this.appendText(header, 'span', `Profile ${agent.profile}`, 'flow-result-profile'); + row.append(header); + for (let index = 0; index < 3; index += 1) { + const passed = this.scenario.passedCriteria[agent.profile]; + const state = index < passed ? 'Pass' : index === passed ? 'Fail' : 'Skipped'; + const cell = row.insertCell(); + cell.textContent = state; + cell.dataset.result = state.toLowerCase(); + } + } + panel.append(table); + } + if (announce) this.text('[data-announcement]', `${this.scenario.title}. Step ${this.stage + 1} of 4. ${headings[this.stage]}${this.stage === 3 ? ' Demo complete. Results are fictional.' : ''}`); + } + + private appendText(parent: Element, tag: 'span' | 'p', text: string, className?: string) { + const element = document.createElement(tag); + element.textContent = text; + if (className) element.className = className; + parent.append(element); + } +} + +if (!customElements.get('scope-flow')) customElements.define('scope-flow', ScopeFlow); diff --git a/website/src/scripts/sample-agents.ts b/website/src/scripts/sample-agents.ts new file mode 100644 index 000000000..9210dc818 --- /dev/null +++ b/website/src/scripts/sample-agents.ts @@ -0,0 +1,13 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +// Illustrative roster, not a ranking or a list of supported Scope workers. +export const sampleAgents = [ + { profile: 'A', name: 'GitHub Copilot', initial: 'G' }, + { profile: 'B', name: 'Claude Code', initial: 'C' }, + { profile: 'C', name: 'Cursor', initial: 'Cu' }, + { profile: 'D', name: 'OpenAI Codex', initial: 'Co' }, + { profile: 'E', name: 'OpenCode', initial: 'O' }, +] as const; + +export type SampleProfile = typeof sampleAgents[number]['profile']; diff --git a/website/src/styles/landing.css b/website/src/styles/landing.css index dd2975839..20c98f037 100644 --- a/website/src/styles/landing.css +++ b/website/src/styles/landing.css @@ -3,523 +3,223 @@ * Licensed under the MIT License. */ -/* - * Scope — documentation landing (splash) styles. - * - * A professional, theme-aware design system for a developer-tool - * benchmark. Everything is driven by a small set of semantic tokens - * (surface / border / text / brand) that flip between light and dark, - * so the whole page inverts from one place. Neutral slate ramp, a - * single indigo brand accent, and green reserved for the "pass / score" - * semantic. No decorative motion — just type, space, and hairlines. - * - * Scoped via `:has(.scope-home)` so interior doc pages are untouched. - */ - -/* ================================================================ * - * 1. Design tokens - * ================================================================ */ - -html:has(.scope-home) { - /* Spacing scale (8px base) */ - --sp-1: 0.25rem; - --sp-2: 0.5rem; - --sp-3: 0.75rem; - --sp-4: 1rem; - --sp-6: 1.5rem; - --sp-8: 2rem; - --sp-12: 3rem; - --sp-16: 4rem; - - /* Radii */ - --r-sm: 0.5rem; - --r-md: 0.75rem; - --r-lg: 1rem; - --r-xl: 1.25rem; - - /* Type family: fast, high-quality system stack tuned like Inter */ - --font-display: 'Inter', ui-sans-serif, system-ui, -apple-system, - 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif; - - background-color: var(--bg); -} - -/* Dark (default + explicit dark toggle) */ -html:has(.scope-home):not([data-theme='light']) { - color-scheme: dark; - - --bg: #0b0e16; - --surface: #10141f; - --surface-2: #151b28; - --border: rgba(255, 255, 255, 0.09); - --border-strong: rgba(255, 255, 255, 0.16); - --text: #e7eaf1; - --text-muted: rgba(231, 234, 241, 0.62); - --text-faint: rgba(231, 234, 241, 0.42); - - --brand: #8b95ff; /* indigo-400-ish, reads on dark */ - --brand-strong: #a5adff; - --ok: #4ade80; /* pass / score green */ - --warn: #fbbf24; - --fail: #f87171; - --on-brand: #0b0e16; - - /* Starlight dark chrome tokens */ - --sl-color-white: hsl(0, 0%, 100%); - --sl-color-gray-1: hsl(224, 20%, 94%); - --sl-color-gray-2: hsl(224, 8%, 79%); - --sl-color-gray-3: hsl(224, 7%, 58%); - --sl-color-gray-4: hsl(224, 8%, 38%); - --sl-color-gray-5: hsl(224, 12%, 24%); - --sl-color-gray-6: hsl(224, 15%, 16%); - --sl-color-gray-7: hsl(224, 18%, 12%); - --sl-color-black: hsl(224, 20%, 8%); - - --sl-color-accent-low: hsl(234, 54%, 22%); - --sl-color-accent: hsl(234, 90%, 66%); - --sl-color-accent-high: hsl(234, 100%, 86%); - - --sl-color-text: var(--sl-color-gray-2); - --sl-color-text-accent: var(--sl-color-accent-high); - --sl-color-bg: var(--bg); - --sl-color-bg-nav: transparent; - --sl-color-bg-sidebar: var(--sl-color-gray-6); - --sl-color-bg-inline-code: var(--sl-color-gray-5); - --sl-color-hairline-light: var(--sl-color-gray-5); - --sl-color-hairline-shade: var(--bg); -} - -/* Light toggle */ -html[data-theme='light']:has(.scope-home) { - color-scheme: light; - - --bg: #ffffff; - --surface: #ffffff; - --surface-2: #f8fafc; - --border: rgba(15, 23, 42, 0.1); - --border-strong: rgba(15, 23, 42, 0.18); - --text: #0f172a; - --text-muted: rgba(15, 23, 42, 0.62); - --text-faint: rgba(15, 23, 42, 0.42); - - --brand: #4f46e5; /* indigo-600 */ - --brand-strong: #4338ca; - --ok: #16a34a; - --warn: #d97706; - --fail: #dc2626; - --on-brand: #ffffff; - - --sl-color-bg: var(--bg); - --sl-color-bg-nav: transparent; -} - -/* ================================================================ * - * 2. Canvas + Starlight chrome - * ================================================================ */ - -body:has(.scope-home) { background: var(--bg) !important; } - -body:has(.scope-home) .page, -body:has(.scope-home) .main-frame, -body:has(.scope-home) .main-pane, -body:has(.scope-home) .content-panel { - background: transparent !important; -} - -/* hide Starlight's auto-generated page title on the landing route only */ -body:has(.scope-home) .content-panel:has(> .sl-container > h1#_top) { - display: none; -} - -body:has(.scope-home) header.header { - background: color-mix(in oklch, var(--bg) 82%, transparent); - backdrop-filter: saturate(140%) blur(12px); - border-bottom: 1px solid var(--border); -} - -.scope-home { - overflow-x: clip; - font-family: var(--font-display); - color: var(--text); -} -.scope-home > :first-child { margin-top: 0; } - -/* ================================================================ * - * 3. Shared primitives - * ================================================================ */ - -.scope-btn { - display: inline-flex; - align-items: center; - gap: var(--sp-2); - padding: 0.72rem 1.3rem; - border-radius: var(--r-sm); - font-size: 0.95rem; - font-weight: 600; - line-height: 1; - text-decoration: none; - border: 1px solid transparent; - transition: background 0.15s ease, border-color 0.15s ease, - color 0.15s ease, transform 0.15s ease, box-shadow 0.15s ease; -} - -.scope-btn svg { width: 1.05rem; height: 1.05rem; } - -.scope-btn--primary { - color: var(--on-brand); - background: var(--brand); - box-shadow: 0 1px 2px rgba(15, 23, 42, 0.12); -} -.scope-btn--primary:hover { - background: var(--brand-strong); - transform: translateY(-1px); - box-shadow: 0 8px 24px -10px var(--brand); -} - -.scope-btn--ghost { - color: var(--text); - border-color: var(--border-strong); - background: var(--surface); -} -.scope-btn--ghost:hover { border-color: var(--brand); color: var(--brand); } - -/* ================================================================ * - * 4. HERO - * ================================================================ */ - -.scope-hero { - text-align: center; - padding: clamp(3rem, 8vw, 6rem) 0 0; -} - -.scope-hero__inner { max-width: 56rem; margin-inline: auto; } - -.scope-hero h1 { - margin: var(--sp-6) auto 0; - max-width: 18ch; - font-size: clamp(2.6rem, 6.5vw, 4.6rem); - line-height: 1.04; - letter-spacing: -0.032em; - font-weight: 700; - color: var(--text); -} - -.scope-hero h1 .grad { color: var(--brand); } - -.scope-hero .scope-subtitle { - margin: var(--sp-6) auto 0; - max-width: 46ch; - font-size: clamp(1.05rem, 2.1vw, 1.25rem); - line-height: 1.6; - color: var(--text-muted); -} - -.scope-actions { - display: flex; - flex-wrap: wrap; - gap: var(--sp-3); - justify-content: center; - margin-top: var(--sp-8); -} - -/* ---------------- Product proof panel ---------------- */ - -.scope-proof { - margin: clamp(3rem, 7vw, 4.5rem) auto 0; - max-width: 60rem; - border: 1px solid var(--border); - border-radius: var(--r-xl); - background: var(--surface); - box-shadow: 0 24px 60px -40px rgba(15, 23, 42, 0.55); - overflow: hidden; - text-align: left; -} - -.scope-proof__bar { - display: flex; - align-items: center; - gap: var(--sp-2); - padding: 0.7rem 1rem; - border-bottom: 1px solid var(--border); - background: var(--surface-2); -} - -.scope-proof__dots { display: flex; align-items: center; gap: 0.5rem; } -.scope-proof__dots i { - width: 0.72rem; height: 0.72rem; border-radius: 999px; - margin: 0; - background: var(--border-strong); - box-shadow: inset 0 0 0 0.5px rgba(0, 0, 0, 0.18); -} -/* macOS traffic lights: close / minimize / zoom */ -.scope-proof__dots i:nth-child(1) { background: #ff5f57; } -.scope-proof__dots i:nth-child(2) { background: #febc2e; } -.scope-proof__dots i:nth-child(3) { background: #28c840; } -.scope-proof__title { - margin-left: var(--sp-2); - font-family: var(--sl-font-mono, monospace); - font-size: 0.74rem; - color: var(--text-faint); -} -.scope-proof__run { - margin-left: auto; - font-family: var(--sl-font-mono, monospace); - font-size: 0.7rem; - color: var(--text-muted); -} - -.scope-board { - display: grid; - grid-template-columns: repeat(3, 1fr); - gap: 0; +:root { + --sl-font: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; + --sl-font-mono: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; + --sl-color-accent-low: #202453; + --sl-color-accent: #7778ee; + --sl-color-accent-high: #c2c5ff; + --scope-bg: #0e111b; + --scope-surface: #161a27; + --scope-inset: #111521; + --scope-text: #f0f1f8; + --scope-muted: #a7afc5; + --scope-border: #303749; + --scope-brand: #b1b4ff; + --scope-brand-fill: #b1b4ff; + --scope-on-brand: #171a36; + --scope-pass: #83dcb0; + --scope-fail: #ffa498; + --scope-shadow: 0 24px 70px -36px #0009; +} +:root[data-theme='light'] { + --sl-color-accent-low: #eeedff; + --sl-color-accent: #514bc5; + --sl-color-accent-high: #36318a; + --scope-bg: #fafbfdfc; + --scope-surface: #ffffff; + --scope-inset: #f3f5fa; + --scope-text: #171c30; + --scope-muted: #576079; + --scope-border: #dce0eb; + --scope-brand: #5048bd; + --scope-brand-fill: #514ac6; + --scope-on-brand: #ffffff; + --scope-pass: #16754c; + --scope-fail: #af352c; + --scope-shadow: 0 24px 70px -36px #30376240; +} + +/* Keep the reading experience native to Starlight, with shared brand accents. */ +header.header { border-bottom-color: var(--scope-border); } +body:not(:has(.scope-home)) .sidebar-content a[aria-current='page'] { border-radius: 0.4rem; } +body:not(:has(.scope-home)) .sl-markdown-content { line-height: 1.8; } +body:not(:has(.scope-home)) .pagination-links a { border-radius: 0.75rem; } +:focus-visible { outline: 3px solid var(--scope-brand); outline-offset: 4px; } + +html:has(.scope-home) { --sl-content-width: 78rem; --sl-color-bg: var(--scope-bg); --sl-color-bg-nav: var(--scope-bg); } +body:has(.scope-home) { background: var(--scope-bg); } +body:has(.scope-home) .content-panel:has([data-home-title-placeholder]) { display: none; } +body:has(.scope-home) .content-panel { border: 0; padding-top: 0; } +body:has(.scope-home) .sl-container { max-width: 78rem; } +body:has(.scope-home) header.header { background: color-mix(in srgb, var(--scope-bg) 94%, transparent); backdrop-filter: blur(14px); } +.scope-home { color: var(--scope-text); font-family: var(--sl-font); line-height: 1.6; } +.scope-home * { box-sizing: border-box; } +.scope-home :is(h1,h2,h3,p) { margin: 0; } +.scope-home a { text-decoration: none; } +.scope-home button, .scope-home select { font: inherit; } +.scope-home button { cursor: pointer; } +.scope-home button:disabled { cursor: default; opacity: 0.6; } +.scope-home :is(section, h2) { scroll-margin-top: 6rem; } +.scope-eyebrow { color: var(--scope-brand); font-size: 0.72rem; font-weight: 650; text-transform: uppercase; letter-spacing: 0.13em; } +.scope-signal { display: inline-block; width: 7px; height: 7px; border-radius: 50%; background: var(--scope-pass); box-shadow: 0 0 0 4px color-mix(in srgb, var(--scope-pass) 12%, transparent); } +.scope-hero { position: relative; padding: clamp(3rem, 6vw, 4.5rem) 1rem 0; text-align: center; } +.scope-hero::before { content: ''; position: absolute; inset: 0 -1rem; pointer-events: none; z-index: -1; background: radial-gradient(ellipse at 50% 24%, color-mix(in srgb, var(--scope-brand) 9%, transparent), transparent 65%); } +.scope-hero > .scope-eyebrow { display: inline-flex; gap: 0.8rem; align-items: center; padding: 0.4rem 0.85rem; border: 1px solid var(--scope-border); background: var(--scope-surface); border-radius: 100px; font-size: 0.65rem; } +.scope-hero h1 { margin: 1.7rem auto 1.3rem; max-width: 19ch; font-size: clamp(2.8rem, 5.7vw, 5rem); font-weight: 650; line-height: 1.08; letter-spacing: -0.06em; text-wrap: balance; } +.scope-hero h1 span { color: var(--scope-brand); } +.scope-hero .scope-subtitle { max-width: 57ch; margin: auto; color: var(--scope-muted); font-size: clamp(1rem, 1.5vw, 1.15rem); line-height: 1.75; text-wrap: pretty; } +.scope-actions { display: flex; flex-wrap: wrap; align-items: center; justify-content: center; gap: 0.75rem; margin-top: 1.8rem; } +.scope-btn { display: inline-flex; align-items: center; justify-content: center; gap: 0.7rem; min-height: 46px; padding: 0.65rem 1.2rem; border: 1px solid transparent; border-radius: 0.55rem; font-size: 0.875rem; font-weight: 600; line-height: 1.4; transition: background 180ms, box-shadow 180ms; white-space: nowrap; } +.scope-btn--primary { color: var(--scope-on-brand); background: var(--scope-brand-fill); box-shadow: 0 3px 7px #171a3612, inset 0 1px 0 #ffffff20; } +.scope-btn--primary:hover { background: color-mix(in srgb, var(--scope-brand-fill) 88%, var(--scope-text)); box-shadow: 0 4px 18px color-mix(in srgb, var(--scope-brand) 25%, transparent); } +.scope-btn--secondary { color: var(--scope-text); background: var(--scope-surface); border-color: var(--scope-border); } +.scope-btn--secondary:hover { background: var(--scope-inset); } +.scope-hero .scope-hero-note { margin-top: 1rem; color: var(--scope-muted); font-size: 0.75rem; } +.scope-agent-strip { display: flex; flex-wrap: wrap; justify-content: center; align-items: center; gap: 1.4rem; margin-top: 3.7rem; padding: 1.5rem 0; border-top: 1px solid var(--scope-border); border-bottom: 1px solid var(--scope-border); font-size: 0.8rem; } +.scope-agent-strip > span:first-child { color: var(--scope-muted); font-size: 0.75rem; } +.scope-agent-strip strong { font-size: 1rem; font-weight: 600; } +.scope-agent-strip a { color: var(--scope-brand); } +.scope-strip-divider { width: 1px; height: 1.1rem; background: var(--scope-border); } +.scope-section { margin-top: clamp(3.5rem, 7vw, 6rem); } +.scope-demo-section { margin-top: 3.5rem; } +.scope-section-heading { display: flex; justify-content: space-between; align-items: end; gap: 2rem; margin-bottom: 1.8rem; } +.scope-section-heading h2 { margin-top: 0.55rem; font-size: clamp(1.8rem, 3.3vw, 2.65rem); font-weight: 600; letter-spacing: -0.04em; line-height: 1.2; text-wrap: balance; } +.scope-section-heading > p { max-width: 33ch; font-size: 0.9rem; color: var(--scope-muted); } +.scope-text-link { display: inline-flex; align-items: center; justify-content: space-between; gap: 0.75rem; color: var(--scope-brand); font-size: 0.85rem; font-weight: 600; } +.scope-text-link:hover { text-decoration: underline; } + +/* The playground uses a custom element, without a client-side UI framework. */ +.scope-flow { display: block; border: 1px solid var(--scope-border); border-radius: 1rem; background: var(--scope-surface); box-shadow: var(--scope-shadow); overflow: clip; } +.flow-toolbar { display: flex; justify-content: space-between; align-items: center; gap: 1rem; padding: 1rem 1.5rem; border-bottom: 1px solid var(--scope-border); } +.flow-demo-label { display: flex; flex-wrap: wrap; gap: 0.75rem; align-items: center; font-size: 0.85rem; } +.flow-demo-badge { padding: 0.1rem 0.5rem; color: var(--scope-muted); background: var(--scope-inset); border: 1px solid var(--scope-border); border-radius: 4px; font-family: var(--sl-font-mono); font-size: 0.65rem; } +.flow-select-label { display: flex; align-items: center; gap: 0.75rem; color: var(--scope-muted); font-size: 0.75rem; } +.flow-select-label select { min-height: 44px; padding: 0.5rem 2rem 0.5rem 0.75rem; border: 1px solid var(--scope-border); border-radius: 0.4rem; background: var(--scope-surface); color: var(--scope-text); font-size: 0.8rem; cursor: pointer; max-width: 100%; } +.flow-canvas { position: relative; padding: 1.2rem 2rem 1.75rem; background-color: var(--scope-inset); background-image: radial-gradient(var(--scope-border) 0.8px, transparent 0.8px); background-size: 18px 18px; } +.flow-canvas-label { display: flex; justify-content: space-between; gap: 1rem; margin-bottom: 1.25rem; font: 0.62rem var(--sl-font-mono); letter-spacing: 0.06em; color: var(--scope-muted); } +.flow-graph { position: relative; } +.flow-connections { position: absolute; inset: 0; width: 100%; height: 100%; pointer-events: none; } +.flow-wire, .flow-packets { fill: none; stroke: var(--scope-border); stroke-width: 2; } +.flow-packets { stroke: var(--scope-brand); stroke-dasharray: 8 16; } +.flow-packets path { opacity: 0; } +.flow-packets path[data-active='true'] { opacity: 0.75; } +[data-playing='true'] .flow-packets path[data-active='true'] { animation: flow-travel 1s linear infinite; } +@keyframes flow-travel { to { stroke-dashoffset: -48; } } +.flow-nodes { position: relative; display: grid; grid-template-columns: 21% 22% 22% 17%; justify-content: space-between; align-items: center; height: var(--flow-graph-height); } +.flow-node { display: flex; flex-direction: column; text-align: left; gap: 0.5rem; min-width: 0; padding: 1rem; border: 1px solid var(--scope-border); border-radius: 0.65rem; background: var(--scope-surface); color: var(--scope-text); box-shadow: 0 3px 8px #11182706; transition: border-color 200ms, box-shadow 200ms; } +.flow-node:hover { border-color: var(--scope-brand); } +.flow-node[aria-current='step'] { border-color: var(--scope-brand); box-shadow: 0 0 0 3px color-mix(in srgb, var(--scope-brand) 13%, transparent), 0 8px 24px #1118270c; } +.flow-node[data-complete='true'] { border-color: color-mix(in srgb, var(--scope-pass) 45%, var(--scope-border)); } +.flow-node strong { font-size: 0.9rem; line-height: 1.3; letter-spacing: -0.025em; } +.flow-node > span:not([class]), .flow-node-tag { font-size: 0.7rem; color: var(--scope-muted); line-height: 1.5; } +.flow-node-kicker { display: block; color: var(--scope-muted); font-size: 0.6rem; text-transform: uppercase; letter-spacing: 0.06em; } +.flow-node-icon { display: grid; place-items: center; width: 30px; height: 30px; color: var(--scope-brand); background: color-mix(in srgb, var(--scope-brand) 9%, var(--scope-surface)); border: 1px solid color-mix(in srgb, var(--scope-brand) 18%, var(--scope-border)); border-radius: 7px; margin-bottom: 0.3rem; } +.flow-node-icon svg { width: 18px; height: 18px; fill: none; stroke: currentColor; stroke-width: 1.5; stroke-linejoin: round; stroke-linecap: round; } +.flow-node-tag { border-top: 1px solid var(--scope-border); padding-top: 0.65rem; margin-top: 0.3rem; width: 100%; } +.flow-agent-nodes { display: grid; grid-template-rows: repeat(var(--flow-agent-count), minmax(0, 1fr)); gap: var(--flow-agent-gap); height: 100%; } +.flow-agent { position: relative; display: grid; grid-template-columns: 24px 1fr; column-gap: 0.6rem; row-gap: 0.2rem; align-items: center; padding: 0.65rem 0.8rem; width: 100%; } +.flow-agent strong { font-size: 0.75rem; } +.flow-agent .flow-node-kicker { font-size: 0.55rem; margin-top: 0.3rem; } +.flow-agent-initial { display: grid; place-items: center; width: 24px; height: 24px; border-radius: 6px; background: var(--scope-inset); border: 1px solid var(--scope-border); color: var(--scope-brand); font: 600 0.75rem var(--sl-font-mono); } +.flow-agent-status { grid-column: 1 / -1; border-top: 1px solid var(--scope-border); padding-top: 0.4rem; color: var(--scope-muted); font: 0.62rem var(--sl-font-mono); } +[data-stage='1'] .flow-agent-status { color: var(--scope-brand); } +.flow-criteria { display: flex; flex-direction: column; align-items: start; margin-top: 0.25rem; width: 100%; font: 0.6rem var(--sl-font-mono); color: var(--scope-muted); } +.flow-criteria > span { padding: 0.3rem 0.5rem; border: 1px solid var(--scope-border); border-radius: 4px; background: var(--scope-inset); } +.flow-criteria i { width: 1px; height: 9px; background: var(--scope-brand); margin-left: 0.8rem; } +.flow-report { padding: 0.9rem; } +.flow-chart { display: flex; align-items: end; gap: 5px; height: 44px; padding: 5px 0 0; width: 100%; border-bottom: 1px solid var(--scope-border); } +.flow-chart i { flex: 1; height: 25%; background: var(--scope-border); border-radius: 2px 2px 0 0; transform-origin: bottom; transition: transform 500ms, background 500ms; } +.flow-chart i:nth-child(2) { height: 65%; }.flow-chart i:nth-child(3) { height: 45%; }.flow-chart i:nth-child(4) { height: 90%; }.flow-chart i:nth-child(5) { height: 75%; } +[data-stage='3'] .flow-chart i { background: var(--scope-brand); } +.flow-controls { display: flex; align-items: center; justify-content: space-between; gap: 1.25rem; padding: 1rem 1.5rem; border-block: 1px solid var(--scope-border); } +.flow-playback { display: flex; gap: 0.65rem; align-items: center; } +.flow-playback .scope-btn { min-width: 8.2rem; font-size: 0.75rem; min-height: 44px; } +.flow-reset { color: var(--scope-muted); border: 0; background: transparent; min-height: 44px; padding: 0.5rem; font-size: 0.75rem !important; } +.flow-reset:hover { color: var(--scope-brand); } +.flow-step-buttons { display: flex; gap: 0.5rem; } +.flow-step-buttons button { display: inline-flex; gap: 0.4rem; align-items: center; padding: 0.5rem 0.65rem; min-height: 44px; background: transparent; color: var(--scope-muted); border: 1px solid transparent; border-radius: 6px; font-size: 0.7rem; } +.flow-step-buttons button > span:first-child { font: 0.65rem var(--sl-font-mono); } +.flow-step-buttons button[aria-current='step'] { color: var(--scope-brand); border-color: var(--scope-border); background: var(--scope-inset); } +.flow-inspector { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 2.5rem; padding: 1.6rem; min-height: 237px; align-items: start; } +.flow-inspector h3 { margin: 0.6rem 0; font-size: 1.1rem; font-weight: 600; letter-spacing: -0.02em; line-height: 1.4; } +.flow-inspector-copy > p { color: var(--scope-muted); font-size: 0.82rem; } +.flow-detail-panel { padding: 1rem 1.1rem; border: 1px solid var(--scope-border); border-radius: 0.5rem; background: var(--scope-inset); font: 0.73rem/1.7 var(--sl-font-mono); min-height: 166px; } +.flow-code-label { display: block; font: 0.6rem var(--sl-font-mono); color: var(--scope-muted); letter-spacing: 0.07em; margin-bottom: 0.8rem; } +.flow-detail-panel .flow-log-line { margin-top: 0.5rem; } +.flow-results { border-collapse: collapse; width: 100%; font-size: 0.7rem; } +.flow-results caption { text-align: left; color: var(--scope-muted); font-size: 0.6rem; padding-bottom: 0.5rem; } +.flow-results :is(th, td) { padding: 0.35rem 0.25rem; text-align: left; border-bottom: 1px solid var(--scope-border); font-weight: 400; } +.flow-results thead th { color: var(--scope-muted); font-size: 0.6rem; } +.flow-result-profile { display: block; color: var(--scope-muted); font-size: 0.7rem; } +.flow-results [data-result='pass'] { color: var(--scope-pass); }.flow-results [data-result='fail'] { color: var(--scope-fail); }.flow-results [data-result='skipped'] { color: var(--scope-muted); } +.scope-home .flow-disclaimer { padding: 0 1.5rem 1rem; font-size: 0.68rem; color: var(--scope-muted); } +.scope-home :is(.flow-canvas-label, .flow-demo-badge, .flow-node-kicker, .flow-agent .flow-node-kicker, .flow-node-tag, .flow-criteria, .flow-agent-status, .flow-code-label, .flow-results, .flow-results caption, .flow-results thead th, .flow-step-buttons button, .flow-step-buttons button > span:first-child, .flow-disclaimer, .scope-path-top, .scope-profile-preview, .scope-trace-preview, .scope-mini-dag span, .scope-access-note) { font-size: 0.75rem; } +.flow-node > span:not([class]) { font-size: 0.75rem; } +.scope-flow:not(:defined) .flow-controls { display: none; } +.scope-flow:not(:defined) .flow-node { opacity: 1; } + +.scope-evidence-grid { display: grid; grid-template-columns: 1.2fr 1fr 1fr; gap: 1rem; } +.scope-evidence { display: flex; flex-direction: column; padding: 1.7rem; border: 1px solid var(--scope-border); border-radius: 0.8rem; background: var(--scope-surface); color: var(--scope-text); transition: border-color 180ms, box-shadow 180ms; } +.scope-evidence:hover, .scope-path:hover { border-color: var(--scope-brand); box-shadow: 0 5px 20px #11182708; } +.scope-evidence h3 { font-size: 1.25rem; font-weight: 600; letter-spacing: -0.03em; line-height: 1.35; margin: 0.7rem 0; } +.scope-evidence > p:not(.scope-eyebrow) { color: var(--scope-muted); font-size: 0.85rem; } +.scope-evidence > .scope-text-link { margin-top: auto; padding-top: 1.4rem; } +.scope-mini-dag { display: flex; align-items: center; justify-content: center; min-height: 130px; margin-bottom: 1.5rem; background: radial-gradient(ellipse, color-mix(in srgb, var(--scope-brand) 9%, transparent), transparent 75%); } +.scope-mini-dag span { border: 1px solid var(--scope-border); border-radius: 5px; padding: 0.45rem 0.6rem; font: 0.65rem var(--sl-font-mono); background: var(--scope-surface); } +.scope-mini-dag i { width: 18px; height: 1px; background: var(--scope-brand); } +.scope-profile-preview, .scope-trace-preview { display: grid; align-content: center; gap: 0.55rem; min-height: 130px; margin-bottom: 1.5rem; padding: 1rem; background: var(--scope-inset); border: 1px solid var(--scope-border); border-radius: 7px; font: 0.62rem var(--sl-font-mono); color: var(--scope-muted); } +.scope-profile-preview > span { display: flex; justify-content: space-between; gap: 0.75rem; }.scope-profile-preview b, .scope-trace-preview b { font-weight: 400; color: var(--scope-text); }.scope-trace-preview b { margin-left: 0.6rem; } +.scope-paths { display: grid; grid-template-columns: repeat(3, 1fr); gap: 1rem; } +.scope-path { display: flex; flex-direction: column; padding: 1.6rem; color: var(--scope-text); border: 1px solid var(--scope-border); background: var(--scope-surface); border-radius: 0.7rem; transition: border-color 180ms; } +.scope-path-top { display: flex; justify-content: space-between; gap: 1rem; font: 0.65rem var(--sl-font-mono); color: var(--scope-muted); margin-bottom: 1.6rem; } +.scope-path-top > span:first-child { color: var(--scope-brand); } +.scope-path h3 { font-size: 1.1rem; font-weight: 600; letter-spacing: -0.02em; } +.scope-path p { color: var(--scope-muted); font-size: 0.85rem; margin: 0.7rem 0 1.5rem; } +.scope-path .scope-text-link { margin-top: auto; } +.scope-help-row { display: flex; flex-wrap: wrap; gap: 1.25rem; margin-top: 1.5rem; font-size: 0.75rem; } +.scope-help-row span { color: var(--scope-muted); }.scope-help-row a { color: var(--scope-brand); }.scope-help-row a:hover { text-decoration: underline; } +.scope-cta { margin-top: 6rem; text-align: center; padding: 4rem 1.5rem; background: radial-gradient(ellipse at 50% 110%, color-mix(in srgb, var(--scope-brand) 12%, transparent), transparent 70%), var(--scope-surface); border: 1px solid var(--scope-border); border-radius: 1rem; } +.scope-cta h2 { font-size: clamp(2rem, 4vw, 3.25rem); letter-spacing: -0.045em; font-weight: 600; line-height: 1.15; margin: 1rem 0; } +.scope-cta > p:not(.scope-eyebrow) { color: var(--scope-muted); font-size: 0.9rem; margin-bottom: 1.5rem; } +.scope-access-note { display: block; font-size: 0.72rem; color: var(--scope-muted); margin: 1rem auto 0; max-width: 50ch; } +.scope-home-footer { display: flex; flex-wrap: wrap; gap: 1rem; justify-content: space-between; padding: 2rem 0 0; font-size: 0.75rem; font-weight: 600; }.scope-home-footer a { color: var(--scope-muted); }.scope-footer-muted { color: var(--scope-muted); font-weight: 400; } + +@media (max-width: 65rem) { + .flow-step-name { display: none; } + .flow-agent { grid-template-columns: 1fr; }.flow-agent-initial { display: none; } + .flow-node { padding: 0.75rem; } + .scope-evidence-grid { grid-template-columns: 1fr 1fr; }.scope-evidence--wide { grid-column: 1 / -1; }.scope-mini-dag { min-height: 80px; } +} +@media (max-width: 48rem) { + .scope-section-heading { display: block; }.scope-section-heading > p, .scope-section-heading > a { display: block; margin-top: 1rem; max-width: 55ch; } + .scope-agent-strip { column-gap: 1rem; row-gap: 0.6rem; }.scope-agent-strip > span:first-child { width: 100%; } + .flow-toolbar { flex-wrap: wrap; padding: 1rem; }.flow-select-label { width: 100%; justify-content: space-between; } + .flow-canvas { padding: 1rem; }.flow-canvas-label { font-size: 0.6rem; flex-wrap: wrap; } + .flow-connections { display: none; } + .flow-nodes { grid-template-columns: 1fr; gap: 1.4rem; height: auto; } + .flow-node { position: relative; padding: 1rem; } + .flow-node:not(.flow-agent):not(.flow-report)::after, .flow-agent-nodes::after { content: ''; position: absolute; width: 2px; height: 1.4rem; background: var(--scope-brand); bottom: -1.4rem; left: 50%; } + .flow-agent-nodes { position: relative; grid-template-columns: repeat(2, minmax(0, 1fr)); grid-template-rows: none; gap: 0.75rem; height: auto; } + .flow-agent { display: grid; grid-template-columns: 24px 1fr; min-height: 88px; }.flow-agent-initial { display: grid; } + .flow-agent:last-child:nth-child(odd) { grid-column: 1 / -1; } + .flow-scenario, .flow-judge, .flow-report { display: grid; grid-template-columns: 32px 1fr; align-items: center; column-gap: 0.8rem; } + .flow-node-icon { grid-row: 1 / 3; margin: 0; }.flow-node > span:not(.flow-node-icon):not(.flow-node-kicker), .flow-node-tag { grid-column: 2; } + .flow-criteria { flex-direction: row; flex-wrap: wrap; align-items: center; }.flow-criteria i { width: 8px; height: 1px; margin: 0; } + .flow-chart { height: 28px; max-width: 140px; } + .flow-controls { padding: 0.75rem 1rem; gap: 0.5rem; }.flow-step-buttons { gap: 0.15rem; }.flow-step-buttons button { padding: 0.4rem; min-width: 36px; } + .flow-inspector { grid-template-columns: 1fr; gap: 1rem; padding: 1.25rem; min-height: 340px; } + .scope-paths { grid-template-columns: 1fr; }.scope-path-top { margin-bottom: 1rem; } + .scope-cta { margin-top: 3.5rem; } +} +@media (max-width: 30rem) { + .scope-hero { padding-inline: 0; }.scope-hero h1 { font-size: 2.65rem; }.scope-hero > .scope-eyebrow { letter-spacing: 0.07em; font-size: 0.6rem; } + .scope-evidence-grid { grid-template-columns: 1fr; }.scope-evidence--wide { grid-column: auto; } + .flow-controls { flex-wrap: wrap; }.flow-step-buttons { width: 100%; justify-content: space-between; }.flow-step-buttons button { min-width: 44px; }.flow-step-name { display: inline; } + .flow-agent { grid-template-columns: 1fr; }.flow-agent-initial { display: none; } + .flow-demo-label { font-size: 0.75rem; } + .scope-actions { flex-direction: column; }.scope-actions .scope-btn { width: 100%; } } - -.scope-lane { padding: 1.15rem 1.25rem 1.35rem; border-right: 1px solid var(--border); margin: 0; } -.scope-lane:last-child { border-right: none; } - -.scope-lane__top { - display: flex; - align-items: flex-start; - justify-content: space-between; - gap: var(--sp-2); - min-height: 4.05rem; - margin-bottom: var(--sp-4); - padding-bottom: var(--sp-3); - border-bottom: 1px solid var(--border); -} - -.scope-lane__name { display: block; font-weight: 600; font-size: 0.95rem; line-height: 1.3; color: var(--text); } -.scope-lane__id { - display: block; - margin-top: 0.2rem; - font-family: var(--sl-font-mono, monospace); - font-size: 0.66rem; - line-height: 1.35; - color: var(--text-faint); -} - -.scope-lane__badge { - flex-shrink: 0; - font-family: var(--sl-font-mono, monospace); - font-size: 0.6rem; - font-weight: 700; - letter-spacing: 0.06em; - padding: 0.2rem 0.5rem; - border-radius: 999px; - border: 1px solid var(--border-strong); - color: var(--text-muted); - text-transform: uppercase; -} - -.scope-crit { - display: flex; - align-items: center; - gap: var(--sp-2); - padding: 0.4rem 0; - font-size: 0.82rem; - color: var(--text-muted); -} - -.scope-mark { - flex-shrink: 0; - display: inline-flex; - align-items: center; - justify-content: center; - width: 1.1rem; - height: 1.1rem; - border-radius: 999px; - font-size: 0.68rem; - font-weight: 800; -} -.scope-mark--pass { background: color-mix(in oklch, var(--ok) 16%, transparent); color: var(--ok); } -.scope-mark--fail { background: color-mix(in oklch, var(--fail) 16%, transparent); color: var(--fail); } -.scope-mark--run { background: color-mix(in oklch, var(--brand) 16%, transparent); color: var(--brand); } -.scope-mark--wait { background: var(--surface-2); color: var(--text-faint); border: 1px solid var(--border); } - -@media (max-width: 46rem) { - .scope-board { grid-template-columns: 1fr; } - .scope-lane { border-right: none; border-bottom: 1px solid var(--border); } - .scope-lane:last-child { border-bottom: none; } -} - -/* ================================================================ * - * 5. SECTIONS - * ================================================================ */ - -.scope-section { margin-top: clamp(4rem, 9vw, 7rem); } - -.scope-section__head { max-width: 46rem; margin: 0 0 var(--sp-12); } - -.scope-section__eyebrow { - font-family: var(--sl-font-mono, monospace); - font-size: 0.72rem; - font-weight: 600; - letter-spacing: 0.16em; - text-transform: uppercase; - color: var(--brand); -} - -.scope-section__head h2 { - margin: var(--sp-3) 0 0; - border: none; - font-size: clamp(1.8rem, 4.2vw, 2.5rem); - letter-spacing: -0.025em; - font-weight: 700; - color: var(--text); -} - -.scope-section__head p { - margin: var(--sp-4) 0 0; - font-size: 1.05rem; - line-height: 1.6; - color: var(--text-muted); -} - -/* ---------------- How it works (steps) ---------------- */ - -.scope-steps { - display: grid; - grid-template-columns: repeat(3, 1fr); - gap: var(--sp-4); - counter-reset: step; -} - -.scope-step { - position: relative; - padding: var(--sp-6); - border: 1px solid var(--border); - border-radius: var(--r-lg); - background: var(--surface); -} - -.scope-step__k { - display: inline-flex; - align-items: center; - justify-content: center; - width: 2.1rem; - height: 2.1rem; - border-radius: var(--r-sm); - background: color-mix(in oklch, var(--brand) 14%, transparent); - color: var(--brand); - font-family: var(--sl-font-mono, monospace); - font-weight: 700; - font-size: 0.85rem; -} - -.scope-step h3 { margin: var(--sp-4) 0 var(--sp-2); font-size: 1.1rem; font-weight: 600; color: var(--text); } -.scope-step p { margin: 0; font-size: var(--sl-text-sm); line-height: 1.6; color: var(--text-muted); } - -@media (max-width: 52rem) { .scope-steps { grid-template-columns: 1fr; } } - -/* ---------------- Feature grid ---------------- */ - -.scope-features { - display: grid; - grid-template-columns: repeat(3, 1fr); - border-top: 1px solid var(--border); - border-left: 1px solid var(--border); - border-radius: var(--r-lg); - overflow: hidden; -} - -.scope-feature { - padding: 1.7rem 1.6rem; - border-right: 1px solid var(--border); - border-bottom: 1px solid var(--border); - transition: background 0.15s ease; -} -.scope-feature:hover { background: var(--surface-2); } - -.scope-feature__no { - font-family: var(--sl-font-mono, monospace); - font-size: 0.78rem; - font-weight: 600; - color: var(--brand); -} - -.scope-feature h3 { margin: 0.8rem 0 0.4rem; font-size: 1.08rem; font-weight: 600; letter-spacing: -0.01em; color: var(--text); } -.scope-feature p { margin: 0; font-size: var(--sl-text-sm); line-height: 1.6; color: var(--text-muted); } - -@media (max-width: 60rem) { .scope-features { grid-template-columns: 1fr 1fr; } } -@media (max-width: 38rem) { .scope-features { grid-template-columns: 1fr; } } - -/* ---------------- Channels ---------------- */ - -.scope-channels { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--sp-4); } - -.scope-channel { - display: flex; - flex-direction: column; - min-width: 0; - padding: var(--sp-6); - border: 1px solid var(--border); - border-radius: var(--r-lg); - background: var(--surface); - transition: border-color 0.15s ease, transform 0.15s ease, box-shadow 0.15s ease; -} -.scope-channel:hover { - border-color: var(--border-strong); - transform: translateY(-2px); - box-shadow: 0 18px 40px -28px rgba(15, 23, 42, 0.5); -} - -.scope-channel__k { - font-family: var(--sl-font-mono, monospace); - font-size: 0.72rem; - letter-spacing: 0.1em; - text-transform: uppercase; - color: var(--text-faint); -} -.scope-channel h3 { margin: 0.5rem 0; font-size: 1.25rem; font-weight: 600; color: var(--text); } -.scope-channel p { margin: 0 0 var(--sp-4); font-size: var(--sl-text-sm); line-height: 1.6; color: var(--text-muted); flex: 1; } -.scope-channel a { font-size: var(--sl-text-sm); font-weight: 600; color: var(--brand); text-decoration: none; } -.scope-channel a:hover { color: var(--brand-strong); } - -@media (max-width: 60rem) { .scope-channels { grid-template-columns: 1fr; } } - -/* ---------------- Explore-the-docs cards ---------------- */ - -.scope-home .card-grid { gap: var(--sp-4); } -.scope-home .card { - border-color: var(--border); - background: var(--surface); - box-shadow: none; - transition: border-color 0.15s ease, transform 0.15s ease; -} -.scope-home .card:hover { border-color: var(--border-strong); transform: translateY(-2px); } -.scope-home .card .title { color: var(--text); font-weight: 600; } -.scope-home .card a { color: var(--brand); } - -/* ================================================================ * - * 6. CTA - * ================================================================ */ - -.scope-cta { - margin-top: clamp(4rem, 9vw, 7rem); - border: 1px solid var(--border); - border-radius: var(--r-xl); - padding: clamp(2.5rem, 6vw, 4.5rem) var(--sp-6); - text-align: center; - background: var(--surface-2); -} - -.scope-cta h2 { - margin: 0 auto; - border: none; - max-width: 20ch; - font-size: clamp(1.7rem, 4.2vw, 2.5rem); - font-weight: 700; - letter-spacing: -0.025em; - color: var(--text); -} - -.scope-cta p { margin: var(--sp-4) auto 0; max-width: 42ch; line-height: 1.6; color: var(--text-muted); } -.scope-cta .scope-actions { margin-top: var(--sp-8); } - -/* ================================================================ * - * 7. Motion discipline - * ================================================================ */ - @media (prefers-reduced-motion: reduce) { - .scope-home * { transition: none !important; } + .scope-home *, .scope-home *::before, .scope-home *::after { animation: none !important; transition: none !important; scroll-behavior: auto !important; } } From b60ba25f7433ed0c3553e52f5b28fd5065ec18af Mon Sep 17 00:00:00 2001 From: Wassim Chegham Date: Thu, 17 Sep 2026 16:57:06 +0200 Subject: [PATCH 2/6] Update button aria-label for sample agent execution Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- website/src/components/FlowDemo.astro | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/src/components/FlowDemo.astro b/website/src/components/FlowDemo.astro index 68b942c36..39cd1ce31 100644 --- a/website/src/components/FlowDemo.astro +++ b/website/src/components/FlowDemo.astro @@ -52,7 +52,7 @@ const wires = [incoming, outgoing, `M770 ${center} H830`];
{sampleAgents.map((agent) => ( - From ae54b73fb2e320c44066950e864e6a06f78697e4 Mon Sep 17 00:00:00 2001 From: Wassim Chegham Date: Thu, 17 Sep 2026 22:04:46 +0200 Subject: [PATCH 3/6] Use default scenario if selected scenario is unknown Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- website/src/scripts/flow-demo.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/website/src/scripts/flow-demo.ts b/website/src/scripts/flow-demo.ts index 9bf2c936b..8db8fbbe8 100644 --- a/website/src/scripts/flow-demo.ts +++ b/website/src/scripts/flow-demo.ts @@ -89,8 +89,7 @@ class ScopeFlow extends HTMLElement { }, { signal }); this.querySelector('select')?.addEventListener('change', (event) => { if (!(event.target instanceof HTMLSelectElement)) return; - const scenario = scenarios[event.target.value]; - if (!scenario) throw new Error('Unknown Scope demo scenario'); + const scenario = scenarios[event.target.value] ?? scenarios.board; this.interacted = true; this.stop(); this.scenario = scenario; From b6605f11886e0fe3c95595a4174b7035f5df2cf6 Mon Sep 17 00:00:00 2001 From: Wassim Chegham Date: Fri, 18 Sep 2026 10:06:24 +0200 Subject: [PATCH 4/6] feat(docs): clarify playground comparisons and evaluation Show supported and planned agents, compare base and alternate profiles, explain gates and reusable criteria, and surface simulated token and duration metrics. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> --- website/README.md | 64 ++++-- website/src/components/FlowDemo.astro | 63 ++++-- .../content/docs/guides/defining-criteria.mdx | 19 ++ website/src/scripts/flow-demo-data.test.ts | 56 +++++ website/src/scripts/flow-demo-data.ts | 105 ++++++++++ website/src/scripts/flow-demo.ts | 193 +++++++++++------- website/src/scripts/sample-agents.ts | 20 +- website/src/styles/landing.css | 51 ++++- website/vitest.config.ts | 13 ++ 9 files changed, 464 insertions(+), 120 deletions(-) create mode 100644 website/src/scripts/flow-demo-data.test.ts create mode 100644 website/src/scripts/flow-demo-data.ts create mode 100644 website/vitest.config.ts diff --git a/website/README.md b/website/README.md index 8d33de08f..88a0afdf5 100644 --- a/website/README.md +++ b/website/README.md @@ -126,24 +126,39 @@ and an initial task prompt as static HTML. a custom element. It makes no network requests and adds no framework or animation-library dependencies. -Two invented scenarios illustrate task submission, five sample agent profiles, -a three-node criteria dependency graph, and per-criterion evidence. -The example results deliberately differ by scenario. They are labeled -as simulations, not measurements or agent rankings. Keep that -distinction if adding scenarios. - -The sample roster is GitHub Copilot, Claude Code, Cursor, OpenAI Codex, -and OpenCode. These are the five highest-adoption individually named -coding agents in the [JetBrains May-July 2026 survey report](https://blog.jetbrains.com/research/2026/08/ai-coding-agent-adoption-2026/); -the report also lists a combined JetBrains AI/Junie category, which is -not a single agent. Display order is not rank order. - -[sample-agents.ts](src/scripts/sample-agents.ts) is shared by the static -diagram and the results renderer. Connector branches and the profile -count derive from that roster. Results use one row per agent, with -invented pass/fail/skipped outcomes that respect the criteria chain. -The playground does not claim that all sample agents are supported -Scope integrations; the supported-agent links remain separate. +Two invented scenarios illustrate task submission, a base profile with +two alternate profiles, evaluation gates, and per-criterion evidence. +Results deliberately differ by scenario. Outcomes, token counts, and +durations are labeled as simulations, not measurements or agent rankings. +Keep that distinction if adding scenarios. + +The availability strip identifies GitHub Copilot and Claude Code as +**Supported today**, OpenAI Codex and OpenCode as **Planned**, and Cursor +as **Not integrated**. Planned agents have no promised release date and +do not appear in the simulated executions. + +[sample-agents.ts](src/scripts/sample-agents.ts) separates availability +from the fictional profiles. The base uses Copilot, Var 1 adds a task +skill with the same agent and model, and Var 2 changes the agent and +model to Claude Code. All use the same task and criteria. Connector +branches and profile counts derive from this shared profile list. + +The judge step distinguishes **gates** from the reusable **criteria +library**. Requirements, Build, and Test are sequential gates. An +optional **Explore the criteria graph** disclosure shows the graph +inside each gate, including two independent checks that depend on +"Tests execute". The graph is collapsed by default to keep the +homepage introduction approachable. + +[flow-demo-data.ts](src/scripts/flow-demo-data.ts) owns the invented +fixtures and derives consistent gate and criterion outcomes: failing +a gate skips later gates, while failing a criterion skips its +descendants, not its siblings. The results table compares each +variation with the base, showing gates passed, input/output and total +tokens, elapsed run duration, and signed token/time differences. +Duration describes the fictional run, not the animation. Lower usage +or shorter duration is not presented as a win when the run failed. +Per-criterion outcomes remain available in a separate disclosure. Playback runs once when the playground enters view. Users can pause, reset, replay, select a scenario, or inspect any step with a button. @@ -152,6 +167,16 @@ users get manual **Next step** controls and no animated connectors. Without JavaScript, the static diagram and explanation remain visible, and nonfunctional playback controls stay hidden. +The playground data tests use the monorepo's existing Vitest runner. +After installing root and website dependencies, run from the repo root: + +```sh +pnpm exec vitest run --config website/vitest.config.ts +``` + +The website has its own test configuration because its standalone +Astro dependencies are not part of the root pnpm workspace install. + ### Review findings and recommendations The September 2026 review covered all 29 handwritten pages, navigation @@ -176,7 +201,8 @@ Recommended content follow-ups: ID policy. The introduction and reference currently describe three agents, while the worker ID list names only two. The landing's supported-agent strip names only the two documented ACP workers; - its separately labeled fictional playground includes five examples. + the playground explicitly separates them from planned or unavailable + integrations and runs fictional profiles of supported agents only. - Walk the first-run guide against a current deployment, then add maintained screenshots. Its claims about preseeded catalogs, model availability, and UI labels should not be assumed for every deployment. diff --git a/website/src/components/FlowDemo.astro b/website/src/components/FlowDemo.astro index 39cd1ce31..e0a54447c 100644 --- a/website/src/components/FlowDemo.astro +++ b/website/src/components/FlowDemo.astro @@ -1,18 +1,20 @@ --- -import { sampleAgents } from '../scripts/sample-agents'; +import { sampleAgents, sampleProfiles } from '../scripts/sample-agents'; +import { demoCriteria, demoGates } from '../scripts/flow-demo-data'; -const stages = ['Define a scenario', 'Run the agents', 'Evaluate the work', 'Explore the results']; -const rowHeight = 96; +const base = import.meta.env.BASE_URL.replace(/\/?$/, '/'); +const stages = ['Define a scenario', 'Compare profiles', 'Judge gates and criteria', 'Explore the results']; +const rowHeight = 116; const rowGap = 12; -const graphHeight = sampleAgents.length * rowHeight + (sampleAgents.length - 1) * rowGap; +const graphHeight = sampleProfiles.length * rowHeight + (sampleProfiles.length - 1) * rowGap; const center = graphHeight / 2; -const incoming = sampleAgents.map((_, index) => { +const incoming = sampleProfiles.map((_, index) => { const y = index * (rowHeight + rowGap) + rowHeight / 2; const direction = Math.sign(y - center); return direction === 0 ? `M210 ${center} H270` : `M210 ${center} H228 Q240 ${center} 240 ${center + direction * 12} V${y - direction * 12} Q240 ${y} 252 ${y} H270`; }).join(' '); -const outgoing = sampleAgents.map((_, index) => { +const outgoing = sampleProfiles.map((_, index) => { const y = index * (rowHeight + rowGap) + rowHeight / 2; const direction = Math.sign(center - y); return direction === 0 ? `M490 ${center} H550` @@ -21,7 +23,7 @@ const outgoing = sampleAgents.map((_, index) => { const wires = [incoming, outgoing, `M770 ${center} H830`]; --- - +
Scope playgroundSimulated
+
    + {sampleAgents.map((agent) => ( +
  • {agent.name}{agent.status}
  • + ))} +
-
EXPERIMENT / task-board{sampleAgents.length} sample profiles / same criteria
+
EXPERIMENT / task-board1 base + {sampleProfiles.length - 1} variations / same task and criteria
Your task prompt
- {sampleAgents.map((agent) => ( - ))}
-
@@ -75,7 +83,7 @@ const wires = [incoming, outgoing, `M770 ${center} H830`];
- {stages.map((stage, index) => )} + {stages.map((stage, index) => )}
@@ -84,10 +92,27 @@ const wires = [incoming, outgoing, `M770 ${center} H830`]; TASK PROMPT / EXAMPLE

Build a task board. Users can add tasks, mark them complete, and filter by status. An empty title must not create a task.

+
-

Illustrative demo only. No agents are running. Agent names are examples, not a list of supported Scope integrations. These are not real scores or usage rankings. Select any step to explore.

+

Illustrative demo only. No agents are running. All outcomes, token counts, and durations are invented, not measured benchmarks or agent rankings. Planned agents are not available today and are not included in the sample runs. Select any step to explore.

- + diff --git a/website/src/scripts/showreel.ts b/website/src/scripts/showreel.ts new file mode 100644 index 000000000..54ad3634a --- /dev/null +++ b/website/src/scripts/showreel.ts @@ -0,0 +1,92 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +class ScopeShowreel extends HTMLElement { + private events: AbortController | undefined; + private observer: IntersectionObserver | undefined; + + connectedCallback() { + const video = this.querySelector('video'); + const button = this.querySelector('button'); + const status = this.querySelector('[role="status"]'); + const source = video?.dataset.src; + if (!video || !button || !status || !source) throw new Error('Missing Scope showreel elements'); + + this.events = new AbortController(); + const { signal } = this.events; + const motion = window.matchMedia('(prefers-reduced-motion: reduce)'); + let wantsPlayback = !motion.matches; + let visible = false; + let playbackRequest = 0; + + video.muted = true; + button.hidden = false; + button.disabled = false; + + const renderPlayback = () => { + button.textContent = video.paused ? 'Play showreel' : 'Pause showreel'; + }; + const reportFailure = (error: unknown) => { + wantsPlayback = false; + video.pause(); + status.textContent = 'The showreel is unavailable.'; + status.hidden = false; + button.disabled = true; + console.error('Scope showreel failed', error); + }; + const syncPlayback = () => { + const request = ++playbackRequest; + video.autoplay = wantsPlayback && visible && !document.hidden; + if (!video.autoplay) { + video.pause(); + return; + } + if (!video.getAttribute('src')) video.src = source; + if (!video.paused) return; + void video.play().catch((error: unknown) => { + // Pausing or a newer play request can invalidate a pending promise. + if (request !== playbackRequest || signal.aborted) return; + if (error instanceof DOMException && error.name === 'NotAllowedError') { + wantsPlayback = false; + renderPlayback(); + status.textContent = 'Autoplay is blocked. Select Play showreel to start.'; + status.hidden = false; + return; + } + reportFailure(error); + }); + }; + + button.addEventListener('click', () => { + wantsPlayback = video.paused; + syncPlayback(); + }, { signal }); + video.addEventListener('play', renderPlayback, { signal }); + video.addEventListener('pause', renderPlayback, { signal }); + video.addEventListener('playing', () => { status.hidden = true; }, { signal }); + video.addEventListener('error', () => reportFailure(video.error), { signal }); + motion.addEventListener('change', () => { + if (motion.matches) wantsPlayback = false; + syncPlayback(); + }, { signal }); + document.addEventListener('visibilitychange', syncPlayback, { signal }); + this.observer = new IntersectionObserver(([entry]) => { + visible = entry.isIntersecting; + syncPlayback(); + }, { threshold: 0.25 }); + this.observer.observe(this); + renderPlayback(); + } + + disconnectedCallback() { + this.events?.abort(); + this.observer?.disconnect(); + const video = this.querySelector('video'); + if (video) { + video.autoplay = false; + video.pause(); + } + } +} + +if (!customElements.get('scope-showreel')) customElements.define('scope-showreel', ScopeShowreel); diff --git a/website/src/styles/landing.css b/website/src/styles/landing.css index cf643ee36..395b9cae5 100644 --- a/website/src/styles/landing.css +++ b/website/src/styles/landing.css @@ -76,6 +76,17 @@ body:has(.scope-home) header.header { background: color-mix(in srgb, var(--scope .scope-btn--secondary { color: var(--scope-text); background: var(--scope-surface); border-color: var(--scope-border); } .scope-btn--secondary:hover { background: var(--scope-inset); } .scope-hero .scope-hero-note { margin-top: 1rem; color: var(--scope-muted); font-size: 0.75rem; } +/* The showreel is dark in both themes, so its overlay controls use fixed dark styling. */ +scope-showreel { display: block; max-width: 60rem; margin: 3rem auto 0; } +.scope-showreel-frame { position: relative; margin: 0; overflow: hidden; border: 1px solid var(--scope-border); border-radius: 1rem; background: #0b0d18; box-shadow: var(--scope-shadow), 0 0 0 6px color-mix(in srgb, var(--scope-brand) 7%, transparent); } +.scope-showreel-frame video { display: block; width: 100%; height: auto; aspect-ratio: 16 / 9; object-fit: cover; } +.scope-showreel-controls { position: absolute; right: 0.75rem; bottom: 0.75rem; left: 0.75rem; display: flex; flex-wrap: wrap; justify-content: end; align-items: center; gap: 0.5rem; pointer-events: none; text-align: right; } +.scope-showreel-controls > * { pointer-events: auto; } +.scope-showreel-controls button { min-height: 44px; padding: 0.5rem 0.85rem; border: 1px solid #ffffff33; border-radius: 0.5rem; background: #0b0d18c7; color: #e9eaf6; font-size: 0.75rem; backdrop-filter: blur(6px); } +.scope-showreel-controls button:hover { border-color: #ffffff80; } +.scope-showreel-controls button:focus-visible { outline: 2px solid #fff; outline-offset: 2px; } +.scope-showreel-controls button:disabled { opacity: 0.6; } +.scope-showreel-controls [role='status'] { max-width: 36ch; padding: 0.45rem 0.65rem; border-radius: 0.4rem; background: #0b0d18d9; color: #e9eaf6; font-size: 0.75rem; } .scope-agent-strip { display: flex; flex-wrap: wrap; justify-content: center; align-items: center; gap: 1.4rem; margin-top: 3.7rem; padding: 1.5rem 0; border-top: 1px solid var(--scope-border); border-bottom: 1px solid var(--scope-border); font-size: 0.8rem; } .scope-agent-strip > span:first-child { color: var(--scope-muted); font-size: 0.75rem; } .scope-agent-strip strong { font-size: 1rem; font-weight: 600; } @@ -257,6 +268,9 @@ body:has(.scope-home) header.header { background: color-mix(in srgb, var(--scope } @media (max-width: 30rem) { .scope-hero { padding-inline: 0; }.scope-hero h1 { font-size: 2.65rem; }.scope-hero > .scope-eyebrow { letter-spacing: 0.07em; font-size: 0.6rem; } + scope-showreel { margin-top: 2.25rem; } + .scope-showreel-controls { position: static; padding: 0.5rem; border-top: 1px solid #ffffff1f; } + .scope-showreel-controls:not(:has(> :not([hidden]))) { display: none; } .scope-evidence-grid { grid-template-columns: 1fr; }.scope-evidence--wide { grid-column: auto; } .flow-controls { flex-wrap: wrap; }.flow-step-buttons { width: 100%; justify-content: space-between; }.flow-step-buttons button { min-width: 44px; }.flow-step-name { display: inline; } .flow-agent { grid-template-columns: 1fr; }.flow-agent-initial { display: none; }