فهرست منبع

feat(stats): add model comparison home

Adam 2 ماه پیش
والد
کامیت
ccd8676bee
2فایلهای تغییر یافته به همراه1411 افزوده شده و 79 حذف شده
  1. 565 77
      packages/stats/app/src/routes/compare/index.tsx
  2. 846 2
      packages/stats/app/src/routes/index.css

+ 565 - 77
packages/stats/app/src/routes/compare/index.tsx

@@ -1,11 +1,16 @@
 import "../index.css"
 import "../index.css"
-import { Link, Meta, Title } from "@solidjs/meta"
+import { Meta, Title } from "@solidjs/meta"
+import { ProviderIcon } from "@opencode-ai/ui/provider-icon"
 import { createAsync } from "@solidjs/router"
 import { createAsync } from "@solidjs/router"
-import { createMemo, createSignal, onMount, Show } from "solid-js"
+import { createEffect, createMemo, createSignal, For, onMount, Show } from "solid-js"
 import { getRequestEvent } from "solid-js/web"
 import { getRequestEvent } from "solid-js/web"
-import { ComparisonCardsSection, modelRefFromCatalog, uniqueComparisonPairs } from "../compare-cards"
-import { ComparisonSelector } from "../compare-selector"
-import { getModelCatalog, type ModelCatalogEntry } from "../model-catalog"
+import { LocaleLinks } from "../../component/locale-links"
+import { useI18n } from "../../context/i18n"
+import { useLanguage } from "../../context/language"
+import { localizedUrl } from "../../lib/language"
+import { comparisonHref, modelRefFromCatalog, type ComparisonModelRef } from "../compare-cards"
+import { formatCatalogLabName, getModelCatalog, type ModelCatalogEntry } from "../model-catalog"
+import { setStatsPageCacheHeaders } from "../stats-cache"
 import {
 import {
   applyThemePreference,
   applyThemePreference,
   Footer,
   Footer,
@@ -17,35 +22,75 @@ import {
   type ThemePreference,
   type ThemePreference,
 } from "../stats-shell"
 } from "../stats-shell"
 
 
-const compareFallbackUrl = "https://stats.opencode.ai"
+const comparePath = "/data/compare"
 const compareTitle = "AI Model Comparison"
 const compareTitle = "AI Model Comparison"
 const compareDescription =
 const compareDescription =
-  "Compare AI models used in OpenCode by context, output, release date, usage, rank, token share, and cost."
-const compareHeaderLinks: readonly HeaderLink[] = [
-  { href: "#compare-tool", label: "Compare" },
-  { href: "#model-comparison", label: "Popular" },
-]
-const compareFooterLinks: readonly HeaderLink[] = [
-  { href: import.meta.env.BASE_URL, label: "Data Home" },
-  { href: `${import.meta.env.BASE_URL}#top-models`, label: "Top Models" },
-  { href: `${import.meta.env.BASE_URL}#token-cost`, label: "Token Cost" },
-  { href: `${import.meta.env.BASE_URL}compare`, label: "Model Compare" },
-]
+  "Compare AI models on key metrics including benchmarks, price, context length, and other model features."
+const statsUnfurlPath = "banner.png"
+const uptimeBars = Array.from({ length: 10 }, (_, index) => index)
+const heroLabs = [
+  { lab: "deepseek", label: "DeepSeek" },
+  { lab: "openai", label: "OpenAI" },
+  { lab: "anthropic", label: "Anthropic" },
+] as const
+const categoryTemplates = [
+  {
+    title: "Flagship models",
+    description: "The latest top-tier model from major labs.",
+    kind: "flagship",
+  },
+  {
+    title: "Most affordable",
+    description: "Compact, lower-cost picks for high-throughput use.",
+    kind: "affordable",
+  },
+  {
+    title: "Best for code",
+    description: "Frequently chosen for programming tasks.",
+    kind: "code",
+  },
+  {
+    title: "Image generation",
+    description: "Compare top image models on cost and quality.",
+    kind: "image",
+  },
+] as const
+
+type CompareCategory = {
+  title: string
+  description: string
+  first: ComparisonModelRef
+  second: ComparisonModelRef
+  avatars: ComparisonModelRef[]
+}
+type CompareSlot = "first" | "second"
 
 
 export default function ModelCompareIndex() {
 export default function ModelCompareIndex() {
+  const i18n = useI18n()
+  const language = useLanguage()
   const event = getRequestEvent()
   const event = getRequestEvent()
-  event?.response.headers.set("Cache-Control", "public, max-age=60, s-maxage=300, stale-while-revalidate=86400")
+  setStatsPageCacheHeaders(event?.response.headers)
   const catalog = createAsync(() => getModelCatalog())
   const catalog = createAsync(() => getModelCatalog())
   const githubStars = createAsync(() => getGitHubStars())
   const githubStars = createAsync(() => getGitHubStars())
   const [themePreference, setThemePreference] = createSignal<ThemePreference>("system")
   const [themePreference, setThemePreference] = createSignal<ThemePreference>("system")
-  const compareUrl = createMemo(() =>
-    new URL(
-      `${import.meta.env.BASE_URL}compare`,
-      event?.request.url ?? (typeof window === "undefined" ? compareFallbackUrl : window.location.href),
-    ).toString(),
-  )
+  const compareUrl = createMemo(() => localizedUrl(language.locale(), comparePath))
+  const statsUnfurlUrl = new URL(statsUnfurlPath, localizedUrl("en", "/data/")).toString()
   const featuredModels = createMemo(() => (catalog()?.models ?? []).slice(0, 120))
   const featuredModels = createMemo(() => (catalog()?.models ?? []).slice(0, 120))
-  const pairs = createMemo(() => buildPopularPairs(featuredModels()))
+  const categories = createMemo(() => buildComparisonCategories(featuredModels()))
+  const compareHeaderLinks = createMemo<readonly HeaderLink[]>(() => [
+    { href: `${import.meta.env.BASE_URL}#top-models`, label: i18n.t("nav.topModels") },
+    { href: `${import.meta.env.BASE_URL}#leaderboard`, label: i18n.t("nav.leaderboard") },
+    { href: `${import.meta.env.BASE_URL}#market-share`, label: i18n.t("nav.marketShare") },
+    { href: `${import.meta.env.BASE_URL}#token-cost`, label: i18n.t("nav.tokenCost") },
+    { href: `${import.meta.env.BASE_URL}#session-cost`, label: i18n.t("nav.sessionCost") },
+  ])
+  const compareFooterLinks = createMemo<readonly HeaderLink[]>(() => [
+    { href: `${import.meta.env.BASE_URL}#top-models`, label: i18n.t("nav.topModels") },
+    { href: `${import.meta.env.BASE_URL}#leaderboard`, label: i18n.t("nav.leaderboard") },
+    { href: `${import.meta.env.BASE_URL}#market-share`, label: i18n.t("nav.marketShare") },
+    { href: `${import.meta.env.BASE_URL}#token-cost`, label: i18n.t("nav.tokenCost") },
+    { href: `${import.meta.env.BASE_URL}#session-cost`, label: i18n.t("nav.sessionCost") },
+  ])
   const updateThemePreference = (preference: ThemePreference) => {
   const updateThemePreference = (preference: ThemePreference) => {
     applyThemePreference(preference)
     applyThemePreference(preference)
     setThemePreference(preference)
     setThemePreference(preference)
@@ -65,84 +110,527 @@ export default function ModelCompareIndex() {
     <main data-page="stats" data-theme={themePreference()}>
     <main data-page="stats" data-theme={themePreference()}>
       <Title>{compareTitle}</Title>
       <Title>{compareTitle}</Title>
       <Meta name="description" content={compareDescription} />
       <Meta name="description" content={compareDescription} />
-      <Link rel="canonical" href={compareUrl()} />
+      <LocaleLinks path={comparePath} />
       <Meta property="og:type" content="website" />
       <Meta property="og:type" content="website" />
       <Meta property="og:site_name" content="OpenCode" />
       <Meta property="og:site_name" content="OpenCode" />
       <Meta property="og:title" content={compareTitle} />
       <Meta property="og:title" content={compareTitle} />
       <Meta property="og:description" content={compareDescription} />
       <Meta property="og:description" content={compareDescription} />
       <Meta property="og:url" content={compareUrl()} />
       <Meta property="og:url" content={compareUrl()} />
-      <Meta name="twitter:card" content="summary" />
+      <Meta property="og:image" content={statsUnfurlUrl} />
+      <Meta property="og:image:type" content="image/png" />
+      <Meta property="og:image:width" content="1200" />
+      <Meta property="og:image:height" content="630" />
+      <Meta property="og:image:alt" content={i18n.t("app.unfurlAlt")} />
+      <Meta name="twitter:card" content="summary_large_image" />
       <Meta name="twitter:title" content={compareTitle} />
       <Meta name="twitter:title" content={compareTitle} />
       <Meta name="twitter:description" content={compareDescription} />
       <Meta name="twitter:description" content={compareDescription} />
-      <Header githubStars={githubStars() ?? "150K"} links={compareHeaderLinks} brandHref={import.meta.env.BASE_URL} />
+      <Meta name="twitter:image" content={statsUnfurlUrl} />
+      <Meta name="twitter:image:alt" content={i18n.t("app.unfurlAlt")} />
+      <Header githubStars={githubStars() ?? "150K"} links={compareHeaderLinks()} brandHref={import.meta.env.BASE_URL} />
       <div data-component="container">
       <div data-component="container">
         <div data-component="content">
         <div data-component="content">
-          <section id="compare-tool" data-section="model-hero">
-            <a data-slot="model-back-link" href={import.meta.env.BASE_URL}>
-              Data
-            </a>
-            <div data-slot="model-hero-grid">
-              <div data-slot="model-hero-copy">
-                <span data-slot="model-id-tag">/compare</span>
-                <h1>Model Comparison</h1>
-                <p>Choose two models and compare usage, cost, limits, and features.</p>
-              </div>
-              <div data-component="model-rank-panel">
-                <span>Model Pairs</span>
-                <strong>{formatPairCount(featuredModels().length)}</strong>
-                <p>Available pairings from the model list.</p>
-              </div>
+          <section id="compare-tool" data-section="compare-home-hero">
+            <nav data-component="compare-home-breadcrumb" aria-label="Breadcrumb">
+              <a data-slot="compare-home-crumb" href={language.route(import.meta.env.BASE_URL)}>
+                Data
+              </a>
+              <span data-slot="compare-home-separator">/</span>
+              <span data-slot="compare-home-crumb" data-current="true">
+                Compare
+              </span>
+            </nav>
+            <div data-slot="compare-home-hero-grid">
+              <h1 aria-label="Compare AI models">
+                <span>Compare</span>
+                <HeroModelStack />
+                <span>AI models</span>
+              </h1>
+              <p>{compareDescription}</p>
             </div>
             </div>
-            <div data-slot="model-hero-pattern" aria-hidden="true" />
+            <div data-slot="compare-home-pattern" aria-hidden="true" />
+          </section>
+          <section data-section="compare-home-selector" aria-label="Choose models to compare">
             <Show
             <Show
               when={featuredModels().length > 1}
               when={featuredModels().length > 1}
-	              fallback={
-	                <div data-component="empty-state" data-compact="true">
-	                  <strong>No models found</strong>
-	                  <p>The model list could not be loaded.</p>
-	                </div>
-	              }
+              fallback={
+                <div data-component="empty-state" data-compact="true">
+                  <strong>No models found</strong>
+                  <p>The model list could not be loaded.</p>
+                </div>
+              }
             >
             >
-              <ComparisonSelector models={featuredModels()} />
+              <CompareHomeSelector models={featuredModels()} />
             </Show>
             </Show>
           </section>
           </section>
-          <ComparisonCardsSection
-            pairs={pairs()}
-            title="Popular Model Comparisons"
-            description="Common model pairs to start with."
-          />
+          <Show when={categories().length > 0}>
+            <section id="model-comparison" data-section="compare-home-related">
+              <p data-slot="section-title">
+                <strong>Related comparisons.</strong> <span>Other model pairs to check.</span>
+              </p>
+              <div data-component="compare-home-card-grid">
+                <For each={categories()}>{(category) => <CompareHomeCard category={category} />}</For>
+              </div>
+            </section>
+          </Show>
         </div>
         </div>
         <Footer
         <Footer
           themePreference={themePreference()}
           themePreference={themePreference()}
           onThemePreferenceChange={updateThemePreference}
           onThemePreferenceChange={updateThemePreference}
-          links={compareFooterLinks}
-          bridge={{ href: "#compare-tool", label: "MODEL COMPARE" }}
+          links={compareFooterLinks()}
+          bridge={null}
         />
         />
       </div>
       </div>
     </main>
     </main>
   )
   )
 }
 }
 
 
-function buildPopularPairs(models: ModelCatalogEntry[]) {
-  return uniqueComparisonPairs(
-    (
-      [
-        [0, 1, "Popular pair"],
-        [0, 2, "Top alternative"],
-        [1, 2, "Nearby pair"],
-        [2, 3, "Recent model pair"],
-        [3, 4, "Model pair"],
-        [4, 5, "Model pair"],
-      ] as const
-    ).flatMap(([firstIndex, secondIndex, detail]) => {
-      const first = models[firstIndex]
-      const second = models[secondIndex]
-      return first && second ? [{ first: modelRefFromCatalog(first), second: modelRefFromCatalog(second), detail }] : []
-    }),
+function CompareHomeSelector(props: { models: ModelCatalogEntry[] }) {
+  const [firstId, setFirstId] = createSignal("")
+  const [secondId, setSecondId] = createSignal("")
+  const [activeSlot, setActiveSlot] = createSignal<CompareSlot>()
+  const modelById = createMemo(() => new Map(props.models.map((model) => [model.id, model])))
+  const first = createMemo(() => modelById().get(firstId()))
+  const second = createMemo(() => modelById().get(secondId()))
+  const activeSelected = createMemo(() => (activeSlot() === "first" ? first() : second()))
+  const activeBlockedId = createMemo(() => (activeSlot() === "first" ? secondId() : firstId()))
+  const href = createMemo(() => {
+    const firstModel = first()
+    const secondModel = second()
+    if (!firstModel || !secondModel || firstModel.id === secondModel.id) return undefined
+    return comparisonHref(modelRefFromCatalog(firstModel), modelRefFromCatalog(secondModel))
+  })
+
+  createEffect(() => {
+    if (!secondId() || secondId() !== firstId()) return
+    setSecondId("")
+  })
+
+  createEffect(() => {
+    const url = href()
+    if (!url || typeof window === "undefined") return
+    window.location.href = url
+  })
+
+  return (
+    <form
+      data-component="compare-home-selector"
+      aria-label="Model comparison selector"
+      onSubmit={(event) => event.preventDefault()}
+    >
+      <CompareHomeSelect
+        selected={first()}
+        label="First model"
+        expanded={activeSlot() === "first"}
+        onOpen={() => setActiveSlot("first")}
+      />
+      <CompareHomeSelect
+        selected={second()}
+        label="Second model"
+        expanded={activeSlot() === "second"}
+        onOpen={() => setActiveSlot("second")}
+      />
+      <Show when={activeSlot()}>
+        {(slot) => (
+          <CompareModelSelectModal
+            models={props.models}
+            selected={activeSelected()}
+            blockedId={activeBlockedId()}
+            label={slot() === "first" ? "Choose first model" : "Choose second model"}
+            onClose={() => setActiveSlot(undefined)}
+            onSelect={(model) => {
+              if (slot() === "first") setFirstId(model.id)
+              if (slot() === "second") setSecondId(model.id)
+              setActiveSlot(undefined)
+            }}
+          />
+        )}
+      </Show>
+    </form>
+  )
+}
+
+function CompareHomeSelect(props: {
+  selected: ModelCatalogEntry | undefined
+  label: string
+  expanded: boolean
+  onOpen: () => void
+}) {
+  return (
+    <button
+      type="button"
+      data-slot="compare-home-select-panel"
+      data-selected={props.selected ? "true" : undefined}
+      aria-label={props.label}
+      aria-haspopup="dialog"
+      aria-expanded={props.expanded}
+      onClick={props.onOpen}
+    >
+      <span data-slot="compare-home-select-copy">
+        <span data-slot="compare-home-plus" aria-hidden="true">
+          +
+        </span>
+        <Show when={props.selected}>{(model) => <ModelAvatar model={model()} size="tiny" />}</Show>
+        <span data-slot="compare-home-select-name">{props.selected?.name ?? "Select a model"}</span>
+      </span>
+    </button>
+  )
+}
+
+function CompareModelSelectModal(props: {
+  models: ModelCatalogEntry[]
+  selected: ModelCatalogEntry | undefined
+  blockedId: string
+  label: string
+  onClose: () => void
+  onSelect: (model: ModelCatalogEntry) => void
+}) {
+  let searchInput: HTMLInputElement | undefined
+  const [search, setSearch] = createSignal("")
+  const [previewId, setPreviewId] = createSignal(props.selected?.id ?? "")
+  const availableModels = createMemo(() => props.models.filter((model) => model.id !== props.blockedId))
+  const filteredModels = createMemo(() => {
+    const terms = search().trim().toLowerCase().split(/\s+/).filter(Boolean)
+    if (terms.length === 0) return availableModels()
+    return availableModels().filter((model) => terms.every((term) => modelSearchText(model).includes(term)))
+  })
+  const preview = createMemo(
+    () =>
+      filteredModels().find((model) => model.id === previewId()) ??
+      filteredModels()[0] ??
+      availableModels()[0],
+  )
+
+  createEffect(() => {
+    const selected = props.selected
+    const fallback = selected && selected.id !== props.blockedId ? selected.id : filteredModels()[0]?.id
+    if (!fallback) return
+    if (availableModels().some((model) => model.id === previewId())) return
+    setPreviewId(fallback)
+  })
+
+  createEffect(() => {
+    const models = filteredModels()
+    if (models.some((model) => model.id === previewId())) return
+    setPreviewId(models[0]?.id ?? "")
+  })
+
+  createEffect(() => {
+    if (typeof window === "undefined") return
+    window.requestAnimationFrame(() => searchInput?.focus())
+  })
+
+  return (
+    <div
+      data-component="compare-model-modal-scrim"
+      role="presentation"
+      onClick={props.onClose}
+      onKeyDown={(event) => {
+        if (event.key !== "Escape") return
+        props.onClose()
+      }}
+    >
+      <div
+        data-component="compare-model-modal"
+        role="dialog"
+        aria-modal="true"
+        aria-label={props.label}
+        onClick={(event) => event.stopPropagation()}
+      >
+        <div data-slot="compare-model-modal-list">
+          <label data-slot="compare-model-modal-search">
+            <span data-slot="compare-model-modal-search-icon" aria-hidden="true" />
+            <input
+              ref={searchInput}
+              value={search()}
+              placeholder="Search models"
+              aria-label="Search models"
+              onInput={(event) => setSearch(event.currentTarget.value)}
+            />
+          </label>
+          <div data-slot="compare-model-modal-results">
+            <Show
+              when={filteredModels().length > 0}
+              fallback={
+                <div data-slot="compare-model-modal-empty">
+                  <strong>No models found</strong>
+                  <span>Try another search.</span>
+                </div>
+              }
+            >
+              <For each={filteredModels()}>
+                {(model) => (
+                  <button
+                    type="button"
+                    data-slot="compare-model-modal-row"
+                    data-active={preview()?.id === model.id ? "true" : undefined}
+                    onPointerEnter={() => setPreviewId(model.id)}
+                    onFocus={() => setPreviewId(model.id)}
+                    onClick={() => props.onSelect(model)}
+                  >
+                    <span data-slot="compare-model-modal-row-main">
+                      <ModelAvatar model={model} size="tiny" />
+                      <span>{model.name}</span>
+                    </span>
+                    <Show when={isFreeModel(model)}>
+                      <span data-slot="compare-model-modal-badge">Free</span>
+                    </Show>
+                  </button>
+                )}
+              </For>
+            </Show>
+          </div>
+        </div>
+        <div data-slot="compare-model-modal-divider" aria-hidden="true" />
+        <Show when={preview()}>{(model) => <CompareModelDetail model={model()} />}</Show>
+      </div>
+    </div>
+  )
+}
+
+function CompareModelDetail(props: { model: ModelCatalogEntry }) {
+  return (
+    <aside data-slot="compare-model-modal-detail">
+      <header data-slot="compare-model-modal-detail-header">
+        <ModelAvatar model={props.model} size="small" />
+        <strong>{props.model.name}</strong>
+      </header>
+      <div data-slot="compare-model-modal-description">
+        <p>{props.model.description ?? `${props.model.name} is an AI model from ${formatCatalogLabName(props.model.lab)}.`}</p>
+        <span aria-hidden="true" />
+      </div>
+      <dl data-slot="compare-model-modal-facts">
+        <CompareModelFact label="Release" value={formatCatalogDate(props.model.releaseDate)} />
+        <CompareModelFact label="Context" value={formatCatalogLimit(props.model.limit?.context)} />
+        <CompareModelFact label="Input" value={formatCatalogUnitPrice(props.model.cost?.input)} />
+        <CompareModelFact label="Output" value={formatCatalogUnitPrice(props.model.cost?.output)} />
+        <div data-slot="compare-model-modal-fact">
+          <dt>Uptime</dt>
+          <dd data-slot="compare-model-modal-uptime">
+            <For each={uptimeBars}>{(bar) => <span data-active={bar < 7 ? "true" : undefined} />}</For>
+          </dd>
+        </div>
+        <div data-slot="compare-model-modal-fact">
+          <dt>URL</dt>
+          <dd>
+            <a href={modelHref(props.model)}>{formatModelUrl(props.model)}</a>
+          </dd>
+        </div>
+      </dl>
+    </aside>
   )
   )
 }
 }
 
 
-function formatPairCount(count: number) {
-  if (count < 2) return "0"
-  return new Intl.NumberFormat("en", { notation: "compact", maximumFractionDigits: 1 }).format((count * (count - 1)) / 2)
+function CompareModelFact(props: { label: string; value: string }) {
+  return (
+    <div data-slot="compare-model-modal-fact">
+      <dt>{props.label}</dt>
+      <dd>{props.value}</dd>
+    </div>
+  )
+}
+
+function HeroModelStack() {
+  return (
+    <span data-slot="compare-home-avatar-stack" aria-hidden="true">
+      <For each={heroLabs}>
+        {(lab) => (
+          <span data-slot="compare-home-avatar-frame">
+            <LabLogo lab={lab.lab} label={lab.label} size="large" />
+          </span>
+        )}
+      </For>
+    </span>
+  )
+}
+
+function CompareHomeCard(props: { category: CompareCategory }) {
+  return (
+    <a
+      data-component="compare-home-card"
+      href={comparisonHref(props.category.first, props.category.second)}
+      aria-label={`${props.category.title}: ${props.category.first.name} vs ${props.category.second.name}`}
+    >
+      <span data-slot="compare-home-card-head">
+        <span>
+          <strong>{props.category.title}</strong>
+          <em>{props.category.description}</em>
+        </span>
+        <b aria-hidden="true" />
+      </span>
+      <span data-slot="compare-home-card-divider" aria-hidden="true" />
+      <span data-slot="compare-home-card-models">
+        <span>{props.category.first.name}</span>
+        <i aria-hidden="true">·</i>
+        <span>{props.category.second.name}</span>
+      </span>
+      <span data-slot="compare-home-card-avatars" aria-hidden="true">
+        <For each={props.category.avatars}>{(model) => <LabLogo lab={model.lab} label={model.name} size="small" />}</For>
+      </span>
+    </a>
+  )
+}
+
+function ModelAvatar(props: { model: ModelCatalogEntry; size: "large" | "small" | "tiny" }) {
+  return <LabLogo lab={props.model.lab} label={props.model.name} size={props.size} />
+}
+
+function LabLogo(props: { lab: string; label: string; size: "large" | "small" | "tiny" }) {
+  const iconId = () => getProviderIconId(props.lab)
+
+  return (
+    <span data-slot="compare-home-avatar" data-lab={iconId()} data-size={props.size} aria-label={props.label}>
+      <ProviderIcon aria-hidden="true" id={iconId()} />
+    </span>
+  )
+}
+
+function buildComparisonCategories(models: ModelCatalogEntry[]): CompareCategory[] {
+  return categoryTemplates.reduce<{ keys: Set<string>; categories: CompareCategory[] }>((result, template, index) => {
+    const candidates = categoryCandidates(template.kind, models)
+    const pair = categoryPair(candidates, models, index, result.keys)
+    if (!pair) return result
+    result.keys.add(comparisonKey(pair.first, pair.second))
+    const first = modelRefFromCatalog(pair.first)
+    const second = modelRefFromCatalog(pair.second)
+    result.categories.push({
+      title: template.title,
+      description: template.description,
+      first,
+      second,
+      avatars: [first, second],
+    })
+    return result
+  }, { keys: new Set(), categories: [] }).categories
+}
+
+function categoryPair(
+  candidates: ModelCatalogEntry[],
+  fallback: ModelCatalogEntry[],
+  offset: number,
+  usedKeys: Set<string>,
+) {
+  const pool = uniqueModels([...candidates, ...fallback.slice(offset), ...fallback])
+  return pool
+    .flatMap((first, firstIndex) =>
+      pool.slice(firstIndex + 1).map((second) => ({
+        first,
+        second,
+        key: comparisonKey(first, second),
+      })),
+    )
+    .find((pair) => !usedKeys.has(pair.key))
+}
+
+function categoryCandidates(kind: (typeof categoryTemplates)[number]["kind"], models: ModelCatalogEntry[]) {
+  if (kind === "affordable")
+    return models
+      .filter((model) => model.cost)
+      .toSorted((a, b) => modelCost(a) - modelCost(b) || displayDateTime(b.releaseDate) - displayDateTime(a.releaseDate))
+  if (kind === "code")
+    return models.filter((model) => model.toolCall || model.reasoning).toSorted(recentModelSort)
+  if (kind === "image")
+    return models
+      .filter((model) => model.modalities.output.some((modality) => modality.toLowerCase().includes("image")))
+      .toSorted(recentModelSort)
+  return models.toSorted(recentModelSort)
+}
+
+function uniqueModels(models: (ModelCatalogEntry | undefined)[]) {
+  return models.reduce<{ keys: Set<string>; models: ModelCatalogEntry[] }>(
+    (result, model) => {
+      if (!model || result.keys.has(model.id)) return result
+      result.keys.add(model.id)
+      result.models.push(model)
+      return result
+    },
+    { keys: new Set(), models: [] },
+  ).models
+}
+
+function recentModelSort(a: ModelCatalogEntry, b: ModelCatalogEntry) {
+  return displayDateTime(b.releaseDate) - displayDateTime(a.releaseDate) || a.name.localeCompare(b.name)
+}
+
+function comparisonKey(first: ModelCatalogEntry, second: ModelCatalogEntry) {
+  return [first.id, second.id].toSorted().join("|")
+}
+
+function modelCost(model: ModelCatalogEntry) {
+  return (model.cost?.input ?? Number.POSITIVE_INFINITY) + (model.cost?.output ?? Number.POSITIVE_INFINITY)
+}
+
+function modelSearchText(model: ModelCatalogEntry) {
+  return `${model.name} ${formatCatalogLabName(model.lab)} ${model.id}`.toLowerCase()
+}
+
+function isFreeModel(model: ModelCatalogEntry) {
+  return model.cost?.input === 0 && model.cost.output === 0
+}
+
+function modelHref(model: ModelCatalogEntry) {
+  return `${import.meta.env.BASE_URL}${model.lab}/${model.slug}`
+}
+
+function formatModelUrl(model: ModelCatalogEntry) {
+  return `.../${model.slug}`
+}
+
+function formatCatalogLimit(value: number | undefined) {
+  return value === undefined ? "Unknown" : formatTokens(value)
+}
+
+function formatCatalogUnitPrice(value: number | undefined) {
+  if (value === undefined) return "Unknown"
+  return `${formatModelPrice(value)} / 1M`
+}
+
+function formatModelPrice(value: number) {
+  if (value > 0 && value < 0.01) return `$${value.toFixed(4)}`
+  return formatMoney(value)
+}
+
+function formatMoney(value: number) {
+  if (value >= 1_000_000) return `$${trimNumber(value / 1_000_000, value >= 10_000_000 ? 0 : 1)}M`
+  if (value >= 1_000) return `$${trimNumber(value / 1_000, value >= 10_000 ? 0 : 1)}K`
+  return `$${value.toFixed(value >= 10 ? 0 : 2)}`
+}
+
+function formatCatalogDate(value: string | undefined) {
+  if (!value) return "Unknown"
+  const match = /^(\d{4})(?:-(\d{2}))?(?:-(\d{2}))?$/.exec(value)
+  if (!match) return value
+  return new Intl.DateTimeFormat("en", {
+    month: match[2] ? "short" : undefined,
+    day: match[3] ? "numeric" : undefined,
+    year: "numeric",
+    timeZone: "UTC",
+  }).format(new Date(Date.UTC(Number(match[1]), match[2] ? Number(match[2]) - 1 : 0, match[3] ? Number(match[3]) : 1)))
+}
+
+function formatTokens(value: number) {
+  if (value >= 1_000_000_000_000)
+    return `${trimNumber(value / 1_000_000_000_000, value >= 10_000_000_000_000 ? 0 : 1)}T`
+  if (value >= 1_000_000_000) return `${trimNumber(value / 1_000_000_000, value >= 10_000_000_000 ? 0 : 1)}B`
+  if (value >= 1_000_000) return `${trimNumber(value / 1_000_000, value >= 10_000_000 ? 0 : 1)}M`
+  if (value >= 1_000) return `${trimNumber(value / 1_000, value >= 10_000 ? 0 : 1)}K`
+  return String(Math.round(value))
+}
+
+function trimNumber(value: number, digits: number) {
+  return Number(value.toFixed(digits)).toLocaleString("en")
+}
+
+function displayDateTime(value: string | undefined) {
+  if (!value) return 0
+  const date = new Date(value)
+  if (!Number.isNaN(date.getTime())) return date.getTime()
+  const year = Number(value.match(/\d{4}/)?.[0] ?? 0)
+  return Number.isFinite(year) ? year : 0
+}
+
+function getProviderIconId(provider: string) {
+  const id = provider.toLowerCase().replace(/[^a-z0-9]+/g, "")
+  if (id === "moonshot") return "moonshotai"
+  if (id === "zhipu") return "zhipuai"
+  return id
 }
 }

+ 846 - 2
packages/stats/app/src/routes/index.css

@@ -5489,6 +5489,742 @@
   background: var(--stats-accent);
   background: var(--stats-accent);
 }
 }
 
 
+[data-page="stats"] [data-section="compare-home-hero"],
+[data-page="stats"] [data-section="compare-home-selector"],
+[data-page="stats"] [data-section="compare-home-related"] {
+  position: relative;
+  box-sizing: border-box;
+  color: var(--stats-text);
+}
+
+[data-page="stats"] [data-section="compare-home-hero"] {
+  display: grid;
+  align-content: end;
+  gap: 24px;
+  min-height: 316px;
+  padding: 128px 40px 40px;
+}
+
+[data-page="stats"] [data-component="compare-home-breadcrumb"] {
+  display: flex;
+  align-items: center;
+  gap: 8px;
+  height: 24px;
+  min-width: 0;
+}
+
+[data-page="stats"] [data-slot="compare-home-crumb"] {
+  display: inline-flex;
+  align-items: center;
+  height: 24px;
+  box-sizing: border-box;
+  padding: 0 8px;
+  color: var(--stats-hero-muted);
+  background: var(--stats-layer-2);
+  font-size: 13px;
+  font-weight: 500;
+  line-height: 1.1;
+  text-decoration: none;
+  white-space: nowrap;
+}
+
+[data-page="stats"] a[data-slot="compare-home-crumb"]:hover,
+[data-page="stats"] a[data-slot="compare-home-crumb"]:focus-visible {
+  color: var(--stats-text);
+  outline: none;
+  text-decoration: none;
+}
+
+[data-page="stats"] [data-slot="compare-home-separator"] {
+  color: var(--stats-faint);
+  font-size: 13px;
+  font-weight: 500;
+  line-height: 1;
+}
+
+[data-page="stats"] [data-slot="compare-home-hero-grid"] {
+  display: grid;
+  grid-template-columns: minmax(0, 1fr) minmax(320px, 519px);
+  gap: 24px;
+  align-items: center;
+}
+
+[data-page="stats"] [data-section="compare-home-hero"] h1 {
+  display: flex;
+  flex-wrap: wrap;
+  align-items: center;
+  gap: 16px;
+  min-width: 0;
+  margin: 0;
+  color: var(--stats-text);
+  font-size: 40px;
+  font-weight: 500;
+  line-height: 60px;
+  letter-spacing: 0;
+}
+
+[data-page="stats"] [data-slot="compare-home-avatar-stack"] {
+  display: inline-flex;
+  align-items: center;
+  height: 46px;
+  padding-inline: 2px;
+}
+
+[data-page="stats"] [data-slot="compare-home-avatar-frame"] {
+  display: inline-flex;
+  align-items: center;
+  justify-content: center;
+  flex: 0 0 auto;
+  padding: 3px;
+  background: var(--stats-bg);
+}
+
+[data-page="stats"] [data-slot="compare-home-avatar-frame"] + [data-slot="compare-home-avatar-frame"] {
+  margin-left: -16px;
+}
+
+[data-page="stats"] [data-slot="compare-home-avatar"] {
+  display: grid;
+  place-items: center;
+  flex: 0 0 auto;
+  color: #ffffff;
+  background: var(--stats-accent-text);
+  box-shadow: inset 0 0 0 1px #0000001a;
+}
+
+[data-page="stats"] [data-slot="compare-home-avatar"][data-lab="deepseek"] {
+  background: #5d6ff4;
+}
+
+[data-page="stats"] [data-slot="compare-home-avatar"][data-lab="openai"] {
+  background: #252525;
+}
+
+[data-page="stats"] [data-slot="compare-home-avatar"][data-lab="anthropic"] {
+  background: #c99b75;
+}
+
+[data-page="stats"] [data-slot="compare-home-avatar"][data-size="large"] {
+  width: 40px;
+  height: 40px;
+}
+
+[data-page="stats"] [data-slot="compare-home-avatar"][data-size="large"] svg {
+  width: 28px;
+  height: 28px;
+}
+
+[data-page="stats"] [data-slot="compare-home-avatar"][data-size="small"] {
+  width: 20px;
+  height: 20px;
+}
+
+[data-page="stats"] [data-slot="compare-home-avatar"][data-size="small"] svg {
+  width: 15px;
+  height: 15px;
+}
+
+[data-page="stats"] [data-slot="compare-home-avatar"][data-size="tiny"] {
+  width: 16px;
+  height: 16px;
+}
+
+[data-page="stats"] [data-slot="compare-home-avatar"][data-size="tiny"] svg {
+  width: 12px;
+  height: 12px;
+}
+
+[data-page="stats"] [data-slot="compare-home-hero-grid"] > p {
+  max-width: 520px;
+  margin: 0;
+  color: var(--stats-muted);
+  font-size: 16px;
+  font-weight: 400;
+  line-height: 24px;
+}
+
+[data-page="stats"] [data-slot="compare-home-pattern"] {
+  width: calc(100% + 80px);
+  height: 16px;
+  margin-inline: -40px;
+  overflow: hidden;
+  background: color-mix(in srgb, var(--stats-text) 10%, transparent);
+  mask-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 6 6' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M0 0H2V2H0V0Z' fill='black'/%3E%3C/svg%3E");
+  mask-position: center top;
+  mask-repeat: repeat;
+  mask-size: 6px 6px;
+  -webkit-mask-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 6 6' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M0 0H2V2H0V0Z' fill='black'/%3E%3C/svg%3E");
+  -webkit-mask-position: center top;
+  -webkit-mask-repeat: repeat;
+  -webkit-mask-size: 6px 6px;
+}
+
+[data-page="stats"] [data-section="compare-home-selector"] {
+  min-height: 98px;
+  border-top: 1px solid var(--stats-line);
+  border-bottom: 1px solid var(--stats-line);
+  box-shadow:
+    inset 1px 0 var(--stats-line),
+    inset -1px 0 var(--stats-line);
+}
+
+[data-page="stats"] [data-component="compare-home-selector"] {
+  display: grid;
+  grid-template-columns: 1fr 1fr;
+  min-height: 96px;
+}
+
+[data-page="stats"] [data-component="compare-home-selector"] button[data-slot="compare-home-select-panel"] {
+  position: relative;
+  display: grid;
+  place-items: center;
+  min-width: 0;
+  min-height: 96px;
+  padding: 0;
+  border: 0;
+  appearance: none;
+  border-radius: 0;
+  color: var(--stats-text);
+  background: var(--stats-bg);
+  cursor: pointer;
+  font: inherit;
+  text-align: inherit;
+}
+
+[data-page="stats"]
+  [data-component="compare-home-selector"]
+  button[data-slot="compare-home-select-panel"]:first-child::before,
+[data-page="stats"]
+  [data-component="compare-home-selector"]
+  button[data-slot="compare-home-select-panel"]:last-child::after {
+  position: absolute;
+  top: 0;
+  bottom: 0;
+  width: 1px;
+  content: "";
+  background: var(--stats-line);
+  pointer-events: none;
+}
+
+[data-page="stats"]
+  [data-component="compare-home-selector"]
+  button[data-slot="compare-home-select-panel"]:first-child::before {
+  left: 0;
+}
+
+[data-page="stats"]
+  [data-component="compare-home-selector"]
+  button[data-slot="compare-home-select-panel"]:last-child::after {
+  right: 0;
+}
+
+[data-page="stats"]
+  [data-component="compare-home-selector"]
+  button[data-slot="compare-home-select-panel"]
+  + button[data-slot="compare-home-select-panel"] {
+  box-shadow: inset 1px 0 var(--stats-line);
+}
+
+[data-page="stats"] [data-component="compare-home-selector"] button[data-slot="compare-home-select-panel"]:hover,
+[data-page="stats"] [data-component="compare-home-selector"] button[data-slot="compare-home-select-panel"]:focus-within {
+  background: var(--stats-layer);
+}
+
+[data-page="stats"] [data-component="compare-home-selector"] button[data-slot="compare-home-select-panel"]:focus-visible {
+  z-index: 1;
+  outline: 1px solid var(--stats-line-strong);
+  outline-offset: -1px;
+}
+
+[data-page="stats"] [data-slot="compare-home-select-copy"] {
+  display: inline-flex;
+  align-items: center;
+  justify-content: center;
+  gap: 8px;
+  max-width: calc(100% - 48px);
+  pointer-events: none;
+}
+
+[data-page="stats"] [data-slot="compare-home-plus"],
+[data-page="stats"] [data-slot="compare-home-select-name"] {
+  min-width: 0;
+  color: inherit;
+  font-size: 13px;
+  font-weight: 500;
+  line-height: 14px;
+}
+
+[data-page="stats"] [data-slot="compare-home-select-name"] {
+  overflow: hidden;
+  text-overflow: ellipsis;
+  white-space: nowrap;
+}
+
+[data-page="stats"] [data-slot="compare-home-select-panel"][data-selected="true"] [data-slot="compare-home-plus"] {
+  display: none;
+}
+
+[data-page="stats"] [data-section="compare-home-related"] {
+  min-height: 425px;
+  margin-top: 40px;
+  padding: 80px 40px;
+  box-shadow:
+    inset 0 1px var(--stats-line),
+    inset 0 -1px var(--stats-line),
+    inset 1px 0 var(--stats-line),
+    inset -1px 0 var(--stats-line);
+}
+
+[data-page="stats"] [data-section="compare-home-related"] [data-slot="section-title"] {
+  margin-bottom: 40px;
+}
+
+[data-page="stats"] [data-component="compare-home-card-grid"] {
+  display: grid;
+  grid-template-columns: repeat(4, minmax(0, 1fr));
+  gap: 10px;
+}
+
+[data-page="stats"] [data-component="compare-home-card"] {
+  position: relative;
+  display: grid;
+  grid-template-rows: 62px 1px 20px 20px;
+  gap: 16px;
+  min-width: 0;
+  height: 184px;
+  box-sizing: border-box;
+  padding: 16px;
+  overflow: hidden;
+  color: var(--stats-text);
+  background: var(--stats-layer);
+  border: 1px solid var(--stats-line);
+  box-shadow: 0 1px 2px #00000008;
+  text-decoration: none;
+}
+
+[data-page="stats"] [data-component="compare-home-card"]:hover,
+[data-page="stats"] [data-component="compare-home-card"]:focus-visible {
+  border-color: var(--stats-line-strong);
+  outline: none;
+  text-decoration: none;
+}
+
+[data-page="stats"] [data-slot="compare-home-card-head"] {
+  display: grid;
+  grid-template-columns: minmax(0, 1fr) 32px;
+  gap: 16px;
+  min-width: 0;
+}
+
+[data-page="stats"] [data-slot="compare-home-card-head"] > span {
+  display: grid;
+  gap: 8px;
+  min-width: 0;
+}
+
+[data-page="stats"] [data-slot="compare-home-card-head"] strong,
+[data-page="stats"] [data-slot="compare-home-card-head"] em,
+[data-page="stats"] [data-slot="compare-home-card-models"] {
+  min-width: 0;
+  overflow: hidden;
+  font-size: 13px;
+  line-height: 20px;
+  text-overflow: ellipsis;
+}
+
+[data-page="stats"] [data-slot="compare-home-card-head"] strong {
+  color: var(--stats-text);
+  font-weight: 500;
+  white-space: nowrap;
+}
+
+[data-page="stats"] [data-slot="compare-home-card-head"] em {
+  display: -webkit-box;
+  color: var(--stats-muted);
+  font-style: normal;
+  font-weight: 400;
+  -webkit-box-orient: vertical;
+  -webkit-line-clamp: 2;
+}
+
+[data-page="stats"] [data-slot="compare-home-card-head"] b {
+  position: relative;
+  display: grid;
+  place-items: center;
+  width: 32px;
+  height: 32px;
+  box-sizing: border-box;
+  border: 1px solid var(--stats-line);
+  background: var(--stats-bg);
+  box-shadow: 0 1px 1.5px #0000000f;
+}
+
+[data-page="stats"] [data-slot="compare-home-card-head"] b::before {
+  position: absolute;
+  top: 8px;
+  left: 8px;
+  width: 3px;
+  height: 3px;
+  content: "";
+  background: currentColor;
+  box-shadow:
+    7px 0 currentColor,
+    0 7px currentColor;
+  color: var(--stats-muted);
+}
+
+[data-page="stats"] [data-slot="compare-home-card-head"] b::after {
+  position: absolute;
+  right: 5px;
+  bottom: 5px;
+  width: 12px;
+  height: 12px;
+  box-sizing: border-box;
+  content: "";
+  background:
+    radial-gradient(circle at 4px 4px, transparent 2.5px, var(--stats-muted) 2.75px 4px, transparent 4.25px),
+    linear-gradient(var(--stats-muted) 0 0) 7px 8px / 5px 1.5px no-repeat;
+  transform: rotate(45deg);
+}
+
+[data-page="stats"] [data-slot="compare-home-card-divider"] {
+  height: 1px;
+  min-width: 0;
+  background: var(--stats-line);
+}
+
+[data-page="stats"] [data-slot="compare-home-card-models"] {
+  display: flex;
+  align-items: center;
+  gap: 6px;
+  color: var(--stats-muted);
+  font-weight: 400;
+  white-space: nowrap;
+}
+
+[data-page="stats"] [data-slot="compare-home-card-models"] span {
+  flex: 0 0 auto;
+}
+
+[data-page="stats"] [data-slot="compare-home-card-models"] i {
+  flex: 0 0 auto;
+  color: var(--stats-faint);
+  font-style: normal;
+}
+
+[data-page="stats"] [data-slot="compare-home-card-avatars"] {
+  display: inline-flex;
+  align-items: center;
+  gap: 8px;
+  min-width: 0;
+}
+
+[data-page="stats"] [data-component="compare-model-modal-scrim"] {
+  position: fixed;
+  inset: 0;
+  z-index: 1000;
+  display: grid;
+  place-items: center;
+  box-sizing: border-box;
+  padding: 24px;
+  background: rgb(0 0 0 / 40%);
+}
+
+[data-page="stats"] [data-component="compare-model-modal"] {
+  display: grid;
+  grid-template-columns: minmax(0, 440px) 1px minmax(0, 279px);
+  width: min(720px, calc(100vw - 48px));
+  height: min(480px, calc(100vh - 48px));
+  overflow: hidden;
+  color: var(--stats-text);
+  background: var(--stats-bg);
+  box-shadow:
+    0 0 0 0.5px rgb(0 0 0 / 12%),
+    0 8px 16px rgb(0 0 0 / 8%),
+    0 16px 32px rgb(0 0 0 / 4%);
+}
+
+[data-page="stats"] [data-slot="compare-model-modal-list"] {
+  display: grid;
+  grid-template-rows: 52px minmax(0, 1fr);
+  min-width: 0;
+  min-height: 0;
+  background: var(--stats-bg);
+}
+
+[data-page="stats"] [data-slot="compare-model-modal-search"] {
+  display: flex;
+  align-items: center;
+  gap: 12px;
+  box-sizing: border-box;
+  height: 52px;
+  padding: 16px;
+  border-bottom: 1px solid var(--stats-line);
+  color: var(--stats-muted);
+  background: var(--stats-bg);
+}
+
+[data-page="stats"] [data-slot="compare-model-modal-search-icon"] {
+  position: relative;
+  flex: 0 0 auto;
+  width: 16px;
+  height: 16px;
+  color: var(--stats-faint);
+}
+
+[data-page="stats"] [data-slot="compare-model-modal-search-icon"]::before {
+  position: absolute;
+  top: 3px;
+  left: 3px;
+  width: 6px;
+  height: 6px;
+  border: 1.5px solid currentColor;
+  border-radius: 999px;
+  content: "";
+}
+
+[data-page="stats"] [data-slot="compare-model-modal-search-icon"]::after {
+  position: absolute;
+  top: 10px;
+  left: 9px;
+  width: 5px;
+  height: 1.5px;
+  background: currentColor;
+  content: "";
+  transform: rotate(45deg);
+  transform-origin: left center;
+}
+
+[data-page="stats"] [data-slot="compare-model-modal-search"] input {
+  width: 100%;
+  min-width: 0;
+  height: 20px;
+  padding: 0;
+  border: 0;
+  outline: 0;
+  color: var(--stats-text);
+  background: transparent;
+  font: inherit;
+  font-size: 13px;
+  font-weight: 400;
+  line-height: 1.1;
+}
+
+[data-page="stats"] [data-slot="compare-model-modal-search"] input::placeholder {
+  color: var(--stats-faint);
+  opacity: 1;
+}
+
+[data-page="stats"] [data-slot="compare-model-modal-results"] {
+  min-width: 0;
+  min-height: 0;
+  overflow-y: auto;
+  background: var(--stats-layer);
+}
+
+[data-page="stats"] [data-component="compare-model-modal"] button[data-slot="compare-model-modal-row"] {
+  display: flex;
+  align-items: center;
+  gap: 16px;
+  width: 100%;
+  height: 49px;
+  box-sizing: border-box;
+  padding: 0 16px;
+  border: 0;
+  border-bottom: 1px solid var(--stats-line);
+  appearance: none;
+  border-radius: 0;
+  color: var(--stats-text);
+  background: transparent;
+  cursor: pointer;
+  font: inherit;
+  text-align: left;
+}
+
+[data-page="stats"] [data-component="compare-model-modal"] button[data-slot="compare-model-modal-row"]:hover,
+[data-page="stats"] [data-component="compare-model-modal"] button[data-slot="compare-model-modal-row"]:focus-visible,
+[data-page="stats"] [data-component="compare-model-modal"] button[data-slot="compare-model-modal-row"][data-active="true"] {
+  color: var(--stats-text);
+  background: var(--stats-layer-2);
+  outline: none;
+}
+
+[data-page="stats"] [data-slot="compare-model-modal-row-main"] {
+  display: flex;
+  align-items: center;
+  flex: 1 1 auto;
+  gap: 12px;
+  min-width: 0;
+}
+
+[data-page="stats"] [data-slot="compare-model-modal-row-main"] > span:last-child {
+  min-width: 0;
+  overflow: hidden;
+  color: var(--stats-text);
+  font-size: 13px;
+  font-weight: 500;
+  line-height: 1.1;
+  text-overflow: ellipsis;
+  white-space: nowrap;
+}
+
+[data-page="stats"] [data-slot="compare-model-modal-badge"] {
+  display: inline-flex;
+  align-items: center;
+  justify-content: center;
+  flex: 0 0 auto;
+  height: 16px;
+  padding: 0 6px;
+  color: var(--stats-muted);
+  background: var(--stats-layer-2);
+  font-size: 11px;
+  font-weight: 500;
+  line-height: 1.1;
+}
+
+[data-page="stats"] [data-slot="compare-model-modal-empty"] {
+  display: grid;
+  gap: 8px;
+  padding: 24px 16px;
+  color: var(--stats-muted);
+  font-size: 13px;
+  line-height: 1.4;
+}
+
+[data-page="stats"] [data-slot="compare-model-modal-empty"] strong {
+  color: var(--stats-text);
+  font-weight: 500;
+}
+
+[data-page="stats"] [data-slot="compare-model-modal-divider"] {
+  width: 1px;
+  min-height: 0;
+  background: var(--stats-line);
+}
+
+[data-page="stats"] [data-slot="compare-model-modal-detail"] {
+  display: grid;
+  grid-template-rows: 52px minmax(0, 1fr) auto;
+  min-width: 0;
+  min-height: 0;
+  background: var(--stats-bg);
+}
+
+[data-page="stats"] [data-slot="compare-model-modal-detail-header"] {
+  display: flex;
+  align-items: center;
+  gap: 12px;
+  box-sizing: border-box;
+  height: 52px;
+  padding: 16px;
+  background: var(--stats-bg);
+}
+
+[data-page="stats"] [data-slot="compare-model-modal-detail-header"] strong {
+  min-width: 0;
+  overflow: hidden;
+  color: var(--stats-text);
+  font-size: 13px;
+  font-weight: 500;
+  line-height: 1.1;
+  text-overflow: ellipsis;
+  white-space: nowrap;
+}
+
+[data-page="stats"] [data-slot="compare-model-modal-description"] {
+  position: relative;
+  min-width: 0;
+  min-height: 0;
+  padding: 0 16px 16px;
+  overflow: hidden;
+  background: var(--stats-bg);
+}
+
+[data-page="stats"] [data-slot="compare-model-modal-description"] p {
+  margin: 0;
+  color: var(--stats-muted);
+  font-size: 11px;
+  font-weight: 400;
+  line-height: 1.5;
+  white-space: pre-wrap;
+}
+
+[data-page="stats"] [data-slot="compare-model-modal-description"] > span {
+  position: absolute;
+  right: 0;
+  bottom: 0;
+  left: 0;
+  height: 32px;
+  background: linear-gradient(to bottom, transparent, var(--stats-bg));
+  pointer-events: none;
+}
+
+[data-page="stats"] [data-slot="compare-model-modal-facts"] {
+  display: grid;
+  gap: 8px;
+  box-sizing: border-box;
+  min-width: 0;
+  margin: 0;
+  padding: 16px;
+  overflow: hidden;
+  background: var(--stats-bg);
+}
+
+[data-page="stats"] [data-slot="compare-model-modal-fact"] {
+  display: grid;
+  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
+  gap: 16px;
+  min-width: 0;
+  padding-bottom: 8px;
+  border-bottom: 1px solid var(--stats-line);
+  color: var(--stats-muted);
+  font-size: 11px;
+  font-weight: 500;
+  line-height: 1.5;
+}
+
+[data-page="stats"] [data-slot="compare-model-modal-fact"]:last-child {
+  padding-bottom: 0;
+  border-bottom: 0;
+}
+
+[data-page="stats"] [data-slot="compare-model-modal-fact"] dt,
+[data-page="stats"] [data-slot="compare-model-modal-fact"] dd {
+  min-width: 0;
+  margin: 0;
+  overflow: hidden;
+  text-overflow: ellipsis;
+  white-space: nowrap;
+}
+
+[data-page="stats"] [data-slot="compare-model-modal-fact"] dd {
+  color: var(--stats-text);
+  text-align: right;
+}
+
+[data-page="stats"] [data-slot="compare-model-modal-fact"] a {
+  color: inherit;
+  text-decoration: underline;
+  text-decoration-color: color-mix(in srgb, var(--stats-text) 20%, transparent);
+  text-underline-offset: 2px;
+}
+
+[data-page="stats"] [data-slot="compare-model-modal-uptime"] {
+  display: inline-flex;
+  justify-content: flex-end;
+  gap: 2px;
+}
+
+[data-page="stats"] [data-slot="compare-model-modal-uptime"] span {
+  width: 3px;
+  height: 12px;
+  background: var(--stats-layer-2);
+}
+
+[data-page="stats"] [data-slot="compare-model-modal-uptime"] span[data-active="true"] {
+  background: #198b43;
+}
+
 [data-page="stats"][data-theme="dark"],
 [data-page="stats"][data-theme="dark"],
 :root[data-stats-theme="dark"] [data-page="stats"]:not([data-theme="light"]) {
 :root[data-stats-theme="dark"] [data-page="stats"]:not([data-theme="light"]) {
   color-scheme: dark;
   color-scheme: dark;
@@ -5886,10 +6622,22 @@
   [data-page="stats"] [data-section="model-hero"],
   [data-page="stats"] [data-section="model-hero"],
   [data-page="stats"] [data-section="lab-hero"],
   [data-page="stats"] [data-section="lab-hero"],
   [data-page="stats"] [data-section="model-momentum"],
   [data-page="stats"] [data-section="model-momentum"],
-  [data-page="stats"] [data-section="model-panel"] {
+  [data-page="stats"] [data-section="model-panel"],
+  [data-page="stats"] [data-section="compare-home-hero"],
+  [data-page="stats"] [data-section="compare-home-related"] {
     padding: 64px 32px;
     padding: 64px 32px;
   }
   }
 
 
+  [data-page="stats"] [data-section="compare-home-hero"] {
+    min-height: 280px;
+    padding: 104px 32px 40px;
+  }
+
+  [data-page="stats"] [data-slot="compare-home-pattern"] {
+    width: calc(100% + 64px);
+    margin-inline: -32px;
+  }
+
   [data-page="stats"] [data-section="lab-hero"] {
   [data-page="stats"] [data-section="lab-hero"] {
     min-height: 280px;
     min-height: 280px;
     padding: 104px 32px 40px;
     padding: 104px 32px 40px;
@@ -5943,6 +6691,15 @@
     align-items: start;
     align-items: start;
   }
   }
 
 
+  [data-page="stats"] [data-slot="compare-home-hero-grid"] {
+    grid-template-columns: 1fr;
+    align-items: start;
+  }
+
+  [data-page="stats"] [data-component="compare-home-card-grid"] {
+    grid-template-columns: repeat(2, minmax(0, 1fr));
+  }
+
   [data-page="stats"] [data-section="lab-overview"] {
   [data-page="stats"] [data-section="lab-overview"] {
     grid-template-columns: repeat(2, minmax(0, 1fr));
     grid-template-columns: repeat(2, minmax(0, 1fr));
   }
   }
@@ -6165,10 +6922,87 @@
   [data-page="stats"] [data-section="model-hero"],
   [data-page="stats"] [data-section="model-hero"],
   [data-page="stats"] [data-section="lab-hero"],
   [data-page="stats"] [data-section="lab-hero"],
   [data-page="stats"] [data-section="model-momentum"],
   [data-page="stats"] [data-section="model-momentum"],
-  [data-page="stats"] [data-section="model-panel"] {
+  [data-page="stats"] [data-section="model-panel"],
+  [data-page="stats"] [data-section="compare-home-hero"],
+  [data-page="stats"] [data-section="compare-home-related"] {
     padding: 48px 24px;
     padding: 48px 24px;
   }
   }
 
 
+  [data-page="stats"] [data-section="compare-home-hero"] {
+    gap: 20px;
+    min-height: 316px;
+    padding: 72px 24px 40px;
+  }
+
+  [data-page="stats"] [data-slot="compare-home-pattern"] {
+    width: calc(100% + 48px);
+    margin-inline: -24px;
+  }
+
+  [data-page="stats"] [data-section="compare-home-hero"] h1 {
+    gap: 12px;
+    font-size: 32px;
+    line-height: 42px;
+  }
+
+  [data-page="stats"] [data-component="compare-home-breadcrumb"] {
+    flex-wrap: wrap;
+    height: auto;
+  }
+
+  [data-page="stats"] [data-component="compare-home-selector"] {
+    grid-template-columns: 1fr;
+  }
+
+  [data-page="stats"] [data-component="compare-home-selector"] button[data-slot="compare-home-select-panel"]::before,
+  [data-page="stats"] [data-component="compare-home-selector"] button[data-slot="compare-home-select-panel"]::after {
+    position: absolute;
+    top: 0;
+    bottom: 0;
+    width: 1px;
+    content: "";
+    background: var(--stats-line);
+    pointer-events: none;
+  }
+
+  [data-page="stats"] [data-component="compare-home-selector"] button[data-slot="compare-home-select-panel"]::before {
+    left: 0;
+  }
+
+  [data-page="stats"] [data-component="compare-home-selector"] button[data-slot="compare-home-select-panel"]::after {
+    right: 0;
+  }
+
+  [data-page="stats"] [data-component="compare-model-modal-scrim"] {
+    padding: 16px;
+  }
+
+  [data-page="stats"] [data-component="compare-model-modal"] {
+    grid-template-columns: 1fr;
+    width: calc(100vw - 32px);
+    height: min(520px, calc(100vh - 32px));
+  }
+
+  [data-page="stats"] [data-slot="compare-model-modal-detail"],
+  [data-page="stats"] [data-slot="compare-model-modal-divider"] {
+    display: none;
+  }
+
+  [data-page="stats"]
+    [data-component="compare-home-selector"]
+    button[data-slot="compare-home-select-panel"]
+    + button[data-slot="compare-home-select-panel"] {
+    box-shadow: inset 0 1px var(--stats-line);
+  }
+
+  [data-page="stats"] [data-section="compare-home-related"] {
+    margin-top: 24px;
+  }
+
+  [data-page="stats"] [data-component="compare-home-card-grid"] {
+    grid-template-columns: 1fr;
+  }
+
   [data-page="stats"] [data-slot="top-models-title"],
   [data-page="stats"] [data-slot="top-models-title"],
   [data-page="stats"] [data-slot="section-title"] {
   [data-page="stats"] [data-slot="section-title"] {
     margin-bottom: 32px;
     margin-bottom: 32px;
@@ -6860,6 +7694,16 @@
 }
 }
 
 
 @media (max-width: 40rem) {
 @media (max-width: 40rem) {
+  [data-page="stats"] [data-section="compare-home-hero"] h1 {
+    align-items: flex-start;
+    flex-direction: column;
+  }
+
+  [data-page="stats"] [data-slot="compare-home-hero-grid"] > p {
+    font-size: 14px;
+    line-height: 22px;
+  }
+
   [data-page="stats"] [data-slot="footer-grid"] {
   [data-page="stats"] [data-slot="footer-grid"] {
     grid-template-columns: 1fr;
     grid-template-columns: 1fr;
   }
   }