diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000000000000000000000000000000000000..5180b32be3fa68c48214f3ceb389f1b6ecacea39 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,11 @@ +node_modules +.next +.git +database +test-artifacts +*.sqlite +*.sqlite-* +*.wal +*.shm +*.log +*.tsbuildinfo diff --git a/.gitattributes b/.gitattributes index a6344aac8c09253b3b630fb776ae94478aa0275b..b5663e72c0f56ff1645179d89bce2e075e7cf18f 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,35 +1,22 @@ -*.7z filter=lfs diff=lfs merge=lfs -text -*.arrow filter=lfs diff=lfs merge=lfs -text -*.bin filter=lfs diff=lfs merge=lfs -text -*.bz2 filter=lfs diff=lfs merge=lfs -text -*.ckpt filter=lfs diff=lfs merge=lfs -text -*.ftz filter=lfs diff=lfs merge=lfs -text -*.gz filter=lfs diff=lfs merge=lfs -text -*.h5 filter=lfs diff=lfs merge=lfs -text -*.joblib filter=lfs diff=lfs merge=lfs -text -*.lfs.* filter=lfs diff=lfs merge=lfs -text -*.mlmodel filter=lfs diff=lfs merge=lfs -text -*.model filter=lfs diff=lfs merge=lfs -text -*.msgpack filter=lfs diff=lfs merge=lfs -text -*.npy filter=lfs diff=lfs merge=lfs -text -*.npz filter=lfs diff=lfs merge=lfs -text -*.onnx filter=lfs diff=lfs merge=lfs -text -*.ot filter=lfs diff=lfs merge=lfs -text -*.parquet filter=lfs diff=lfs merge=lfs -text -*.pb filter=lfs diff=lfs merge=lfs -text -*.pickle filter=lfs diff=lfs merge=lfs -text -*.pkl filter=lfs diff=lfs merge=lfs -text -*.pt filter=lfs diff=lfs merge=lfs -text -*.pth filter=lfs diff=lfs merge=lfs -text -*.rar filter=lfs diff=lfs merge=lfs -text -*.safetensors filter=lfs diff=lfs merge=lfs -text -saved_model/**/* filter=lfs diff=lfs merge=lfs -text -*.tar.* filter=lfs diff=lfs merge=lfs -text -*.tar filter=lfs diff=lfs merge=lfs -text -*.tflite filter=lfs diff=lfs merge=lfs -text -*.tgz filter=lfs diff=lfs merge=lfs -text -*.wasm filter=lfs diff=lfs merge=lfs -text -*.xz filter=lfs diff=lfs merge=lfs -text -*.zip filter=lfs diff=lfs merge=lfs -text -*.zst filter=lfs diff=lfs merge=lfs -text -*tfevents* filter=lfs diff=lfs merge=lfs -text +*.mp4 filter=lfs diff=lfs merge=lfs -text +*.pdf filter=lfs diff=lfs merge=lfs -text +public/assets_common/photos/Group_Chat.jpg filter=lfs diff=lfs merge=lfs -text +public/assets_common/photos/image_155613883779109.png filter=lfs diff=lfs merge=lfs -text +public/fonts/editorial/Inter-300.ttf filter=lfs diff=lfs merge=lfs -text +public/fonts/editorial/Inter-400.ttf filter=lfs diff=lfs merge=lfs -text +public/fonts/editorial/Inter-500.ttf filter=lfs diff=lfs merge=lfs -text +public/fonts/editorial/Inter-600.ttf filter=lfs diff=lfs merge=lfs -text +public/fonts/editorial/Inter-700.ttf filter=lfs diff=lfs merge=lfs -text +public/fonts/editorial/Inter-800.ttf filter=lfs diff=lfs merge=lfs -text +public/fonts/editorial/JetBrainsMono-400.ttf filter=lfs diff=lfs merge=lfs -text +public/fonts/editorial/JetBrainsMono-500.ttf filter=lfs diff=lfs merge=lfs -text +public/fonts/editorial/SourceSerif4-400.ttf filter=lfs diff=lfs merge=lfs -text +public/fonts/editorial/SourceSerif4-600.ttf filter=lfs diff=lfs merge=lfs -text +public/fonts/editorial/SourceSerif4-700.ttf filter=lfs diff=lfs merge=lfs -text +public/institution-logos/buaa.png filter=lfs diff=lfs merge=lfs -text +public/institution-logos/sjtu.png filter=lfs diff=lfs merge=lfs -text +public/institution-logos/tsinghua.png filter=lfs diff=lfs merge=lfs -text +public/institution-logos/ustc.png filter=lfs diff=lfs merge=lfs -text +public/style02/abstract-triview.webp filter=lfs diff=lfs merge=lfs -text +public/style02/prompt-prediction.webp filter=lfs diff=lfs merge=lfs -text +public/style02/state-annotations.webp filter=lfs diff=lfs merge=lfs -text diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..9e9968a2daa869083e12664fcc84c2cbb85c491a --- /dev/null +++ b/.gitignore @@ -0,0 +1,6 @@ +node_modules/ +.next/ +.next-*/ +test-artifacts/ +*.log +*.tsbuildinfo diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000000000000000000000000000000000000..65485cd0c5e48701749dfb2abd7c8660fed3f87c --- /dev/null +++ b/Dockerfile @@ -0,0 +1,19 @@ +FROM node:24-bookworm-slim + +WORKDIR /app + +ENV NEXT_TELEMETRY_DISABLED=1 +ENV PORT=7860 + +COPY package.json package-lock.json ./ +RUN npm ci + +COPY . . +RUN npm run build + +ENV NODE_ENV=production +ENV TRIWORLDBENCH_VIDEO_ROOT=/tmp/triworldbench/video-cases + +EXPOSE 7860 + +CMD ["sh", "-c", "npm run hf:download-dataset && npm run hf:download-video-cases && npm run hf:restore-space-assets && npx next start -H 0.0.0.0 -p ${PORT:-7860}"] diff --git a/README.md b/README.md index de5ee71e7cfd74f8e0998ef4b0c063f8a906cc74..7c9a33cdbdbceac38ecbfa34ace85628580ad490 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,19 @@ --- -title: TriWorldBench SPACE -emoji: 🏆 -colorFrom: red -colorTo: indigo +title: TriWorldBench +emoji: "🧪" +colorFrom: blue +colorTo: gray sdk: docker +app_port: 7860 pinned: false -short_description: Embodied World Model Benchmark +short_description: Multi-view world-model video evaluation. --- -Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference +# TriWorldBench + +The public TriWorldBench website presents the benchmark, leaderboard, datasets, +submission guidance, policies, and contact information. + +For hosted deployment, configure the approved dataset and operational secrets in +the Hugging Face Space settings. Runtime values and access credentials are +intentionally not stored in this repository. diff --git a/deployment-manifest.json b/deployment-manifest.json new file mode 100644 index 0000000000000000000000000000000000000000..4cbebd69e9848165f2a5dcd7e2faa9dd5e26b85f --- /dev/null +++ b/deployment-manifest.json @@ -0,0 +1,21 @@ +{ + "schema": 2, + "generated_at_utc": "2026-07-27T17:57:13.401083+00:00", + "web_tree_sha256": "7abdd66073cb12d2f8b7290c371d00c5e1648c4db730c46a12eb612d58d7e099", + "source_file_count": 88, + "release_contract": { + "web_source": "TriWorldBench/web", + "local_database": "database/database.sqlite", + "dataset_file": "database.sqlite", + "dataset_video_prefix": "video-cases", + "space_database_path": "/tmp/triworldbench/database.sqlite", + "space_video_path": "/tmp/triworldbench/video-cases" + }, + "database_release": { + "dataset_file": "database.sqlite", + "snapshot_sha256": "49785aa2a116ea07f50e51bb7d141b18151bf2dafbdf406b06b6bb5f9669716f", + "data_version": 237, + "video_count": 24, + "video_prefix": "video-cases" + } +} diff --git a/next-env.d.ts b/next-env.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..5efd594a08e490b3323afd6348a5256e955dc153 --- /dev/null +++ b/next-env.d.ts @@ -0,0 +1,6 @@ +/// +/// +/// + +// NOTE: This file should not be edited +// see https://nextjs.org/docs/app/api-reference/config/typescript for more information. diff --git a/next.config.ts b/next.config.ts new file mode 100644 index 0000000000000000000000000000000000000000..ed3f373c8f839fa9791e5c10980f9e6e446d6de6 --- /dev/null +++ b/next.config.ts @@ -0,0 +1,13 @@ +import type { NextConfig } from "next"; + +const nextConfig: NextConfig = { + // An optional isolated directory supports parallel local builds. + distDir: process.env.TRIWORLDBENCH_NEXT_DIST_DIR || ".next", + outputFileTracingRoot: __dirname, + // Public styles and static assets are imported directly by the site layout. + images: { + remotePatterns: [], + }, +}; + +export default nextConfig; diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000000000000000000000000000000000000..e9592e6bf73705348b70e3bfd7988d5d54e17167 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,973 @@ +{ + "name": "triworldbench-web", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "triworldbench-web", + "version": "1.0.0", + "dependencies": { + "next": "^15.1.0", + "react": "^19.0.0", + "react-dom": "^19.0.0", + "react-icons": "5.7.0" + }, + "devDependencies": { + "@types/node": "^22.0.0", + "@types/react": "^19.0.0", + "@types/react-dom": "^19.0.0", + "typescript": "^5.7.0" + } + }, + "node_modules/@emnapi/runtime": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.11.0.tgz", + "integrity": "sha512-55coeOFKHv1ywEcUXJtWU5f+Jr/W5tZDvZig8DLKSwUN1JpROQ4rk/SNOQiFWmaR/VKF4zuFyW1B8JduOSv6Pg==", + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@img/colour": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@img/colour/-/colour-1.1.0.tgz", + "integrity": "sha512-Td76q7j57o/tLVdgS746cYARfSyxk8iEfRxewL9h4OMzYhbW4TAcppl0mT4eyqXddh6L/jwoM75mo7ixa/pCeQ==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/@img/sharp-darwin-arm64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.34.5.tgz", + "integrity": "sha512-imtQ3WMJXbMY4fxb/Ndp6HBTNVtWCUI0WdobyheGf5+ad6xX8VIDO8u2xE4qc/fr08CKG/7dDseFtn6M6g/r3w==", + "cpu": [ + "arm64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-darwin-arm64": "1.2.4" + } + }, + "node_modules/@img/sharp-darwin-x64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.34.5.tgz", + "integrity": "sha512-YNEFAF/4KQ/PeW0N+r+aVVsoIY0/qxxikF2SWdp+NRkmMB7y9LBZAVqQ4yhGCm/H3H270OSykqmQMKLBhBJDEw==", + "cpu": [ + "x64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-darwin-x64": "1.2.4" + } + }, + "node_modules/@img/sharp-libvips-darwin-arm64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.2.4.tgz", + "integrity": "sha512-zqjjo7RatFfFoP0MkQ51jfuFZBnVE2pRiaydKJ1G/rHZvnsrHAOcQALIi9sA5co5xenQdTugCvtb1cuf78Vf4g==", + "cpu": [ + "arm64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "darwin" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-darwin-x64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.2.4.tgz", + "integrity": "sha512-1IOd5xfVhlGwX+zXv2N93k0yMONvUlANylbJw1eTah8K/Jtpi15KC+WSiaX/nBmbm2HxRM1gZ0nSdjSsrZbGKg==", + "cpu": [ + "x64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "darwin" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-arm": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.2.4.tgz", + "integrity": "sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A==", + "cpu": [ + "arm" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-arm64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.2.4.tgz", + "integrity": "sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw==", + "cpu": [ + "arm64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-ppc64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-ppc64/-/sharp-libvips-linux-ppc64-1.2.4.tgz", + "integrity": "sha512-FMuvGijLDYG6lW+b/UvyilUWu5Ayu+3r2d1S8notiGCIyYU/76eig1UfMmkZ7vwgOrzKzlQbFSuQfgm7GYUPpA==", + "cpu": [ + "ppc64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-riscv64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-riscv64/-/sharp-libvips-linux-riscv64-1.2.4.tgz", + "integrity": "sha512-oVDbcR4zUC0ce82teubSm+x6ETixtKZBh/qbREIOcI3cULzDyb18Sr/Wcyx7NRQeQzOiHTNbZFF1UwPS2scyGA==", + "cpu": [ + "riscv64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-s390x": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.2.4.tgz", + "integrity": "sha512-qmp9VrzgPgMoGZyPvrQHqk02uyjA0/QrTO26Tqk6l4ZV0MPWIW6LTkqOIov+J1yEu7MbFQaDpwdwJKhbJvuRxQ==", + "cpu": [ + "s390x" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-x64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.2.4.tgz", + "integrity": "sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw==", + "cpu": [ + "x64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linuxmusl-arm64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.2.4.tgz", + "integrity": "sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw==", + "cpu": [ + "arm64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linuxmusl-x64": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.2.4.tgz", + "integrity": "sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg==", + "cpu": [ + "x64" + ], + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-linux-arm": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.34.5.tgz", + "integrity": "sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw==", + "cpu": [ + "arm" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-arm": "1.2.4" + } + }, + "node_modules/@img/sharp-linux-arm64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.34.5.tgz", + "integrity": "sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg==", + "cpu": [ + "arm64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-arm64": "1.2.4" + } + }, + "node_modules/@img/sharp-linux-ppc64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-ppc64/-/sharp-linux-ppc64-0.34.5.tgz", + "integrity": "sha512-7zznwNaqW6YtsfrGGDA6BRkISKAAE1Jo0QdpNYXNMHu2+0dTrPflTLNkpc8l7MUP5M16ZJcUvysVWWrMefZquA==", + "cpu": [ + "ppc64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-ppc64": "1.2.4" + } + }, + "node_modules/@img/sharp-linux-riscv64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-riscv64/-/sharp-linux-riscv64-0.34.5.tgz", + "integrity": "sha512-51gJuLPTKa7piYPaVs8GmByo7/U7/7TZOq+cnXJIHZKavIRHAP77e3N2HEl3dgiqdD/w0yUfiJnII77PuDDFdw==", + "cpu": [ + "riscv64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-riscv64": "1.2.4" + } + }, + "node_modules/@img/sharp-linux-s390x": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.34.5.tgz", + "integrity": "sha512-nQtCk0PdKfho3eC5MrbQoigJ2gd1CgddUMkabUj+rBevs8tZ2cULOx46E7oyX+04WGfABgIwmMC0VqieTiR4jg==", + "cpu": [ + "s390x" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-s390x": "1.2.4" + } + }, + "node_modules/@img/sharp-linux-x64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.34.5.tgz", + "integrity": "sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ==", + "cpu": [ + "x64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-x64": "1.2.4" + } + }, + "node_modules/@img/sharp-linuxmusl-arm64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.34.5.tgz", + "integrity": "sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg==", + "cpu": [ + "arm64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linuxmusl-arm64": "1.2.4" + } + }, + "node_modules/@img/sharp-linuxmusl-x64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.34.5.tgz", + "integrity": "sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q==", + "cpu": [ + "x64" + ], + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linuxmusl-x64": "1.2.4" + } + }, + "node_modules/@img/sharp-wasm32": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.34.5.tgz", + "integrity": "sha512-OdWTEiVkY2PHwqkbBI8frFxQQFekHaSSkUIJkwzclWZe64O1X4UlUjqqqLaPbUpMOQk6FBu/HtlGXNblIs0huw==", + "cpu": [ + "wasm32" + ], + "license": "Apache-2.0 AND LGPL-3.0-or-later AND MIT", + "optional": true, + "dependencies": { + "@emnapi/runtime": "^1.7.0" + }, + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-win32-arm64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-arm64/-/sharp-win32-arm64-0.34.5.tgz", + "integrity": "sha512-WQ3AgWCWYSb2yt+IG8mnC6Jdk9Whs7O0gxphblsLvdhSpSTtmu69ZG1Gkb6NuvxsNACwiPV6cNSZNzt0KPsw7g==", + "cpu": [ + "arm64" + ], + "license": "Apache-2.0 AND LGPL-3.0-or-later", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-win32-ia32": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.34.5.tgz", + "integrity": "sha512-FV9m/7NmeCmSHDD5j4+4pNI8Cp3aW+JvLoXcTUo0IqyjSfAZJ8dIUmijx1qaJsIiU+Hosw6xM5KijAWRJCSgNg==", + "cpu": [ + "ia32" + ], + "license": "Apache-2.0 AND LGPL-3.0-or-later", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-win32-x64": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.34.5.tgz", + "integrity": "sha512-+29YMsqY2/9eFEiW93eqWnuLcWcufowXewwSNIT6UwZdUUCrM3oFjMWH/Z6/TMmb4hlFenmfAVbpWeup2jryCw==", + "cpu": [ + "x64" + ], + "license": "Apache-2.0 AND LGPL-3.0-or-later", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@next/env": { + "version": "15.5.19", + "resolved": "https://registry.npmjs.org/@next/env/-/env-15.5.19.tgz", + "integrity": "sha512-sWWluFvcv5v3Fxznmf2ZfjyoVQt/64oCnYqS90inQWGzMPK1VjvekPiz3OPHKmFT30EnHrjlbyaHLt3M0vWabw==", + "license": "MIT" + }, + "node_modules/@next/swc-darwin-arm64": { + "version": "15.5.19", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-15.5.19.tgz", + "integrity": "sha512-jx9wWlTKueHKPvVOndyr7WuaevWCkuYqsQ8gC0TMPKAVWG3MhcdMrjfo9tvIZNXd0QOUYXXvAcZ325y8Uq7uzg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-darwin-x64": { + "version": "15.5.19", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-15.5.19.tgz", + "integrity": "sha512-291KFcsIQ3OenRdiUDFOR6W3wezzH4auENXm1gbm1Bjd4ANMMRgxPrWTUztQN43BnVoVuMnHCrLeECIMwgFKbA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-arm64-gnu": { + "version": "15.5.19", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-15.5.19.tgz", + "integrity": "sha512-WeH+nelQyyMeE2f8FxBRZNrGipya5zHZV2vjzfCOAYyiI6am+NbnWAAldOBFQBB2w0DjJcsvrKqoFT2b7+5YoA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-arm64-musl": { + "version": "15.5.19", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-15.5.19.tgz", + "integrity": "sha512-5xTOE0lDlDCSSfp+BAif7j17VRRCjWp//ZPZy6NI0QpdrhxtQnsZguSx0xAAZ0c9XZLrLLwCe/XVe5YPrRilKw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-x64-gnu": { + "version": "15.5.19", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-15.5.19.tgz", + "integrity": "sha512-LTxRmMgqqMv05Had879W00Fm53quiJd3Zuz8h1JSNJ3nGSlbZ/7Tjs1tKyScgN3Au3t3MyPsjPlq60fMmSHLsg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-x64-musl": { + "version": "15.5.19", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-15.5.19.tgz", + "integrity": "sha512-eoNQSpA5PQfB9wBO4RA47MTDXWz1fizy9Y3Z6e4DetYIF3dvjuu8sj7aIGn/bFCU6lnFzTK34NtCaffP4NsQ7Q==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-win32-arm64-msvc": { + "version": "15.5.19", + "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-15.5.19.tgz", + "integrity": "sha512-6UNt2dFuCHOe446sm/Kp69nUe8/wIhnh9bm6Xcqw4qEWCOppLMOvhTBVgvM7invVUNr4SPpP6NOQsACtn2IN9Q==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-win32-x64-msvc": { + "version": "15.5.19", + "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-15.5.19.tgz", + "integrity": "sha512-PhmojAHyqMne56HBLGu9dhDnHPuFmEjrXSQMM/nW0J6j849lk3ESrVtqNJcCk8CKOV7brpTTbaYAjwKPzKM69w==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@swc/helpers": { + "version": "0.5.15", + "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.15.tgz", + "integrity": "sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.8.0" + } + }, + "node_modules/@types/node": { + "version": "22.19.20", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.19.20.tgz", + "integrity": "sha512-6tELRwSDYWW9EdZhbeZmYGZ1/7Djkt+Ah3/ScEYT9cDord7UJzasR/4D3VONg9tQI5CDp+/CZC1AXj2pCFOvpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~6.21.0" + } + }, + "node_modules/@types/react": { + "version": "19.2.17", + "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.17.tgz", + "integrity": "sha512-MXfmqaVPEVgkBT/aY0aGCkRWWtByiYQXo3xdQ8r5RzuFrPiRn8Gar2tQdXSUQ2GKV3bkXckek89V8wQBY2Q/Aw==", + "dev": true, + "license": "MIT", + "dependencies": { + "csstype": "^3.2.2" + } + }, + "node_modules/@types/react-dom": { + "version": "19.2.3", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.2.3.tgz", + "integrity": "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@types/react": "^19.2.0" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001797", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001797.tgz", + "integrity": "sha512-l8xKG+gwAIExZGl9FrF7KUwuOmk6wbEPC9Xoy/RtnWv1XG0Q4LFlagaLpUv3Kiza3W/wm27zy0yWJEieYKAP6w==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "CC-BY-4.0" + }, + "node_modules/client-only": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/client-only/-/client-only-0.0.1.tgz", + "integrity": "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==", + "license": "MIT" + }, + "node_modules/csstype": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", + "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/detect-libc": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", + "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", + "license": "Apache-2.0", + "optional": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/nanoid": { + "version": "3.3.12", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.12.tgz", + "integrity": "sha512-ZB9RH/39qpq5Vu6Y+NmUaFhQR6pp+M2Xt76XBnEwDaGcVAqhlvxrl3B2bKS5D3NH3QR76v3aSrKaF/Kiy7lEtQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/next": { + "version": "15.5.19", + "resolved": "https://registry.npmjs.org/next/-/next-15.5.19.tgz", + "integrity": "sha512-xNOW6tYshGX1/Oi3F8uuk4gpDeWsSUE/1Z0G5uUMekIxaQ0xc03UXd9II0VQHYMWviMeA0OHpJFAKsHf8bTYVg==", + "license": "MIT", + "dependencies": { + "@next/env": "15.5.19", + "@swc/helpers": "0.5.15", + "caniuse-lite": "^1.0.30001579", + "postcss": "8.4.31", + "styled-jsx": "5.1.6" + }, + "bin": { + "next": "dist/bin/next" + }, + "engines": { + "node": "^18.18.0 || ^19.8.0 || >= 20.0.0" + }, + "optionalDependencies": { + "@next/swc-darwin-arm64": "15.5.19", + "@next/swc-darwin-x64": "15.5.19", + "@next/swc-linux-arm64-gnu": "15.5.19", + "@next/swc-linux-arm64-musl": "15.5.19", + "@next/swc-linux-x64-gnu": "15.5.19", + "@next/swc-linux-x64-musl": "15.5.19", + "@next/swc-win32-arm64-msvc": "15.5.19", + "@next/swc-win32-x64-msvc": "15.5.19", + "sharp": "^0.34.3" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.1.0", + "@playwright/test": "^1.51.1", + "babel-plugin-react-compiler": "*", + "react": "^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0", + "react-dom": "^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0", + "sass": "^1.3.0" + }, + "peerDependenciesMeta": { + "@opentelemetry/api": { + "optional": true + }, + "@playwright/test": { + "optional": true + }, + "babel-plugin-react-compiler": { + "optional": true + }, + "sass": { + "optional": true + } + } + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "license": "ISC" + }, + "node_modules/postcss": { + "version": "8.4.31", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz", + "integrity": "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.6", + "picocolors": "^1.0.0", + "source-map-js": "^1.0.2" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/react": { + "version": "19.2.7", + "resolved": "https://registry.npmjs.org/react/-/react-19.2.7.tgz", + "integrity": "sha512-HNe9WslTbXmFK8o8cmwgAeJFSBvt1bPdHCVKtaaV+WlAN36mpT4hcRpwbf3fY56ar2oIXzsBpOAiIRHAdY0OlQ==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-dom": { + "version": "19.2.7", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.7.tgz", + "integrity": "sha512-t0BRVXvbiE/o20Hfw669rLbMCDWtYZLvmJigy2f0MxsXF+71pxhR3xOkspmsO8h3ZlNzyibAmtCa3l4lYKk6gQ==", + "license": "MIT", + "dependencies": { + "scheduler": "^0.27.0" + }, + "peerDependencies": { + "react": "^19.2.7" + } + }, + "node_modules/react-icons": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/react-icons/-/react-icons-5.7.0.tgz", + "integrity": "sha512-LBLy340Rzqy6+/yVhZKT3B/QpP1BZaesGqasf09HPOBzRarcDIFH0WwXlXQfE7q7ipxK4MSiC5DIBWURCny6fw==", + "license": "MIT", + "peerDependencies": { + "react": "*" + } + }, + "node_modules/scheduler": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.27.0.tgz", + "integrity": "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==", + "license": "MIT" + }, + "node_modules/semver": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.4.tgz", + "integrity": "sha512-rUCObTnP32Q08R2uuIrt7r9PlEonuTmtuXYcW6s5kjdlj3xbnwe+21yXptAUYcMAABLkYYTtnmzb3w3EDZfueA==", + "license": "ISC", + "optional": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/sharp": { + "version": "0.34.5", + "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.34.5.tgz", + "integrity": "sha512-Ou9I5Ft9WNcCbXrU9cMgPBcCK8LiwLqcbywW3t4oDV37n1pzpuNLsYiAV8eODnjbtQlSDwZ2cUEeQz4E54Hltg==", + "hasInstallScript": true, + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "@img/colour": "^1.0.0", + "detect-libc": "^2.1.2", + "semver": "^7.7.3" + }, + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-darwin-arm64": "0.34.5", + "@img/sharp-darwin-x64": "0.34.5", + "@img/sharp-libvips-darwin-arm64": "1.2.4", + "@img/sharp-libvips-darwin-x64": "1.2.4", + "@img/sharp-libvips-linux-arm": "1.2.4", + "@img/sharp-libvips-linux-arm64": "1.2.4", + "@img/sharp-libvips-linux-ppc64": "1.2.4", + "@img/sharp-libvips-linux-riscv64": "1.2.4", + "@img/sharp-libvips-linux-s390x": "1.2.4", + "@img/sharp-libvips-linux-x64": "1.2.4", + "@img/sharp-libvips-linuxmusl-arm64": "1.2.4", + "@img/sharp-libvips-linuxmusl-x64": "1.2.4", + "@img/sharp-linux-arm": "0.34.5", + "@img/sharp-linux-arm64": "0.34.5", + "@img/sharp-linux-ppc64": "0.34.5", + "@img/sharp-linux-riscv64": "0.34.5", + "@img/sharp-linux-s390x": "0.34.5", + "@img/sharp-linux-x64": "0.34.5", + "@img/sharp-linuxmusl-arm64": "0.34.5", + "@img/sharp-linuxmusl-x64": "0.34.5", + "@img/sharp-wasm32": "0.34.5", + "@img/sharp-win32-arm64": "0.34.5", + "@img/sharp-win32-ia32": "0.34.5", + "@img/sharp-win32-x64": "0.34.5" + } + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/styled-jsx": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/styled-jsx/-/styled-jsx-5.1.6.tgz", + "integrity": "sha512-qSVyDTeMotdvQYoHWLNGwRFJHC+i+ZvdBRYosOFgC+Wg1vx4frN2/RG/NA7SYqqvKNLf39P2LSRA2pu6n0XYZA==", + "license": "MIT", + "dependencies": { + "client-only": "0.0.1" + }, + "engines": { + "node": ">= 12.0.0" + }, + "peerDependencies": { + "react": ">= 16.8.0 || 17.x.x || ^18.0.0-0 || ^19.0.0-0" + }, + "peerDependenciesMeta": { + "@babel/core": { + "optional": true + }, + "babel-plugin-macros": { + "optional": true + } + } + }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "license": "0BSD" + }, + "node_modules/typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/undici-types": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", + "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", + "dev": true, + "license": "MIT" + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000000000000000000000000000000000000..1ebc8d4eddd02a717ec24779a9fc550910d458e7 --- /dev/null +++ b/package.json @@ -0,0 +1,26 @@ +{ + "name": "triworldbench-web", + "version": "1.0.0", + "private": true, + "description": "Public read-only website for TriWorldBench.", + "scripts": { + "dev": "next dev --turbo", + "build": "next build", + "start": "next start", + "hf:download-dataset": "node scripts/download-dataset.mjs", + "hf:download-video-cases": "node scripts/download-video-cases.mjs", + "hf:restore-space-assets": "node scripts/restore-space-assets.mjs" + }, + "dependencies": { + "next": "^15.1.0", + "react": "^19.0.0", + "react-dom": "^19.0.0", + "react-icons": "5.7.0" + }, + "devDependencies": { + "@types/node": "^22.0.0", + "@types/react": "^19.0.0", + "@types/react-dom": "^19.0.0", + "typescript": "^5.7.0" + } +} diff --git a/public/assets_common/photos/Group_Chat.jpg b/public/assets_common/photos/Group_Chat.jpg new file mode 100644 index 0000000000000000000000000000000000000000..0eca5c4b0a14297e73e02271496282f41f22cac2 --- /dev/null +++ b/public/assets_common/photos/Group_Chat.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:630a5e7d3e46351f7da007875968430ee14bb72c2c7e27d91fb85947ed48726f +size 140481 diff --git a/public/assets_common/photos/image_155613883779109.png b/public/assets_common/photos/image_155613883779109.png new file mode 100644 index 0000000000000000000000000000000000000000..12865b4571aef3a3c8a24208584a0c2158ae4c2b --- /dev/null +++ b/public/assets_common/photos/image_155613883779109.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:0e269abd795fbf8ad6ea038a986aebcb12e1cf54f31f87696a12fa90e5e0936d +size 961066 diff --git a/public/fonts/editorial/Inter-300.ttf b/public/fonts/editorial/Inter-300.ttf new file mode 100644 index 0000000000000000000000000000000000000000..2fbfdcfc298ca6a1a7657facdb4abbe4f3d93380 --- /dev/null +++ b/public/fonts/editorial/Inter-300.ttf @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d0f4bc7faca468376e3db9b5e57afcdc2192134c9ac82a9511f32767b56853a4 +size 325748 diff --git a/public/fonts/editorial/Inter-400.ttf b/public/fonts/editorial/Inter-400.ttf new file mode 100644 index 0000000000000000000000000000000000000000..6d70dd254147555a2ecbae6bb82f1933bdf56cca --- /dev/null +++ b/public/fonts/editorial/Inter-400.ttf @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1b08e7fc267a5c7e1d614100f604b83e7e8a0be241f0f288faa2b3ac93a683ba +size 324820 diff --git a/public/fonts/editorial/Inter-500.ttf b/public/fonts/editorial/Inter-500.ttf new file mode 100644 index 0000000000000000000000000000000000000000..0935d61a35c90d565d5f1c0550e29fae973302a3 --- /dev/null +++ b/public/fonts/editorial/Inter-500.ttf @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:8c883f63b2c4157d997319f2c8bc6995ed4357ef371940d31ca159004a4aae63 +size 325304 diff --git a/public/fonts/editorial/Inter-600.ttf b/public/fonts/editorial/Inter-600.ttf new file mode 100644 index 0000000000000000000000000000000000000000..8a282e94a2402e951dc81f2fff1a76b9b0fa6f80 --- /dev/null +++ b/public/fonts/editorial/Inter-600.ttf @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:e7a1aaf7eda9f2fad4131725fa556265ec75ca7b2d756260173a040363e8d4f7 +size 326048 diff --git a/public/fonts/editorial/Inter-700.ttf b/public/fonts/editorial/Inter-700.ttf new file mode 100644 index 0000000000000000000000000000000000000000..5279191f647346135721f80a4ba572b9c77522aa --- /dev/null +++ b/public/fonts/editorial/Inter-700.ttf @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:b37284b5701b6b168dfc770aa1a4ac492106422fd3ba76bc7641e37434e8019c +size 326468 diff --git a/public/fonts/editorial/Inter-800.ttf b/public/fonts/editorial/Inter-800.ttf new file mode 100644 index 0000000000000000000000000000000000000000..dc72e2091e0f508a09aa8294c158c10c78a639f1 --- /dev/null +++ b/public/fonts/editorial/Inter-800.ttf @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:eec66af7f2337bd34fe6e801cf92ededcb57a20c0d7bc40a61d4eefcbe3dd40c +size 327324 diff --git a/public/fonts/editorial/JetBrainsMono-400.ttf b/public/fonts/editorial/JetBrainsMono-400.ttf new file mode 100644 index 0000000000000000000000000000000000000000..270b4c3ab2d249441289730d06bd2e4b540f8767 --- /dev/null +++ b/public/fonts/editorial/JetBrainsMono-400.ttf @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:44ce4a84f20d60f24539bd0cef11f79c29e38609e0f8adf18551c9794a5d9dc3 +size 112172 diff --git a/public/fonts/editorial/JetBrainsMono-500.ttf b/public/fonts/editorial/JetBrainsMono-500.ttf new file mode 100644 index 0000000000000000000000000000000000000000..8d83f6f550b45f5e5203c43075bd943db73a5539 --- /dev/null +++ b/public/fonts/editorial/JetBrainsMono-500.ttf @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:3386a05f6ece969e4537de6be894170d20558e82f7d56c8c5d332972ef172160 +size 112204 diff --git a/public/fonts/editorial/SourceSerif4-400.ttf b/public/fonts/editorial/SourceSerif4-400.ttf new file mode 100644 index 0000000000000000000000000000000000000000..28e48a3c40b9a47513067de328b64ca00d6fdc6a --- /dev/null +++ b/public/fonts/editorial/SourceSerif4-400.ttf @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:8ca4d603b02214e2723f2bdf6c83632551942c9b06702e2bdbcf07f0d8714809 +size 194464 diff --git a/public/fonts/editorial/SourceSerif4-600.ttf b/public/fonts/editorial/SourceSerif4-600.ttf new file mode 100644 index 0000000000000000000000000000000000000000..8a3adf79379ab15df2ea3ed7c2952bcf9ca11919 --- /dev/null +++ b/public/fonts/editorial/SourceSerif4-600.ttf @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:3f471d65b233b067f5d7bfebb9b598994dd513a41f9fb4d900c20ae9d30f242c +size 194800 diff --git a/public/fonts/editorial/SourceSerif4-700.ttf b/public/fonts/editorial/SourceSerif4-700.ttf new file mode 100644 index 0000000000000000000000000000000000000000..058600ddfd3e8f9cb64403f94a79bacdd18103d6 --- /dev/null +++ b/public/fonts/editorial/SourceSerif4-700.ttf @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:00441a2f2ffdad0957667668cb537faa23b3f16377713cbbe3a2c32ad2095f5a +size 194760 diff --git a/public/institution-logos/buaa.png b/public/institution-logos/buaa.png new file mode 100644 index 0000000000000000000000000000000000000000..cb42b7122fa21c36d851e18650e804306adc81bb --- /dev/null +++ b/public/institution-logos/buaa.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:6de1ebf4e85cb72eb8f8e4d24ed0a72a8cea5ddcc6976376ad6b3b93e280b9d9 +size 338254 diff --git a/public/institution-logos/pku.png b/public/institution-logos/pku.png new file mode 100644 index 0000000000000000000000000000000000000000..6ada1ba7967b35c7c8b2b0080985f58191d15008 Binary files /dev/null and b/public/institution-logos/pku.png differ diff --git a/public/institution-logos/sjtu.png b/public/institution-logos/sjtu.png new file mode 100644 index 0000000000000000000000000000000000000000..300f6c25927e458d8285142855320d12fa937867 --- /dev/null +++ b/public/institution-logos/sjtu.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:e88ae88ee8d630dd86f962d656f051cc8d83d71dab7e76beb4678bbedbd8d819 +size 461107 diff --git a/public/institution-logos/tsinghua.png b/public/institution-logos/tsinghua.png new file mode 100644 index 0000000000000000000000000000000000000000..23b7d39e1be53ed9d74ddf97800206727bffdcf4 --- /dev/null +++ b/public/institution-logos/tsinghua.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:3141eb124bef38775023c2b6507d985dab00d9d127e30c3b1585c1971e7a0ddc +size 353191 diff --git a/public/institution-logos/ustc.png b/public/institution-logos/ustc.png new file mode 100644 index 0000000000000000000000000000000000000000..a4214d18b3497fe764b166f574fe83372a625093 --- /dev/null +++ b/public/institution-logos/ustc.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:36242e96b162348f0f4818fb83f77d319566557b891b1b42fc8beb1fac22f543 +size 365159 diff --git a/public/style02/abstract-triview.webp b/public/style02/abstract-triview.webp new file mode 100644 index 0000000000000000000000000000000000000000..0cb01bd6ac7d1a26c88d0ace9982044044f4710a --- /dev/null +++ b/public/style02/abstract-triview.webp @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:9434265d96f0d5147efee135bf1306e06e83a7d6f81ebdb7b29d8b3481790927 +size 286102 diff --git a/public/style02/prompt-prediction.webp b/public/style02/prompt-prediction.webp new file mode 100644 index 0000000000000000000000000000000000000000..6b35feac3c80234afc7d61318a572741d6e4f40e --- /dev/null +++ b/public/style02/prompt-prediction.webp @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:291167e1e00d160f814c699c0e8ce130a7b7fbd860bd5f8f479fe42ec966022f +size 512570 diff --git a/public/style02/state-annotations.webp b/public/style02/state-annotations.webp new file mode 100644 index 0000000000000000000000000000000000000000..dc619f993be6f9b7cfa0697da6e7a841a246ca1d --- /dev/null +++ b/public/style02/state-annotations.webp @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:3f0162ceeeece60d2aa036df64ca91e7ee12873ac6db72fb21c1c32eeaf524da +size 103532 diff --git a/scripts/download-dataset.mjs b/scripts/download-dataset.mjs new file mode 100644 index 0000000000000000000000000000000000000000..522e883742d8d85e8cecf3a530f58ec7756f553c --- /dev/null +++ b/scripts/download-dataset.mjs @@ -0,0 +1,35 @@ +import fs from "node:fs"; +import path from "node:path"; + +const repository = process.env.HF_DATASET_REPO; +const fileName = process.env.HF_DATASET_FILE || "database.sqlite"; +const revision = process.env.HF_REVISION || "main"; +const token = process.env.HF_TOKEN; +const targetPath = + process.env.TRIWORLDBENCH_DB_PATH || + path.join("/tmp", "triworldbench", fileName); + +if (!repository) { + console.error("A Hugging Face Dataset repository must be configured before startup."); + process.exit(1); +} + +const url = `https://huggingface.co/datasets/${repository}/resolve/${revision}/${fileName}`; +const headers = token ? { Authorization: `Bearer ${token}` } : {}; +const response = await fetch(url, { headers }); + +if (!response.ok) { + console.error(`Database download failed: ${response.status} ${response.statusText}`); + process.exit(1); +} + +const database = Buffer.from(await response.arrayBuffer()); +if (database.length < 100 || database.subarray(0, 16).toString("binary") !== "SQLite format 3\u0000") { + console.error("Database download returned a file that is not a valid SQLite database."); + process.exit(1); +} +fs.mkdirSync(path.dirname(targetPath), { recursive: true }); +const temporaryPath = `${targetPath}.download-${process.pid}`; +fs.writeFileSync(temporaryPath, database, { mode: 0o600 }); +fs.renameSync(temporaryPath, targetPath); +console.log(`Downloaded the configured database revision ${revision}.`); diff --git a/scripts/download-video-cases.mjs b/scripts/download-video-cases.mjs new file mode 100644 index 0000000000000000000000000000000000000000..b46ce87b72addea6a3b1d6acd307822cee99c5a0 --- /dev/null +++ b/scripts/download-video-cases.mjs @@ -0,0 +1,84 @@ +import fs from "node:fs/promises"; +import path from "node:path"; +import { fileURLToPath } from "node:url"; + +const scriptDirectory = path.dirname(fileURLToPath(import.meta.url)); +const manifest = JSON.parse( + await fs.readFile(path.join(scriptDirectory, "video-cases-manifest.json"), "utf8") +); +const repository = (process.env.HF_VIDEO_DATASET_REPO || process.env.HF_DATASET_REPO || "").trim(); +const revision = (process.env.HF_VIDEO_REVISION || process.env.HF_REVISION || "main").trim(); +const prefix = (process.env.HF_VIDEO_DATASET_PREFIX || "video-cases").trim().replace(/^\/+|\/+$/g, ""); +const token = process.env.HF_TOKEN; +const targetRoot = path.resolve( + process.env.TRIWORLDBENCH_VIDEO_ROOT || path.join("/tmp", "triworldbench", "video-cases") +); + +if (!repository || repository.split("/").length !== 2) { + throw new Error("HF_VIDEO_DATASET_REPO or HF_DATASET_REPO must use owner/repository format."); +} +if (!token) { + throw new Error("HF_TOKEN is required to download private Dataset videos."); +} +if (!prefix || prefix.split("/").some((part) => !part || part === "." || part === "..")) { + throw new Error("HF_VIDEO_DATASET_PREFIX must be a safe relative Dataset path."); +} +if (!Array.isArray(manifest.files) || !manifest.files.length) { + throw new Error("The video-cases manifest is empty or invalid."); +} + +function validateRelativeVideo(value) { + if (typeof value !== "string" || !/^(clean|random)\/[a-zA-Z0-9()[\]._ -]+\.mp4$/.test(value)) { + throw new Error(`Unsafe video manifest entry: ${String(value)}`); + } + return value; +} + +function encodedPath(value) { + return value.split("/").map(encodeURIComponent).join("/"); +} + +function videoUrl(relativePath) { + const repo = repository.split("/").map(encodeURIComponent).join("/"); + return `https://huggingface.co/datasets/${repo}/resolve/${encodeURIComponent(revision)}/${encodedPath(`${prefix}/${relativePath}`)}`; +} + +function assertMp4(contents, relativePath) { + if (contents.length < 12 || contents.subarray(4, 8).toString("ascii") !== "ftyp") { + throw new Error(`Downloaded file is not a valid MP4 container: ${relativePath}`); + } +} + +async function download(relativePath) { + const response = await fetch(videoUrl(relativePath), { + headers: { Authorization: `Bearer ${token}` }, + redirect: "follow", + }); + if (!response.ok) { + throw new Error(`Video download failed for ${relativePath}: ${response.status} ${response.statusText}`); + } + const contents = Buffer.from(await response.arrayBuffer()); + assertMp4(contents, relativePath); + + const targetPath = path.resolve(targetRoot, relativePath); + if (!targetPath.startsWith(targetRoot + path.sep)) { + throw new Error(`Video target escaped the configured root: ${relativePath}`); + } + await fs.mkdir(path.dirname(targetPath), { recursive: true, mode: 0o700 }); + const temporaryPath = `${targetPath}.download-${process.pid}`; + await fs.writeFile(temporaryPath, contents, { mode: 0o600 }); + await fs.rename(temporaryPath, targetPath); +} + +const files = manifest.files.map(validateRelativeVideo); +const concurrency = Math.min(4, files.length); +let cursor = 0; +await Promise.all(Array.from({ length: concurrency }, async () => { + while (cursor < files.length) { + const index = cursor; + cursor += 1; + await download(files[index]); + } +})); + +console.log(`Downloaded ${files.length} private video cases to the runtime volume.`); diff --git a/scripts/restore-space-assets.mjs b/scripts/restore-space-assets.mjs new file mode 100644 index 0000000000000000000000000000000000000000..71787d0969f6ea6a665afe37aaf4b304ae3f4fc0 --- /dev/null +++ b/scripts/restore-space-assets.mjs @@ -0,0 +1,66 @@ +import fs from "node:fs/promises"; +import path from "node:path"; + +const pointerPrefix = "version https://git-lfs.github.com/spec/v1"; +const publicRoot = path.join(process.cwd(), "public"); +const spaceRepo = process.env.TRIWORLDBENCH_SPACE_REPO?.trim(); +const revision = process.env.HF_REVISION?.trim() || "main"; +const assetExtensions = new Set([".gif", ".jpeg", ".jpg", ".mp4", ".pdf", ".png", ".svg", ".webp"]); + +async function collectFiles(directory) { + const entries = await fs.readdir(directory, { withFileTypes: true }); + const files = []; + for (const entry of entries) { + const entryPath = path.join(directory, entry.name); + if (entry.isDirectory()) { + files.push(...await collectFiles(entryPath)); + } else if (entry.isFile() && assetExtensions.has(path.extname(entry.name).toLowerCase())) { + files.push(entryPath); + } + } + return files; +} + +async function isLfsPointer(filePath) { + const contents = await fs.readFile(filePath, "utf8").catch(() => ""); + return contents.startsWith(pointerPrefix); +} + +function assetUrl(relativePath) { + const encodedRepo = spaceRepo.split("/").map(encodeURIComponent).join("/"); + const encodedPath = relativePath.split("/").map(encodeURIComponent).join("/"); + return `https://huggingface.co/spaces/${encodedRepo}/resolve/${encodeURIComponent(revision)}/public/${encodedPath}`; +} + +const files = await collectFiles(publicRoot); +const pointerFiles = []; +for (const filePath of files) { + if (await isLfsPointer(filePath)) { + pointerFiles.push(filePath); + } +} + +if (!pointerFiles.length) { + console.log("No Git LFS public assets need restoration."); + process.exit(0); +} + +if (!spaceRepo || spaceRepo.split("/").length !== 2) { + throw new Error("TRIWORLDBENCH_SPACE_REPO is required to restore Git LFS public assets."); +} + +for (const filePath of pointerFiles) { + const relativePath = path.relative(publicRoot, filePath).split(path.sep).join("/"); + const response = await fetch(assetUrl(relativePath)); + if (!response.ok) { + throw new Error(`Could not restore ${relativePath}: ${response.status} ${response.statusText}`); + } + const contents = Buffer.from(await response.arrayBuffer()); + if (contents.subarray(0, pointerPrefix.length).toString("utf8") === pointerPrefix) { + throw new Error(`Resolved asset is still a Git LFS pointer: ${relativePath}`); + } + const temporaryPath = `${filePath}.restore-${process.pid}`; + await fs.writeFile(temporaryPath, contents); + await fs.rename(temporaryPath, filePath); + console.log(`Restored public asset: ${relativePath}`); +} diff --git a/scripts/video-cases-manifest.json b/scripts/video-cases-manifest.json new file mode 100644 index 0000000000000000000000000000000000000000..a80662873bd5386ac7d6da79870761639613d204 --- /dev/null +++ b/scripts/video-cases-manifest.json @@ -0,0 +1,29 @@ +{ + "schema": 1, + "files": [ + "clean/blocks_ranking_rgb.mp4", + "clean/click_bell.mp4", + "clean/grab_roller.mp4", + "clean/move_can_pot.mp4", + "clean/move_pillbottle_pad.mp4", + "clean/pick_dual_bottles.mp4", + "clean/place_cans_plasticbox.mp4", + "clean/place_dual_shoes.mp4", + "clean/place_object_stand.mp4", + "clean/scan_object.mp4", + "clean/stack_bowls_three.mp4", + "clean/turn_switch.mp4", + "random/adjust-bottle.mp4", + "random/blocks_ranking_size.mp4", + "random/dump_bin_bigbin.mp4", + "random/grab_roller.mp4", + "random/handover_mic.mp4", + "random/hanging_mug.mp4", + "random/move_can_pot.mp4", + "random/pick_diverse_bottles (2).mp4", + "random/pick_diverse_bottles.mp4", + "random/place_a2b_right.mp4", + "random/place_bread_skillet.mp4", + "random/place_fan.mp4" + ] +} diff --git a/src/app/(site)/layout.tsx b/src/app/(site)/layout.tsx new file mode 100644 index 0000000000000000000000000000000000000000..8376e0d1122ce8c3a3b100074ca31b2464710ad2 --- /dev/null +++ b/src/app/(site)/layout.tsx @@ -0,0 +1,14 @@ +import type { Metadata } from "next"; +import "@/styles/triworldbench.css"; + +export const metadata: Metadata = { + title: "TriWorldBench", +}; + +export default function TriWorldLayout({ + children, +}: { + children: React.ReactNode; +}) { + return <>{children}; +} diff --git a/src/app/(site)/page.tsx b/src/app/(site)/page.tsx new file mode 100644 index 0000000000000000000000000000000000000000..7a8d541154dfcd6d44d0eefaf0cdd579a87b940f --- /dev/null +++ b/src/app/(site)/page.tsx @@ -0,0 +1,932 @@ +import React from "react"; +import type { LeaderboardEntry } from "@/lib/db/schema"; +import { getSharedPageData } from "@/lib/data/page-data"; +import { getDatasetsWithVersions } from "@/lib/data/datasets"; +import { getMetrics } from "@/lib/data/metrics"; +import { getPageAffiliations, getPageAuthors } from "@/lib/data/page-people"; +import { + getTriWorldContentSections, + getTriWorldMetricDefinitionGroups, + type TriWorldConsistencyNode, + type TriWorldContentSection, + type TriWorldMetricDefinitionGroup, + type TriWorldMetricRouting, +} from "@/lib/data/triworld-content"; +import { getTriWorldVisualMetrics } from "@/lib/data/triworld-visual-metrics"; +import { getTriWorldAdvantages } from "@/lib/data/triworld-advantages"; +import { + TRIWORLD_ALL_METRIC_CODES, + TRIWORLD_EVALUATION_DEFINITION_CODES, + TRIWORLD_METRIC_GROUPS, + TRIWORLD_RANKING_CODE, + TRIWORLD_TABLE_METRICS, + type TriWorldBoardEntry, +} from "@/components/triworldbench/metrics"; +import { TriWorldLeaderboard } from "@/components/triworldbench/Leaderboard"; +import { LocalizedMarkdown } from "@/components/triworldbench/LocalizedMarkdown"; +import { + TriWorldCases, + TriWorldVisualization, + type TriWorldMetricText, +} from "@/components/triworldbench/ClientSections"; +import { LanguageMenu } from "@/components/triworldbench/LanguageMenu"; +import { FaGithub } from "react-icons/fa"; +import { contentValue, hasLocalizedText, isEmptyContentMarker, localized, type LocalizedText } from "@/lib/i18n"; +import { getTriWorldHeroActions } from "@/lib/data/triworld-hero-actions"; +import { getTriWorldNavItems } from "@/lib/data/triworld-nav-items"; +import { getHomepageEntrySections } from "@/lib/data/submission-guide"; + +export const dynamic = "force-dynamic"; + +const RANK_MEDALS = ["🥇", "🥈", "🥉"] as const; + +const ADVANTAGES = [ + { + title: ["Multi-View Consistency", "多视角一致性"], + body: [ + "TriWorldBench requires synchronized head, left, and right camera rollouts. Models must preserve geometric identity, object permanence, and robot-arm pose across every viewpoint.", + "TriWorldBench 要求同步生成头部、左腕和右腕三路相机预测。模型需要在每个视角中保持几何身份、物体持续性和机械臂姿态一致。", + ], + them: "VBench", + themNote: ["Single-view focus", "侧重单视角"], + us: "TriWorldBench", + usNote: ["Three-view synchronization", "三视角同步"], + }, + { + title: ["Physical Plausibility Gate", "物理合理性门控"], + body: [ + "TriWorldBench explicitly checks contact plausibility, support relations, collision-free motion, and gravity adherence. Fluent but physically impossible rollouts are penalized.", + "TriWorldBench 会显式检查接触合理性、支撑关系、无碰撞运动以及重力约束。流畅但物理上不可能的预测会被扣分。", + ], + them: "EvalCrafter", + themNote: ["No physics gate", "无物理门控"], + us: "TriWorldBench", + usNote: ["Physics-gated", "物理约束评估"], + }, + { + title: ["Language-Action Alignment", "语言-动作对齐"], + body: [ + "Every rollout is conditioned on a natural-language instruction. Evaluation checks whether the visible robot behavior actually completes the commanded action.", + "每段预测都以自然语言指令为条件。评估会检查可见机器人行为是否真正完成了指令要求的动作。", + ], + them: "FVD / PSNR", + themNote: ["Appearance-first", "外观优先"], + us: "TriWorldBench", + usNote: ["Action grounding", "动作落地"], + }, + { + title: ["Cross-Embodiment Generalization", "跨具身泛化"], + body: [ + "Submissions cover tabletop arms, mobile manipulation platforms, and bimanual systems. Generalization across embodiments is a first-class TriWorldBench evaluation dimension.", + "提交内容覆盖桌面机械臂、移动操作平台和双臂系统。跨具身泛化是 TriWorldBench 的核心评估维度之一。", + ], + them: "Single-robot evaluation", + themNote: ["Single platform", "单一平台"], + us: "TriWorldBench", + usNote: ["Multiple embodied platforms", "多具身平台"], + }, +] as const; + +const STATIC_ACADEMIC_PARAGRAPHS = [ + [ + "World models are predictive simulators that learn how an environment evolves under action, enabling agents to imagine future observations before they act. In robotics, this direction is increasingly merging with Vision-Language-Action systems.", + "世界模型是学习环境如何在动作影响下演化的预测式模拟器,让智能体在行动前预想未来观测。在机器人领域,这一方向正在与视觉、语言和动作一体化系统进一步融合。", + ], + [ + "Existing evaluation stacks do not fully track that goal. Video-generation metrics reward photorealism but rarely explain whether motion in the scene is physically feasible; robotics policy benchmarks measure task success but often ignore prediction quality.", + "现有评估体系并不能完整追踪这一目标。视频生成指标通常奖励逼真外观,却很少解释场景运动是否物理可行;机器人策略基准会衡量任务成功率,但往往忽略预测质量。", + ], + [ + "TriWorldBench introduces a World Model Video Evaluation framework designed for multi-view robots and robotic-arm motion prediction. Each submission generates synchronized multi-camera rollouts conditioned on language instructions.", + "TriWorldBench 提供面向多视角机器人和机械臂运动预测的世界模型视频评测框架。每个提交都需要基于语言指令生成同步的多相机预测序列。", + ], + [ + "The framework combines visual quality and temporal-dynamics metrics for appearance and motion, physical common-sense video evaluation for plausibility, and cross-embodiment policy-transfer ideas for instruction grounding.", + "该框架结合视觉质量与时序动态指标来评估外观和运动,结合物理常识视频评估来衡量合理性,并引入跨具身策略迁移思路来检验指令落地。", + ], + [ + "The final goal of TriWorldBench is to identify world models that can serve as reliable simulators for real-world manipulation: their multi-view predictions should be physically credible, viewpoint-consistent, and responsive to language instructions.", + "TriWorldBench 的最终目标是识别能够作为真实世界操作可靠模拟器的世界模型:它们的多视角预测应当物理可信、视角一致,并能响应语言指令。", + ], +] as const; + +function I18n({ en, zh }: { en: React.ReactNode; zh: React.ReactNode }) { + return ( + <> + {en} + {zh} + + ); +} + +function I18nText({ text }: { text?: LocalizedText }) { + if (!hasLocalizedText(text)) return null; + return ; +} + +function metricHeaderLines(value: string): string[] { + const words = value.trim().split(/\s+/).filter(Boolean); + if (words.length <= 2) return [value.trim()]; + const lines: string[] = []; + for (let index = 0; index < words.length; index += 2) { + lines.push(words.slice(index, index + 2).join(" ")); + } + return lines; +} + +function MetricHeaderText({ text }: { text?: LocalizedText }) { + const en = contentValue(text?.en); + const zh = contentValue(text?.zh); + if (!en && !zh) return null; + return ( + <> + {en ? ( + + {metricHeaderLines(en).map((line, index) => ( + {line} + ))} + + ) : null} + {zh ? ( + + {metricHeaderLines(zh).map((line, index) => ( + {line} + ))} + + ) : null} + + ); +} + +function fmt(value: number | null | undefined, decimals = 4): string { + if (value === null || value === undefined || Number.isNaN(Number(value))) { + return "TBA"; + } + return Number(value).toFixed(decimals); +} + +function buildValueRanks( + rows: TriWorldBoardEntry[], + getValue: (row: TriWorldBoardEntry) => number | null +): Map { + const sorted = rows + .map((row) => ({ modelName: row.modelName, value: getValue(row) })) + .filter((item): item is { modelName: string; value: number } => + item.value !== null && Number.isFinite(item.value) + ) + .sort((a, b) => b.value - a.value); + const ranks = new Map(); + let previousValue: number | null = null; + let previousRank = 0; + sorted.forEach((item, index) => { + const rank = previousValue !== null && item.value === previousValue ? previousRank : index + 1; + ranks.set(item.modelName, rank); + previousValue = item.value; + previousRank = rank; + }); + return ranks; +} + +function RankedScore({ value, rank }: { value: number | null; rank?: number }) { + const rankMarker = rank && rank <= 3 ? RANK_MEDALS[rank - 1] : rank ? `#${rank}` : null; + return ( + + {fmt(value)} + {rankMarker ? ( + + {rankMarker} + + ) : null} + + ); +} + +function toBoardEntries(entries: LeaderboardEntry[]): TriWorldBoardEntry[] { + return entries.map((entry) => { + const metrics: Record = {}; + const normalizedMetrics: Record = {}; + for (const code of TRIWORLD_ALL_METRIC_CODES) { + metrics[code] = entry.metrics[code]?.rawValue ?? null; + normalizedMetrics[code] = entry.metrics[code]?.rawValue ?? null; + } + return { + rank: entry.rank, + modelName: entry.model.name, + teamName: entry.team.name, + score: entry.metrics[TRIWORLD_RANKING_CODE]?.rawValue ?? entry.score.rawValue ?? null, + normalizedScore: entry.metrics[TRIWORLD_RANKING_CODE]?.rawValue ?? entry.score.rawValue ?? null, + status: entry.statusLabel || entry.submission.status, + metrics, + normalizedMetrics, + }; + }); +} + +function SectionHead({ number, title }: { number: string; title: React.ReactNode }) { + return ( +
+ {number} +

{title}

+
+ ); +} + +function ContentFigure({ section }: { section: TriWorldContentSection }) { + if (!section.imagePath) return null; + const hasCaption = hasLocalizedText(section.captionText); + return ( +
+ + {section.imageAltText.en} + + {hasCaption ?
: null} +
+ ); +} + +function FlowConnector({ + branches, + direction, +}: { + branches: 3 | 4; + direction: "split" | "merge"; +}) { + const positions = branches === 3 ? [167, 500, 833] : [125, 375, 625, 875]; + return ( + + ); +} + +function ConsistencyFlow({ + nodes, + caption, +}: { + nodes: TriWorldConsistencyNode[]; + caption: LocalizedText; +}) { + const byKey = new Map(nodes.map((node) => [node.nodeKey, node])); + const renderNode = (nodeKey: string, role: string) => { + const node = byKey.get(nodeKey); + if (!node) return null; + return ( +
+ {hasLocalizedText(node.titleText) ?

: null} + {hasLocalizedText(node.bodyText) ?

: null} +
+ ); + }; + return ( +
+
+
+ {renderNode("state_input", "reference")} +
+ +
+ {renderNode("robot_action", "taxonomy")} + {renderNode("target_object", "taxonomy")} + {renderNode("evidence_status", "taxonomy")} +
+ +
+ {renderNode("shared_rubric", "rubric")} +
+ +
+ {renderNode("compatibility_first", "protocol")} + {renderNode("verification_first", "protocol")} + {renderNode("exemplar_calibrated", "protocol")} + {renderNode("question_based", "protocol")} +
+ +
+ {renderNode("expert_alignment", "expert")} + + {renderNode("frozen_primary", "frozen")} +
+
+
+
+ ); +} + +function MetricRoutingTable({ rows }: { rows: TriWorldMetricRouting[] }) { + return ( +
+ + + + + + + + + + + + + + + + + {rows.map((row) => ( + + + + + + + ))} + +
+
+ ); +} + +function MetricDefinitions({ groups }: { groups: TriWorldMetricDefinitionGroup[] }) { + if (!groups.length) return null; + return ( +
+ {groups.map((group) => { + const normalizedKey = group.groupKey.toLocaleLowerCase().replace(/[_\s]+/g, "-").replace(/[^a-z0-9-]/g, ""); + const matchedGroup = TRIWORLD_METRIC_GROUPS.find((item) => + item.key === normalizedKey || item.code.toLocaleLowerCase().replace(/_/g, "-") === normalizedKey + ); + return ( +
+ {hasLocalizedText(group.titleText) ?

: null} + {hasLocalizedText(group.summaryText) ? : null} + {group.items.length ? ( +
+ {group.items.map((item) => ( +
+ {hasLocalizedText(item.titleText) ?

: null} + {hasLocalizedText(item.bodyText) ? : null} +
+ ))} +
+ ) : null} +
+ ); + })} +
+ ); +} + +function LeaderboardTable({ + rows, + metricTexts, +}: { + rows: TriWorldBoardEntry[]; + metricTexts: Record; +}) { + const rankByCode = new Map>(); + rankByCode.set(TRIWORLD_RANKING_CODE, buildValueRanks(rows, (row) => row.score)); + for (const metric of TRIWORLD_TABLE_METRICS) { + rankByCode.set( + metric.code, + buildValueRanks(rows, (row) => row.metrics[metric.code] ?? null) + ); + } + return ( +
+

+ +

+
+ + + + + + {TRIWORLD_TABLE_METRICS.map((metric) => ( + + ))} + + {rows.map((row) => { + const scoreRank = rankByCode.get(TRIWORLD_RANKING_CODE)?.get(row.modelName); + return ( + + + + + {TRIWORLD_TABLE_METRICS.map((metric) => { + const metricRank = rankByCode.get(metric.code)?.get(row.modelName); + return ; + })} + + ); + })} +
+ + TWB-Score + + + +
+ {row.modelName} + {row.teamName} + + + {row.rank <= 3 ? RANK_MEDALS[row.rank - 1] : row.rank} + + + +
+
+
+ ); +} + +export default function TriWorldPage() { + const shared = getSharedPageData(); + const datasets = getDatasetsWithVersions(); + const homepageEntrySections = getHomepageEntrySections(); + const datasetsEntry = homepageEntrySections.find((entry) => entry.sectionKey === "datasets"); + const submissionEntry = homepageEntrySections.find((entry) => entry.sectionKey === "submission"); + const metrics = getMetrics(); + const contentSections = getTriWorldContentSections(); + const abstractSection = contentSections.find((section) => section.sectionKey === "abstract"); + const overviewSection = contentSections.find((section) => section.sectionKey === "overview"); + const advantagesSection = contentSections.find((section) => section.sectionKey === "advantages"); + const casesSection = contentSections.find((section) => section.sectionKey === "cases"); + const metricsSection = contentSections.find((section) => section.sectionKey === "metrics"); + const leaderboardSection = contentSections.find((section) => section.sectionKey === "leaderboard"); + const visualizationSection = contentSections.find((section) => section.sectionKey === "visualization"); + const casesTitleText = casesSection?.titleText || localized("Visualization Cases", "可视化案例"); + const casesBodyText = casesSection?.bodyText || localized( + "This section presents representative rollouts generated by participating systems. Each clip is a synchronized multi-view prediction conditioned on a natural-language instruction. **Clean** and **random** represent two different video surroundings and backgrounds. The video is composed of three views; from left to right they are **left**, **head**, and **right**. Evaluating the consistency of these three perspectives is the unique feature and important content of this benchmark.", + "本节展示参赛系统生成的代表性预测片段,每个片段均由自然语言指令作为条件,驱动同步多视角预测生成。干净背景与随机背景分别代表两类不同的视频环境设置。每段视频由三个视角组成,从左至右依次为左腕、头部和右腕视角。评估三个视角之间的一致性,是本基准的核心特征与重要组成部分。" + ); + const leaderboardTitleText = leaderboardSection?.titleText || localized( + "TriWorldBench Leaderboard", + "TriWorldBench 榜单" + ); + const leaderboardBodyText = leaderboardSection?.bodyText || localized( + "Browse every published model in one leaderboard. Use a rank range to jump to its block, or locate a model name without changing the displayed ranking.", + "全部已发布模型会保留在同一张榜单中,可通过排名区间跳转,或按模型名称定位,不会改变榜单的显示结果。" + ); + const visualizationTitleText = visualizationSection?.titleText || localized( + "Leaderboard Visualization", + "榜单可视化" + ); + const visualizationBodyText = visualizationSection?.bodyText || localized( + "The **overall radar** shows the six category scores on a 0-100 scale. Search by part of a model name to focus the radar and ranking on matching models, then click a model to read its values at the radar vertices. Use the overall, category, or individual-metric buttons to change the ranking view below.", + "总体雷达图基于六个类别得分,以不同的分数尺度展示模型表现。用户可输入部分模型名称,筛选对应雷达图及下方排名结果;点击模型后,可在雷达图各顶点查看对应分数。通过总分、类别或具体指标按钮,可切换下方排名展示视图。" + ); + const metricDefinitionGroups = getTriWorldMetricDefinitionGroups(); + const metricTexts: Record = Object.fromEntries( + metrics.map((metric) => [ + metric.code, + { + code: metric.code, + label: metric.displayNameText || localized(metric.display_name, metric.display_name_zh), + shortLabel: metric.shortLabelText || metric.displayNameText || localized(metric.display_name, metric.display_name_zh), + title: localized(`${metric.display_name_en || metric.display_name} - ranked`, `${metric.display_name_zh || metric.display_name} - 排名`), + description: metric.descriptionText || localized(metric.description_en || metric.description || "", metric.description_zh), + category: metric.category, + }, + ]) + ); + for (const item of getTriWorldVisualMetrics()) { + const key = item.metric_code === "__overall__" ? "__overall__" : item.metric_code; + metricTexts[key] = { + ...metricTexts[key], + code: key, + label: localized(item.label_en, item.label_zh), + shortLabel: localized(item.label_en, item.label_zh), + title: localized(item.title_en, item.title_zh), + }; + } + for (const group of metricDefinitionGroups) { + const groupCode = TRIWORLD_EVALUATION_DEFINITION_CODES[group.groupKey]; + if (groupCode && metricTexts[groupCode]) { + metricTexts[groupCode] = { + ...metricTexts[groupCode], + label: group.titleText, + shortLabel: group.titleText, + }; + } + for (const item of group.items) { + const itemCode = TRIWORLD_EVALUATION_DEFINITION_CODES[item.itemKey]; + if (itemCode && metricTexts[itemCode]) { + metricTexts[itemCode] = { + ...metricTexts[itemCode], + label: item.titleText, + shortLabel: item.titleText, + }; + } + } + } + const radarCategoryTexts: Record = Object.fromEntries( + TRIWORLD_METRIC_GROUPS + .filter((group) => group.code !== TRIWORLD_RANKING_CODE) + .map((group) => { + const definitionGroup = metricDefinitionGroups.find( + (item) => item.groupKey.toLocaleLowerCase().replace(/[_\s]+/g, "-").replace(/[^a-z0-9-]/g, "") === group.key + ); + return [ + group.code, + definitionGroup?.titleText || metricTexts[group.code]?.label || { en: group.code, zh: group.code }, + ]; + }) + ); + const authors = getPageAuthors(); + const affiliations = getPageAffiliations(); + const navItems = getTriWorldNavItems(); + const advantages = getTriWorldAdvantages(); + const heroEyebrow = isEmptyContentMarker(shared.hero?.eyebrow) + ? "" + : contentValue(shared.hero?.eyebrow) || "World Model Benchmark"; + const githubUrlIsHidden = isEmptyContentMarker(shared.siteInfo?.github_url); + const heroActions = getTriWorldHeroActions().filter( + (action) => action.actionKey !== "github" || !githubUrlIsHidden + ); + const configuredGithubUrl = contentValue(shared.siteInfo?.github_url); + const githubUrl = configuredGithubUrl && configuredGithubUrl !== "#" + ? configuredGithubUrl + : "https://github.com/TriWorldBench/TriWorldBench"; + const rows = toBoardEntries(shared.leaderboard.entries); + const contacts = shared.contacts.filter( + (contact) => Boolean(contentValue(contact.value)) && hasLocalizedText(contact.labelText) + ); + const visibleSectionKeys = [ + abstractSection ? "abstract" : null, + overviewSection ? "overview" : null, + advantagesSection ? "advantages" : null, + "cases", + metricsSection ? "metrics" : null, + "leaderboard", + "visualization", + datasetsEntry ? "datasets" : null, + "policies", + submissionEntry ? "submission" : null, + "contact", + ].filter((key): key is string => Boolean(key)); + const sectionNumbers = new Map( + visibleSectionKeys.map((key, index) => [key, String(index + 1).padStart(2, "0")]) + ); + const sectionNumber = (key: string) => sectionNumbers.get(key) || "00"; + + return ( +
+
+ + TriWorldBench + + + +
+ +
+
+ +
+ {abstractSection ? ( +
+ {hasLocalizedText(abstractSection.titleText) ? } /> : null} + {hasLocalizedText(abstractSection.bodyText) ? : null} + + {hasLocalizedText(abstractSection.secondaryBodyText) ? : null} +
+ ) : null} + + {overviewSection ? ( +
+ {hasLocalizedText(overviewSection.titleText) ? } /> : null} + {hasLocalizedText(overviewSection.bodyText) ?
: null} + +
+ ) : null} + + {advantagesSection ? ( +
+ {hasLocalizedText(advantagesSection.titleText) ? } /> : null} + {hasLocalizedText(advantagesSection.bodyText) ? : null} +
+ {advantages.map((item) => ( +
+ {hasLocalizedText(item.titleText) ?

: null} + {hasLocalizedText(item.bodyText) ? : null} +
+ ))} +
+
+ ) : null} + +
+ } /> +

+ +
+ + {/* + Temporarily hidden: State-Aware Tri-View Consistency. Keep the renderer and + database-backed content source above intact so this section can be restored. + {consistencySection ? ( +
+ } /> +

+ +
+ ) : null} + */} + + {metricsSection ? ( +
+ {hasLocalizedText(metricsSection.titleText) ? } /> : null} + {hasLocalizedText(metricsSection.bodyText) ?
: null} + {/* Temporarily hidden: Metric routing. The data and renderer remain available for restoration. */} + {/* */} + +
+ ) : null} + +
+
+
+ {sectionNumber("leaderboard")} +

+
+ +
+ +
+ + + + {datasetsEntry ? ( +
+ } /> + {hasLocalizedText(datasetsEntry.bodyText) ? : null} + {datasetsEntry.actionHref && hasLocalizedText(datasetsEntry.actionLabelText) ? ( +
+ + + +
+ ) : null} +
+ ) : null} + + {/* + Temporarily hidden: Important Dates remains editable in local-admin and is + retained in SQLite for the next public schedule release. +
+ } /> +
+ {shared.dates.map((date) => ( +
+ + +

+
+ ))} +
+
+ */} + +
+ } /> +
+ {shared.policies.map((policy) => { + const hasTitle = hasLocalizedText(policy.titleText); + const hasBody = hasLocalizedText(policy.bodyText); + if (!hasTitle && !hasBody) return null; + return ( +
+ {hasTitle ?

: null} + {hasBody ? : null} +
+ ); + })} +
+
+ + {/* Academic Background is retained in SQLite but not published on this version of the page. +
+ } /> +
+

+ {STATIC_ACADEMIC_PARAGRAPHS.map((paragraph) => ( +

+ ))} + {shared.references.slice(0, 3).map((reference) => ( +

+ . +

+ ))} +
+
+ */} + + {submissionEntry ? ( +
+ } /> +
+
+ {hasLocalizedText(submissionEntry.bodyText) ? : null} + {submissionEntry.actionHref && hasLocalizedText(submissionEntry.actionLabelText) ? ( +
+ +
+ ) : null} +
+
+ {datasets.uploadRequirements.slice(0, 3).map((requirement, index) => ( +
+ {String(index + 1).padStart(2, "0")} + + {hasLocalizedText(requirement.titleText) ? : null} + {hasLocalizedText(requirement.bodyText) ? : null} + +
+ ))} +
+
+
+ ) : null} + +
+ } /> +
+ {contacts.map((contact) => ( +
+ + {contact.image_path ? ( + + + + ) : ( + {contact.value} + )} + {hasLocalizedText(contact.descriptionText) ? : null} +
+ ))} +
+
+ + {/* Other Information is intentionally unpublished while its database record is retained. +
+ } /> +
+

+ +

+
+ */} + +
+ +
+ +
+
+ ); +} diff --git a/src/app/(site)/submission/page.tsx b/src/app/(site)/submission/page.tsx new file mode 100644 index 0000000000000000000000000000000000000000..d2ee58801857fdc1746a82aef08559aa952ef020 --- /dev/null +++ b/src/app/(site)/submission/page.tsx @@ -0,0 +1,89 @@ +import React from "react"; +import { FaGithub } from "react-icons/fa"; +import { LanguageMenu } from "@/components/triworldbench/LanguageMenu"; +import { LocalizedMarkdown } from "@/components/triworldbench/LocalizedMarkdown"; +import { + getSubmissionGuideMeta, + getSubmissionGuideNavItems, + getSubmissionGuideSections, +} from "@/lib/data/submission-guide"; +import { getSiteInfo } from "@/lib/data/site-info"; +import { contentValue, hasLocalizedText, localized, type LocalizedText } from "@/lib/i18n"; + +export const dynamic = "force-dynamic"; + +function I18nText({ text }: { text?: LocalizedText }) { + if (!hasLocalizedText(text)) return null; + return ; +} + +function SectionHead({ number, title }: { number: string; title: LocalizedText }) { + return ( +
+ {number} +

+
+ ); +} + +export default function TriWorldSubmissionPage() { + const pageNavItems = getSubmissionGuideNavItems(); + const sections = getSubmissionGuideSections(); + const siteInfo = getSiteInfo(); + const configuredGithubUrl = contentValue(siteInfo?.github_url); + const githubUrl = + configuredGithubUrl && configuredGithubUrl !== "#" + ? configuredGithubUrl + : "https://github.com/TriWorldBench/TriWorldBench"; + const meta = getSubmissionGuideMeta() || { + eyebrowText: localized("Submission Portal", "提交入口"), + titleText: localized("Submission Guide", "提交指南"), + introText: localized("TriWorldBench submission requirements.", "TriWorldBench 提交要求。"), + backLabelText: localized("Back to Benchmark", "返回基准页面"), + backHref: "/", + }; + + return ( +
+
+ TriWorldBench + + +
+ +
+
+ +
+ {sections.map((section, index) => ( +
+ + +
+ ))} +
+
+
+ ); +} diff --git a/src/app/(site)/video-cases/[category]/[fileName]/route.ts b/src/app/(site)/video-cases/[category]/[fileName]/route.ts new file mode 100644 index 0000000000000000000000000000000000000000..60cfdd59cee737ef9cbb680faa791cbb79d4f8f8 --- /dev/null +++ b/src/app/(site)/video-cases/[category]/[fileName]/route.ts @@ -0,0 +1,48 @@ +import { readFile } from "node:fs/promises"; +import path from "node:path"; +import { NextRequest, NextResponse } from "next/server"; + +const VIDEO_ROOT = path.resolve( + process.env.TRIWORLDBENCH_VIDEO_ROOT || path.join(process.cwd(), "media", "video-cases") +); + +function safeVideoPath(category: string, fileName: string): string | null { + if (!["clean", "random"].includes(category)) return null; + if (!/^[a-zA-Z0-9()[\]._ -]+\.mp4$/.test(fileName)) return null; + + const resolved = path.resolve(VIDEO_ROOT, category, fileName); + const categoryRoot = path.resolve(VIDEO_ROOT, category); + if (!resolved.startsWith(categoryRoot + path.sep)) return null; + return resolved; +} + +export async function GET( + _req: NextRequest, + context: { params: Promise<{ category: string; fileName: string }> } +) { + const { category, fileName } = await context.params; + const videoPath = safeVideoPath(category, fileName); + if (!videoPath) { + return NextResponse.json({ error: "not found" }, { status: 404 }); + } + + try { + const file = await readFile(videoPath); + return new NextResponse(file, { + headers: { + "Content-Type": "video/mp4", + "Content-Disposition": `inline; filename="${fileName.replace(/"/g, "")}"`, + "Content-Length": String(file.byteLength), + "Cache-Control": "private, no-store, max-age=0", + "Accept-Ranges": "none", + "Cross-Origin-Resource-Policy": "same-origin", + "Permissions-Policy": "picture-in-picture=()", + "Vary": "Cookie", + "X-Content-Type-Options": "nosniff", + "X-Robots-Tag": "noindex, nofollow, noarchive", + }, + }); + } catch { + return NextResponse.json({ error: "not found" }, { status: 404 }); + } +} diff --git a/src/app/api/charts/radar/route.ts b/src/app/api/charts/radar/route.ts new file mode 100644 index 0000000000000000000000000000000000000000..da58e6bd05024e0f516ee3a765117c77263edae0 --- /dev/null +++ b/src/app/api/charts/radar/route.ts @@ -0,0 +1,12 @@ +import { NextRequest, NextResponse } from "next/server"; +import { getRadarData } from "@/lib/data/leaderboard"; + +export function GET(req: NextRequest) { + const metricsParam = req.nextUrl.searchParams.get("metrics"); + const topParam = req.nextUrl.searchParams.get("top"); + const metricCodes = metricsParam + ? metricsParam.split(",").map((s) => s.trim()).filter(Boolean) + : undefined; + const top = topParam ? Number(topParam) : 8; + return NextResponse.json(getRadarData(metricCodes, top)); +} diff --git a/src/app/api/content/[section]/route.ts b/src/app/api/content/[section]/route.ts new file mode 100644 index 0000000000000000000000000000000000000000..d23d9553b56872b691e2646f0d762fa8838dc328 --- /dev/null +++ b/src/app/api/content/[section]/route.ts @@ -0,0 +1,36 @@ +import { NextRequest, NextResponse } from "next/server"; +import { getDb } from "@/lib/db"; +import { all, get as dbGet } from "@/lib/db/helpers"; +import { parseJsonField } from "@/lib/utils"; + +const SECTION_MAP: Record unknown[]> = { + hero: () => all(getDb().prepare("SELECT * FROM hero_content ORDER BY id")), + overview: () => + all>(getDb().prepare("SELECT * FROM overview_content ORDER BY id")) + .map((row) => parseJsonField(row, "stat_json")), + evaluation: () => all(getDb().prepare("SELECT * FROM evaluation_sections ORDER BY sort_order, id")), + research: () => + all>(getDb().prepare("SELECT * FROM research_sections ORDER BY sort_order, id")) + .map((row) => parseJsonField(row, "tags_json")), + participation: () => all(getDb().prepare("SELECT * FROM participation_info ORDER BY sort_order, id")), + venue: () => all(getDb().prepare("SELECT * FROM venue_host_info ORDER BY id")), + policies: () => all(getDb().prepare("SELECT * FROM policy_items ORDER BY sort_order, id")), + contact: () => all(getDb().prepare("SELECT * FROM contact_info ORDER BY sort_order, id")), + other: () => all(getDb().prepare("SELECT * FROM other_information ORDER BY id")), + announcements: () => + all(getDb().prepare("SELECT * FROM announcements ORDER BY published_at DESC, id DESC")), + "academic-references": () => + all>(getDb().prepare("SELECT * FROM academic_references ORDER BY sort_order, id")) + .map((row) => parseJsonField(row, "tags_json")), + "metric-explanations": () => all(getDb().prepare("SELECT * FROM metric_explanations ORDER BY id")), +}; + +export async function GET( + _req: NextRequest, + { params }: { params: Promise<{ section: string }> } +) { + const { section } = await params; + const handler = SECTION_MAP[section]; + if (!handler) return NextResponse.json({ error: "unknown section" }, { status: 404 }); + return NextResponse.json({ section, items: handler() }); +} diff --git a/src/app/api/data-version/route.ts b/src/app/api/data-version/route.ts new file mode 100644 index 0000000000000000000000000000000000000000..e524a1b0ab664f8ed4e9886745bc5555929e91bc --- /dev/null +++ b/src/app/api/data-version/route.ts @@ -0,0 +1,10 @@ +import { NextResponse } from "next/server"; +import { getDb } from "@/lib/db"; +import { get as dbGet } from "@/lib/db/helpers"; + +export function GET() { + const row = dbGet<{ version: number; updated_at: string }>( + getDb().prepare("SELECT version, updated_at FROM data_version WHERE id = 1") + ); + return NextResponse.json(row || { version: 1, updated_at: "" }); +} diff --git a/src/app/api/datasets/route.ts b/src/app/api/datasets/route.ts new file mode 100644 index 0000000000000000000000000000000000000000..fd41f35362db25c50aa516bb2507461dca191831 --- /dev/null +++ b/src/app/api/datasets/route.ts @@ -0,0 +1,6 @@ +import { NextResponse } from "next/server"; +import { getDatasetsWithVersions } from "@/lib/data/datasets"; + +export function GET() { + return NextResponse.json(getDatasetsWithVersions()); +} diff --git a/src/app/api/health/route.ts b/src/app/api/health/route.ts new file mode 100644 index 0000000000000000000000000000000000000000..11f2901476ce75bf1ef77f8e8683bd8ef2331601 --- /dev/null +++ b/src/app/api/health/route.ts @@ -0,0 +1,5 @@ +import { NextResponse } from "next/server"; + +export function GET() { + return NextResponse.json({ ok: true }); +} diff --git a/src/app/api/important-dates/route.ts b/src/app/api/important-dates/route.ts new file mode 100644 index 0000000000000000000000000000000000000000..405afa7f90a09af77c4ba92c36cfb0dda5b9bdca --- /dev/null +++ b/src/app/api/important-dates/route.ts @@ -0,0 +1,6 @@ +import { NextResponse } from "next/server"; +import { getImportantDates } from "@/lib/data/important-dates"; + +export function GET() { + return NextResponse.json({ items: getImportantDates() }); +} diff --git a/src/app/api/leaderboard/history/route.ts b/src/app/api/leaderboard/history/route.ts new file mode 100644 index 0000000000000000000000000000000000000000..e7b6dfcb78a3b317a548336d83f3addb989709d8 --- /dev/null +++ b/src/app/api/leaderboard/history/route.ts @@ -0,0 +1,6 @@ +import { NextResponse } from "next/server"; +import { getSnapshotHistory } from "@/lib/data/leaderboard"; + +export function GET() { + return NextResponse.json({ snapshots: getSnapshotHistory() }); +} diff --git a/src/app/api/leaderboard/route.ts b/src/app/api/leaderboard/route.ts new file mode 100644 index 0000000000000000000000000000000000000000..c764f93ec11526b52d40b641778a25034917630c --- /dev/null +++ b/src/app/api/leaderboard/route.ts @@ -0,0 +1,7 @@ +import { NextRequest, NextResponse } from "next/server"; +import { getLeaderboard } from "@/lib/data/leaderboard"; + +export function GET(req: NextRequest) { + const snapshot = req.nextUrl.searchParams.get("snapshot"); + return NextResponse.json(getLeaderboard(snapshot)); +} diff --git a/src/app/api/models/[modelId]/scores/route.ts b/src/app/api/models/[modelId]/scores/route.ts new file mode 100644 index 0000000000000000000000000000000000000000..5c78c1143a2482cd68185f0bac21c3b792e6a6f7 --- /dev/null +++ b/src/app/api/models/[modelId]/scores/route.ts @@ -0,0 +1,14 @@ +import { NextRequest, NextResponse } from "next/server"; +import { getModelScores } from "@/lib/data/leaderboard"; + +export async function GET( + _req: NextRequest, + { params }: { params: Promise<{ modelId: string }> } +) { + const { modelId } = await params; + const result = getModelScores(modelId); + if (!result.model) { + return NextResponse.json({ error: "model not found" }, { status: 404 }); + } + return NextResponse.json(result); +} diff --git a/src/app/api/site-info/route.ts b/src/app/api/site-info/route.ts new file mode 100644 index 0000000000000000000000000000000000000000..b8fff6f3176294d819f76db1a6914705edc77916 --- /dev/null +++ b/src/app/api/site-info/route.ts @@ -0,0 +1,6 @@ +import { NextResponse } from "next/server"; +import { getSiteAndHero } from "@/lib/data/site-info"; + +export function GET() { + return NextResponse.json(getSiteAndHero()); +} diff --git a/src/app/globals.css b/src/app/globals.css new file mode 100644 index 0000000000000000000000000000000000000000..3e1fcdbd95cf0704e92c7d6e1a6fd68f11909e36 --- /dev/null +++ b/src/app/globals.css @@ -0,0 +1,8 @@ +/* Minimal global reset. The public site stylesheet handles presentation. */ +*, *::before, *::after { + box-sizing: border-box; +} +body { + margin: 0; + font-family: Inter, system-ui, -apple-system, "Segoe UI", sans-serif; +} diff --git a/src/app/layout.tsx b/src/app/layout.tsx new file mode 100644 index 0000000000000000000000000000000000000000..de3f73ede42243e9f686e60d825783f9f674c906 --- /dev/null +++ b/src/app/layout.tsx @@ -0,0 +1,35 @@ +import type { Metadata } from "next"; +import "./globals.css"; + +export const metadata: Metadata = { + title: "TriWorldBench", + description: + "A multi-view robotic world-model video evaluation challenge for physical plausibility, cross-view consistency, and language-action alignment.", + icons: { + icon: "/assets_common/photos/image_155613883779109.png", + }, +}; + +export default function RootLayout({ + children, +}: { + children: React.ReactNode; +}) { + return ( + + + + + + + {children} + + ); +} diff --git a/src/components/triworldbench/ClientSections.tsx b/src/components/triworldbench/ClientSections.tsx new file mode 100644 index 0000000000000000000000000000000000000000..1420a2c79de0da4c350779e9a92e8eef6ab930e1 --- /dev/null +++ b/src/components/triworldbench/ClientSections.tsx @@ -0,0 +1,736 @@ +"use client"; + +import React, { useEffect, useMemo, useRef, useState } from "react"; +import { FaMedal } from "react-icons/fa"; +import { + TRIWORLD_COLORS, + TRIWORLD_RADAR_DIMS, + TRIWORLD_VIS_PANELS, + type TriWorldBoardEntry, +} from "./metrics"; +import { hasLocalizedText, type LocalizedText } from "@/lib/i18n"; +import { LocalizedMarkdown } from "./LocalizedMarkdown"; + +const CLEAN_CASES = [ + "blocks_ranking_rgb.mp4", + "click_bell.mp4", + "grab_roller.mp4", + "move_can_pot.mp4", + "move_pillbottle_pad.mp4", + "pick_dual_bottles.mp4", + "place_cans_plasticbox.mp4", + "place_dual_shoes.mp4", + "place_object_stand.mp4", + "scan_object.mp4", + "stack_bowls_three.mp4", + "turn_switch.mp4", +] as const; + +const RANDOM_CASES = [ + "adjust-bottle.mp4", + "blocks_ranking_size.mp4", + "dump_bin_bigbin.mp4", + "grab_roller.mp4", + "handover_mic.mp4", + "hanging_mug.mp4", + "move_can_pot.mp4", + "pick_diverse_bottles (2).mp4", + "pick_diverse_bottles.mp4", + "place_a2b_right.mp4", + "place_bread_skillet.mp4", + "place_fan.mp4", +] as const; + +const CASE_TITLES_ZH: Record = { + "adjust-bottle.mp4": "调整瓶子", + "blocks_ranking_rgb.mp4": "RGB 方块排序", + "blocks_ranking_size.mp4": "按尺寸排序方块", + "click_bell.mp4": "点击铃铛", + "dump_bin_bigbin.mp4": "将小箱倒入大箱", + "grab_roller.mp4": "抓取滚轮", + "handover_mic.mp4": "递交麦克风", + "hanging_mug.mp4": "悬挂杯子", + "move_can_pot.mp4": "移动罐子到锅中", + "move_pillbottle_pad.mp4": "移动药瓶到垫子", + "pick_diverse_bottles (2).mp4": "抓取多种瓶子(二)", + "pick_diverse_bottles.mp4": "抓取多种瓶子", + "pick_dual_bottles.mp4": "抓取双瓶", + "place_a2b_right.mp4": "从 A 到 B 放置到右侧", + "place_bread_skillet.mp4": "将面包放入煎锅", + "place_cans_plasticbox.mp4": "将罐子放入塑料盒", + "place_dual_shoes.mp4": "放置双鞋", + "place_fan.mp4": "放置风扇", + "place_object_stand.mp4": "将物体放到支架", + "scan_object.mp4": "扫描物体", + "stack_bowls_three.mp4": "堆叠三个碗", + "turn_switch.mp4": "拨动开关", +}; + +const RADAR_LINE_PATTERNS = [ + "none", + "12 5", + "4 4", + "14 4 3 4", + "2 4", + "9 3 2 3", + "18 6", + "6 3", + "16 3 2 3", + "3 3 9 3", + "20 4 4 4", + "7 2", + "11 2 2 2", + "5 3 1 3", + "22 5", + "8 4 2 4", + "13 3", + "3 2", + "15 5 3 2", + "6 2 2 2", + "10 5", + "4 2 10 2", + "17 3 4 3", + "2 3 6 3", +] as const; + +function DualText({ en, zh }: { en: React.ReactNode; zh: React.ReactNode }) { + return ( + <> + {en} + {zh} + + ); +} + +function fmt(value: number | null | undefined): string { + if (value === null || value === undefined || Number.isNaN(Number(value))) { + return "TBA"; + } + return Number(value).toFixed(2); +} + +function formatCaseTitle(fileName: string): string { + return fileName + .replace(/\.mp4$/i, "") + .replace(/\s*\(2\)$/, " 2") + .replace(/[_-]+/g, " ") + .replace(/\b\w/g, (letter) => letter.toUpperCase()); +} + +function radarPoint( + cx: number, + cy: number, + radius: number, + axisIndex: number, + axisCount: number, + value: number +): [number, number] { + const angle = -Math.PI / 2 + (axisIndex / axisCount) * Math.PI * 2; + const scaled = Math.max(0, Math.min(100, value || 0)) / 100; + return [ + cx + Math.cos(angle) * radius * scaled, + cy + Math.sin(angle) * radius * scaled, + ]; +} + +function radarPercentage(value: number | null | undefined, maxValue: number): number { + if (value === null || value === undefined || Number.isNaN(Number(value))) return 0; + return (Number(value) / maxValue) * 100; +} + +function CaseGrid({ + category, + cases, + active, +}: { + category: "clean" | "random"; + cases: ReadonlyArray; + active: boolean; +}) { + const panelRef = useRef(null); + const gridRef = useRef(null); + + useEffect(() => { + if (!active) return; + + const panel = panelRef.current; + const grid = gridRef.current; + if (!panel || !grid) return; + + const updatePanelHeight = () => { + const items = Array.from(grid.querySelectorAll(".case-item")); + if (!items.length) return; + + const rowHeights = new Map(); + for (const item of items) { + const rowTop = Math.round(item.offsetTop); + rowHeights.set(rowTop, Math.max(rowHeights.get(rowTop) || 0, item.offsetHeight)); + } + + const firstTwoRows = [...rowHeights.entries()] + .sort(([a], [b]) => a - b) + .slice(0, 2) + .map(([, height]) => height); + if (!firstTwoRows.length) return; + + const rowGap = Number.parseFloat(window.getComputedStyle(grid).rowGap || "0") || 0; + const measuredHeight = + firstTwoRows.reduce((sum, height) => sum + height, 0) + + rowGap * Math.max(0, firstTwoRows.length - 1); + panel.style.setProperty("--case-panel-max-height", `${Math.ceil(measuredHeight)}px`); + }; + + updatePanelHeight(); + window.addEventListener("resize", updatePanelHeight); + + const videos = Array.from(grid.querySelectorAll("video")); + videos.forEach((video) => { + video.addEventListener("loadedmetadata", updatePanelHeight); + video.addEventListener("loadeddata", updatePanelHeight); + }); + + const resizeObserver = + "ResizeObserver" in window ? new ResizeObserver(updatePanelHeight) : null; + if (resizeObserver) { + Array.from(grid.children).forEach((child) => resizeObserver.observe(child)); + } + + return () => { + window.removeEventListener("resize", updatePanelHeight); + videos.forEach((video) => { + video.removeEventListener("loadedmetadata", updatePanelHeight); + video.removeEventListener("loadeddata", updatePanelHeight); + }); + resizeObserver?.disconnect(); + }; + }, [active, cases]); + + return ( +
+
+ {cases.map((fileName) => ( +
+
+ ))} +
+
+ ); +} + +export interface TriWorldMetricText { + code: string; + label: LocalizedText; + shortLabel: LocalizedText; + title: LocalizedText; + description?: LocalizedText; + category?: string; +} + +function labelFor(metricTexts: Record, code: string, fallback: string): LocalizedText { + return metricTexts[code]?.shortLabel || { en: fallback, zh: fallback }; +} + +function titleFor(metricTexts: Record, code: string | null, fallback: string): LocalizedText { + if (!code) return metricTexts.__overall__?.title || { en: fallback, zh: fallback }; + return metricTexts[code]?.title || { en: fallback, zh: fallback }; +} + +function panelLabelFor(metricTexts: Record, code: string | null, fallback: string): LocalizedText { + if (!code) return metricTexts.__overall__?.label || { en: fallback, zh: fallback }; + return metricTexts[code]?.label || { en: fallback, zh: fallback }; +} + +function radarLabelLines(value: string, maxLineLength = 16): string[] { + const normalized = value.trim(); + if (!normalized || normalized.length <= maxLineLength) return [normalized]; + + const words = normalized.split(/\s+/).filter(Boolean); + if (words.length === 1) { + const characters = Array.from(normalized); + const splitAt = Math.ceil(characters.length / 2); + return [characters.slice(0, splitAt).join(""), characters.slice(splitAt).join("")]; + } + + let bestSplit = 1; + let bestScore = Number.POSITIVE_INFINITY; + for (let split = 1; split < words.length; split += 1) { + const firstLength = words.slice(0, split).join(" ").length; + const secondLength = words.slice(split).join(" ").length; + const score = Math.max(firstLength, secondLength) * 2 + Math.abs(firstLength - secondLength); + if (score < bestScore) { + bestScore = score; + bestSplit = split; + } + } + return [words.slice(0, bestSplit).join(" "), words.slice(bestSplit).join(" ")]; +} + +function radarLabelSpans(value: string, className: string, x: string): React.ReactNode[] { + const lines = radarLabelLines(value); + return lines.map((line, index) => ( + + {line} + + )); +} + +function OverallRadar({ + rows, + allRows, + highlightName, + metricTexts, + categoryTexts, +}: { + rows: TriWorldBoardEntry[]; + allRows: TriWorldBoardEntry[]; + highlightName: string | null; + metricTexts: Record; + categoryTexts: Record; +}) { + const cx = 250; + const cy = 250; + const radius = 194; + const ringFractions = [0.2, 0.4, 0.6, 0.8, 1]; + const highlighted = highlightName + ? rows.find((row) => row.modelName === highlightName) + : null; + + return ( + + {ringFractions.map((fraction) => { + const points = TRIWORLD_RADAR_DIMS.map((_, index) => + radarPoint( + cx, + cy, + radius * fraction, + index, + TRIWORLD_RADAR_DIMS.length, + 100 + ) + .map((coordinate) => coordinate.toFixed(1)) + .join(",") + ).join(" "); + + return ( + + + + ); + })} + + {TRIWORLD_RADAR_DIMS.map((dimension, index) => { + const [x, y] = radarPoint(cx, cy, radius, index, TRIWORLD_RADAR_DIMS.length, 100); + const [labelX, labelY] = radarPoint( + cx, + cy, + radius + 32, + index, + TRIWORLD_RADAR_DIMS.length, + 100 + ); + const label = categoryTexts[dimension.code] || labelFor(metricTexts, dimension.code, dimension.code); + const angle = -Math.PI / 2 + (index / TRIWORLD_RADAR_DIMS.length) * Math.PI * 2; + const horizontalDirection = Math.cos(angle); + const labelAnchor = horizontalDirection > 0.25 ? "start" : horizontalDirection < -0.25 ? "end" : "middle"; + const tickOffsetX = -Math.sin(angle) * 6; + const tickOffsetY = Math.cos(angle) * 6; + const labelXValue = labelX.toFixed(1); + return ( + + + + {radarLabelSpans(label.en, "i18n-en", labelXValue)} + {radarLabelSpans(label.zh, "i18n-zh", labelXValue)} + + {ringFractions.map((fraction) => { + const [tickX, tickY] = radarPoint( + cx, + cy, + radius, + index, + TRIWORLD_RADAR_DIMS.length, + fraction * 100 + ); + return ( + + {Math.round(dimension.maxValue * fraction)} + + ); + })} + + ); + })} + + {rows.map((row) => { + const globalIndex = Math.max(0, allRows.findIndex((item) => item.modelName === row.modelName)); + const color = TRIWORLD_COLORS[globalIndex % TRIWORLD_COLORS.length]; + const dashPattern = RADAR_LINE_PATTERNS[globalIndex % RADAR_LINE_PATTERNS.length]; + const points = TRIWORLD_RADAR_DIMS.map((dimension, dimensionIndex) => + radarPoint( + cx, + cy, + radius, + dimensionIndex, + TRIWORLD_RADAR_DIMS.length, + radarPercentage(row.metrics[dimension.code], dimension.maxValue) + ) + .map((coordinate) => coordinate.toFixed(1)) + .join(",") + ).join(" "); + const isHighlighted = highlightName === row.modelName; + const isDimmed = Boolean(highlightName && !isHighlighted); + + return ( + + + + + ); + })} + + {highlighted && + TRIWORLD_RADAR_DIMS.map((dimension, index) => { + const [x, y] = radarPoint( + cx, + cy, + radius, + index, + TRIWORLD_RADAR_DIMS.length, + radarPercentage(highlighted.metrics[dimension.code], dimension.maxValue) + ); + const color = + TRIWORLD_COLORS[ + Math.max(0, allRows.findIndex((row) => row.modelName === highlighted.modelName)) % + TRIWORLD_COLORS.length + ]; + return ( + + + + {fmt(highlighted.metrics[dimension.code])} + + + ); + })} + + ); +} + +export function TriWorldCases() { + const [activeCategory, setActiveCategory] = useState<"clean" | "random">("clean"); + + return ( + <> +
+ + +
+ + + + ); +} + +export function TriWorldVisualization({ + rows, + metricTexts, + categoryTexts, + sectionNumber, + titleText, + descriptionText, +}: { + rows: TriWorldBoardEntry[]; + metricTexts: Record; + categoryTexts: Record; + sectionNumber: string; + titleText: LocalizedText; + descriptionText: LocalizedText; +}) { + const [panelKey, setPanelKey] = useState<(typeof TRIWORLD_VIS_PANELS)[number]["key"]>("overall"); + const [highlightName, setHighlightName] = useState(null); + const [modelQuery, setModelQuery] = useState(""); + const rankingListRef = useRef(null); + + const visibleRows = useMemo(() => { + const query = modelQuery.trim().toLocaleLowerCase(); + if (!query) return rows; + return rows.filter((row) => row.modelName.toLocaleLowerCase().includes(query)); + }, [modelQuery, rows]); + + useEffect(() => { + if (highlightName && !visibleRows.some((row) => row.modelName === highlightName)) { + setHighlightName(null); + } + }, [highlightName, visibleRows]); + + const visiblePanels = useMemo( + () => TRIWORLD_VIS_PANELS.filter((panel) => + hasLocalizedText(panelLabelFor(metricTexts, panel.code, panel.key)) + ), + [metricTexts] + ); + const activePanel = + visiblePanels.find((panel) => panel.key === panelKey) ?? + visiblePanels[0] ?? + TRIWORLD_VIS_PANELS[0]; + const rankedRows = useMemo(() => { + const sorted = [...visibleRows]; + if (activePanel.code) { + sorted.sort( + (a, b) => + (b.metrics[activePanel.code as string] ?? -Infinity) - + (a.metrics[activePanel.code as string] ?? -Infinity) + ); + return sorted.map((row, index) => ({ + ...row, + value: row.metrics[activePanel.code as string] ?? null, + visualRank: index + 1, + })); + } + sorted.sort((a, b) => (b.score ?? -Infinity) - (a.score ?? -Infinity)); + return sorted.map((row, index) => ({ ...row, value: row.score, visualRank: index + 1 })); + }, [activePanel.code, visibleRows]); + + useEffect(() => { + if (!highlightName) return; + + const list = rankingListRef.current; + const selectedRow = Array.from(list?.querySelectorAll(".twb-bar-row") || []) + .find((row) => row.dataset.model === highlightName); + if (!list || !selectedRow) return; + + const listRect = list.getBoundingClientRect(); + const rowRect = selectedRow.getBoundingClientRect(); + list.scrollTop = Math.max( + 0, + list.scrollTop + rowRect.top - listRect.top - (list.clientHeight - rowRect.height) / 2 + ); + }, [activePanel.key, highlightName, rankedRows]); + + const maxValue = Math.max( + 1, + ...rankedRows.map((row) => (row.value === null ? 0 : Number(row.value))) + ); + const activePanelTitle = titleFor(metricTexts, activePanel.code, activePanel.key); + + return ( +
+
+ {sectionNumber} +

+
+

+ +

+ +
+
+ +
+
+
+

+ +
+ +
+ {visibleRows.map((row) => { + const globalIndex = Math.max(0, rows.findIndex((item) => item.modelName === row.modelName)); + const color = TRIWORLD_COLORS[globalIndex % TRIWORLD_COLORS.length]; + const isActive = highlightName === row.modelName; + return ( + + ); + })} +
+ {!visibleRows.length ?

: null} +
+
+ +
+ +
+ {visiblePanels.map((panel) => ( + + ))} +
+
+ +
+ {hasLocalizedText(activePanelTitle) ? ( +

+ +

+ ) : null} +
+ {rankedRows.map((row) => { + const globalIndex = Math.max(0, rows.findIndex((item) => item.modelName === row.modelName)); + const color = TRIWORLD_COLORS[globalIndex % TRIWORLD_COLORS.length]; + const isHighlighted = highlightName === row.modelName; + const isDimmed = Boolean(highlightName && !isHighlighted); + const width = row.value === null ? 0 : (Number(row.value) / maxValue) * 100; + const medalColor = row.visualRank === 1 + ? "#c58b13" + : row.visualRank === 2 + ? "#6b7280" + : "#b56736"; + return ( + + ); + })} + {!rankedRows.length ?

: null} +
+
+ +
+ ); +} diff --git a/src/components/triworldbench/LanguageMenu.tsx b/src/components/triworldbench/LanguageMenu.tsx new file mode 100644 index 0000000000000000000000000000000000000000..db605865a806622e86d7e41f4dc255239faa05f6 --- /dev/null +++ b/src/components/triworldbench/LanguageMenu.tsx @@ -0,0 +1,52 @@ +"use client"; + +import React, { useEffect, useState } from "react"; + +type Language = "en" | "zh"; + +const STORAGE_KEY = "triworldbench-language"; + +function normalizeLanguage(value: string | null): Language { + return value === "zh" ? "zh" : "en"; +} + +function applyLanguage(language: Language) { + document.documentElement.setAttribute("data-twb-lang", language); +} + +export function LanguageMenu() { + const [language, setLanguage] = useState("en"); + + useEffect(() => { + const stored = normalizeLanguage(window.sessionStorage.getItem(STORAGE_KEY)); + setLanguage(stored); + applyLanguage(stored); + }, []); + + const chooseLanguage = (nextLanguage: Language) => { + setLanguage(nextLanguage); + window.sessionStorage.setItem(STORAGE_KEY, nextLanguage); + applyLanguage(nextLanguage); + }; + + return ( +
+ + +
+ ); +} diff --git a/src/components/triworldbench/Leaderboard.tsx b/src/components/triworldbench/Leaderboard.tsx new file mode 100644 index 0000000000000000000000000000000000000000..1ab498ae5a9ccebb0b44c4661d2d1ed19d952f42 --- /dev/null +++ b/src/components/triworldbench/Leaderboard.tsx @@ -0,0 +1,305 @@ +"use client"; + +import React, { useCallback, useMemo, useRef, useState } from "react"; +import { FaMedal } from "react-icons/fa"; +import { contentValue, type LocalizedText } from "@/lib/i18n"; +import { + TRIWORLD_COLORS, + TRIWORLD_TABLE_METRICS, + type TriWorldBoardEntry, +} from "./metrics"; +import { LocalizedMarkdown } from "./LocalizedMarkdown"; + +type MetricText = { + code: string; + label: LocalizedText; + shortLabel: LocalizedText; + title: LocalizedText; + description?: LocalizedText; +}; + +type Props = { + rows: TriWorldBoardEntry[]; + metricTexts: Record; + descriptionText: LocalizedText; +}; + +const RANGE_SIZE = 20; + +function DualText({ en, zh }: { en: React.ReactNode; zh: React.ReactNode }) { + return ( + <> + {en} + {zh} + + ); +} + +function displayScore(value: number | null | undefined): string { + if (value === null || value === undefined || !Number.isFinite(Number(value))) return "TBA"; + return Number(value).toFixed(2); +} + +function textFor( + metricTexts: Record, + code: string, + fallback: string +): LocalizedText { + return metricTexts[code]?.label || metricTexts[code]?.shortLabel || { en: fallback, zh: fallback }; +} + +function headerLines(value: string): string[] { + const words = value.trim().split(/\s+/).filter(Boolean); + if (words.length <= 2) return [value.trim()]; + const lines: string[] = []; + for (let index = 0; index < words.length; index += 2) { + lines.push(words.slice(index, index + 2).join(" ")); + } + return lines; +} + +function MetricHeaderText({ text }: { text: LocalizedText }) { + const en = contentValue(text.en); + const zh = contentValue(text.zh); + return ( + <> + {en ? ( + + {headerLines(en).map((line, index) => ( + {line} + ))} + + ) : null} + {zh ? ( + + {headerLines(zh).map((line, index) => ( + {line} + ))} + + ) : null} + + ); +} + +function valueFor(row: TriWorldBoardEntry, code: string): number | null { + return code === "TWBScore" ? row.score : row.metrics[code] ?? null; +} + +function isScore(value: number | null): value is number { + return value !== null && Number.isFinite(value); +} + +export function TriWorldLeaderboard({ rows, metricTexts, descriptionText }: Props) { + const [query, setQuery] = useState(""); + const [highlightedName, setHighlightedName] = useState(null); + const [message, setMessage] = useState(""); + const rangeMenuRef = useRef(null); + const rowRefs = useRef(new Map()); + + const ranges = useMemo(() => { + const total = Math.ceil(rows.length / RANGE_SIZE); + return Array.from({ length: total }, (_, index) => { + const start = index * RANGE_SIZE; + const end = Math.min(start + RANGE_SIZE, rows.length); + return { index, start, end, label: start === 0 ? `Top ${end}` : `Ranks ${start + 1}-${end}` }; + }); + }, [rows.length]); + + const metricRanks = useMemo(() => { + const ranksByMetric = new Map>(); + + for (const metric of TRIWORLD_TABLE_METRICS) { + const rankedRows = rows + .map((row) => ({ row, value: valueFor(row, metric.code) })) + .filter((entry): entry is { row: TriWorldBoardEntry; value: number } => isScore(entry.value)) + .sort((left, right) => right.value - left.value); + const ranks = new Map(); + let previousValue: number | null = null; + let previousRank = 0; + + rankedRows.forEach((entry, index) => { + const rank = previousValue !== null && entry.value === previousValue ? previousRank : index + 1; + ranks.set(entry.row, rank); + previousValue = entry.value; + previousRank = rank; + }); + ranksByMetric.set(metric.code, ranks); + } + + return ranksByMetric; + }, [rows]); + + const locate = useCallback((name = query) => { + const normalized = name.trim().toLocaleLowerCase(); + if (!normalized) { + setHighlightedName(null); + setMessage(""); + return; + } + const matched = + rows.find((row) => row.modelName.toLocaleLowerCase() === normalized) || + rows.find((row) => row.modelName.toLocaleLowerCase().includes(normalized)); + if (!matched) { + setHighlightedName(null); + setMessage(`No published model matches "${name.trim()}".`); + return; + } + setHighlightedName(matched.modelName); + setMessage(`Located ${matched.modelName} at rank ${matched.rank}.`); + window.requestAnimationFrame(() => { + rowRefs.current.get(matched.modelName)?.scrollIntoView({ behavior: "smooth", block: "center", inline: "nearest" }); + }); + }, [query, rows]); + + const jumpToRange = (start: number) => { + const row = rows[start]; + if (!row) return; + setHighlightedName(null); + setMessage(""); + rangeMenuRef.current?.removeAttribute("open"); + window.requestAnimationFrame(() => { + rowRefs.current.get(row.modelName)?.scrollIntoView({ behavior: "smooth", block: "start", inline: "nearest" }); + }); + }; + + return ( +
+

+ +

+ +
+
+ + + +
+ {ranges.map((range) => ( + + ))} +
+
+
{ + event.preventDefault(); + locate(); + }} + > + + setQuery(event.target.value)} + placeholder="Model name" + autoComplete="off" + /> + +
+
+ {message ?

{message}

: null} + +
+ + + + + + {TRIWORLD_TABLE_METRICS.map((metric) => { + const label = textFor(metricTexts, metric.code, metric.code); + return ( + + ); + })} + + + + {rows.flatMap((row, index) => { + const color = TRIWORLD_COLORS[index % TRIWORLD_COLORS.length]; + const range = ranges.find((item) => item.start === index); + const isHighlighted = highlightedName === row.modelName; + const entry = ( + { + if (node) rowRefs.current.set(row.modelName, node); + else rowRefs.current.delete(row.modelName); + }} + data-highlighted={isHighlighted ? "true" : undefined} + style={{ "--model-highlight": color } as React.CSSProperties} + > + + + {TRIWORLD_TABLE_METRICS.map((metric) => { + const value = valueFor(row, metric.code); + const metricRank = metricRanks.get(metric.code)?.get(row) ?? null; + return ( + + ); + })} + + ); + return range + ? [ + + + , + entry, + ] + : [entry]; + })} + +
+ +
+ {row.modelName} + {row.teamName ? {row.teamName} : null} + {row.rank} +
+ {metricRank !== null ? ( + + {metricRank <= 3 ? ( + + ) : null} + {displayScore(value)} +
+
+ +
+
+
+ ); +} diff --git a/src/components/triworldbench/LocalizedMarkdown.tsx b/src/components/triworldbench/LocalizedMarkdown.tsx new file mode 100644 index 0000000000000000000000000000000000000000..d98f1b40f05a4f83872e50f170d6f66fbfdbbf94 --- /dev/null +++ b/src/components/triworldbench/LocalizedMarkdown.tsx @@ -0,0 +1,147 @@ +import React from "react"; +import { contentValue, type LocalizedText } from "@/lib/i18n"; + +type InlineToken = { + kind: "strong" | "em" | "code" | "link" | "text"; + value: string; + href?: string; +}; + +function isSafeHref(value: string): boolean { + return /^(https?:\/\/|mailto:|\/|#)/i.test(value.trim()); +} + +function tokenizeInline(value: string): InlineToken[] { + const tokens: InlineToken[] = []; + const expression = /(\*\*[^*]+\*\*|`[^`]+`|\[[^\]]+\]\([^\s)]+\)|\*[^*]+\*)/g; + let cursor = 0; + for (const match of value.matchAll(expression)) { + const index = match.index ?? 0; + if (index > cursor) tokens.push({ kind: "text", value: value.slice(cursor, index) }); + const token = match[0]; + if (token.startsWith("**")) tokens.push({ kind: "strong", value: token.slice(2, -2) }); + else if (token.startsWith("`")) tokens.push({ kind: "code", value: token.slice(1, -1) }); + else if (token.startsWith("[")) { + const link = /^\[([^\]]+)\]\(([^\s)]+)\)$/.exec(token); + if (link && isSafeHref(link[2])) tokens.push({ kind: "link", value: link[1], href: link[2] }); + else tokens.push({ kind: "text", value: token }); + } else tokens.push({ kind: "em", value: token.slice(1, -1) }); + cursor = index + token.length; + } + if (cursor < value.length) tokens.push({ kind: "text", value: value.slice(cursor) }); + return tokens; +} + +export function MarkdownInline({ value }: { value: string }) { + const lines = value.split("\n"); + return ( + <> + {lines.map((line, lineIndex) => ( + + {lineIndex ?
: null} + {tokenizeInline(line).map((token, index) => { + if (token.kind === "strong") return ; + if (token.kind === "em") return ; + if (token.kind === "code") return {token.value}; + if (token.kind === "link") { + const external = /^https?:\/\//i.test(token.href || ""); + return {token.value}; + } + return {token.value}; + })} +
+ ))} + + ); +} + +export function MarkdownBlocks({ value }: { value: string }) { + const lines = value.replace(/\r\n?/g, "\n").split("\n"); + const blocks: React.ReactNode[] = []; + let index = 0; + + while (index < lines.length) { + const line = lines[index]; + if (!line.trim()) { + index += 1; + continue; + } + if (line.startsWith("```")) { + const language = line.slice(3).trim(); + const code: string[] = []; + index += 1; + while (index < lines.length && !lines[index].startsWith("```")) { + code.push(lines[index]); + index += 1; + } + if (index < lines.length) index += 1; + blocks.push(
{code.join("\n")}
); + continue; + } + const heading = /^(#{1,6})\s+(.+)$/.exec(line); + if (heading) { + const level = Math.min(5, heading[1].length + 2); + const Tag = `h${level}` as "h3" | "h4" | "h5"; + blocks.push(); + index += 1; + continue; + } + const unordered = /^[-*+]\s+(.+)$/.exec(line); + const ordered = /^\d+[.)]\s+(.+)$/.exec(line); + if (unordered || ordered) { + const orderedList = Boolean(ordered); + const values: string[] = []; + while (index < lines.length) { + const match = orderedList ? /^\d+[.)]\s+(.+)$/.exec(lines[index]) : /^[-*+]\s+(.+)$/.exec(lines[index]); + if (!match) break; + values.push(match[1]); + index += 1; + } + const List = orderedList ? "ol" : "ul"; + blocks.push({values.map((item, itemIndex) =>
  • )}
    ); + continue; + } + const paragraph = [line]; + index += 1; + while ( + index < lines.length && + lines[index].trim() && + !lines[index].startsWith("```") && + !/^(#{1,6})\s+/.test(lines[index]) && + !/^[-*+]\s+/.test(lines[index]) && + !/^\d+[.)]\s+/.test(lines[index]) + ) { + paragraph.push(lines[index]); + index += 1; + } + blocks.push(

    ); + } + + return <>{blocks}; +} + +export function LocalizedMarkdown({ + text, + inline = false, +}: { + text?: LocalizedText; + inline?: boolean; +}) { + const en = contentValue(text?.en); + const zh = contentValue(text?.zh); + if (!en && !zh) return null; + if (inline) { + return ( + <> + {en ? : null} + {zh ? : null} + + ); + } + return ( + <> + {en ?
    : null} + {zh ?
    : null} + + ); +} diff --git a/src/components/triworldbench/OpsStack.tsx b/src/components/triworldbench/OpsStack.tsx new file mode 100644 index 0000000000000000000000000000000000000000..88f9c7dc6a84721864bbf1f2aafee4f976ada7fe --- /dev/null +++ b/src/components/triworldbench/OpsStack.tsx @@ -0,0 +1,30 @@ +interface OpsCheck { + label: string; +} + +export function OpsStack({ + sectionNumber, + title, + description, + checks, +}: { + sectionNumber: string; + title: string; + description: string; + checks: OpsCheck[]; +}) { + return ( +
    +
    + {sectionNumber} +

    {title}

    +
    +

    {description}

    +
      + {checks.map((c) => ( +
    • {c.label}
    • + ))} +
    +
    + ); +} diff --git a/src/components/triworldbench/PhaseMonitor.tsx b/src/components/triworldbench/PhaseMonitor.tsx new file mode 100644 index 0000000000000000000000000000000000000000..58def66fec060b9b7c64437579ea2fac3a9bcd6f --- /dev/null +++ b/src/components/triworldbench/PhaseMonitor.tsx @@ -0,0 +1,33 @@ +interface Phase { + label: string; + value: number; +} + +export function PhaseMonitor({ + sectionNumber, + title, + description, + phases, +}: { + sectionNumber: string; + title: string; + description: string; + phases: Phase[]; +}) { + return ( +
    +
    + {sectionNumber} +

    {title}

    +
    +

    {description}

    +
    + {phases.map((p) => ( + + {p.label} + + ))} +
    +
    + ); +} diff --git a/src/components/triworldbench/TelemetryQueue.tsx b/src/components/triworldbench/TelemetryQueue.tsx new file mode 100644 index 0000000000000000000000000000000000000000..564327673bd7966fba7f6673964262e3f6c72416 --- /dev/null +++ b/src/components/triworldbench/TelemetryQueue.tsx @@ -0,0 +1,36 @@ +interface TelemetryChannel { + label: string; + value: string; + note: string; +} + +export function TelemetryQueue({ + sectionNumber, + title, + description, + channels, +}: { + sectionNumber: string; + title: string; + description: string; + channels: TelemetryChannel[]; +}) { + return ( +
    +
    + {sectionNumber} +

    {title}

    +
    +

    {description}

    +
    + {channels.map((ch) => ( +
    + {ch.label} + {ch.value} + {ch.note} +
    + ))} +
    +
    + ); +} diff --git a/src/components/triworldbench/metrics.ts b/src/components/triworldbench/metrics.ts new file mode 100644 index 0000000000000000000000000000000000000000..74296e877c9a19f8ad3d43d90ec67bdf1c47235f --- /dev/null +++ b/src/components/triworldbench/metrics.ts @@ -0,0 +1,204 @@ +export const TRIWORLD_COLORS = [ + "#0f766e", "#2563eb", "#d97706", "#16a34a", "#7c3aed", "#e11d48", + "#0891b2", "#4f46e5", "#c2410c", "#15803d", "#9333ea", "#be123c", + "#0369a1", "#a16207", "#0f766e", "#4338ca", "#b45309", "#047857", + "#6d28d9", "#9f1239", "#155e75", "#1d4ed8", "#ca8a04", "#166534", +] as const; + +export const TRIWORLD_RANKING_CODE = "TWBScore" as const; +export const TRIWORLD_SCORE_ACCENT = "#a16207" as const; + +// Database keys used by Evaluation Metrics. The leaderboard uses these labels +// so the table always follows the terminology maintained in localization data. +export const TRIWORLD_EVALUATION_DEFINITION_CODES: Readonly> = { + "twb-score": "TWBScore", + "tri-view-consistency": "tri_view_consistency", + "task-alignment": "task_alignment", + "physical-3d-coherence": "physical_3d_coherence", + "motion-quality": "motion_quality", + "temporal-consistency": "temporal_consistency", + "visual-quality": "visual_quality", + "normalized-psnr": "psnr", + ssim: "ssim", + "vlm-consistency-i": "vlm_consistency_i", + "vlm-consistency-ii": "vlm_consistency_ii", + "vlm-consistency-iii": "vlm_consistency_iii", + "vqa-consistency": "vqa_consistency", + "instruction-following": "Instruction_Following", + "semantic-alignment": "semantic_alignment", + "jepa-similarity": "jepa_similarity", + "interaction-quality": "Interaction_Quality", + perspective: "Perspectivity", + "state-alignment": "dynamic_state_alignment", + "flow-score": "flow_score", + "trajectory-accuracy": "trajectory_accuracy", + "subject-consistency": "subject_consistency", + "background-consistency": "background_consistency", + "photometric-smoothness": "photometric_smoothness", + "image-quality": "image_quality", + "aesthetic-quality": "aesthetic_quality", +}; + +export interface TriWorldMetricDefinition { + key: string; + code: string; +} + +export interface TriWorldMetricGroup { + key: string; + code: string; + color: string; + submetrics: readonly TriWorldMetricDefinition[]; +} + +export const TRIWORLD_METRIC_GROUPS: readonly TriWorldMetricGroup[] = [ + { + key: "twb-score", + code: TRIWORLD_RANKING_CODE, + color: TRIWORLD_SCORE_ACCENT, + submetrics: [], + }, + { + key: "tri-view-consistency", + code: "tri_view_consistency", + color: "#2563eb", + submetrics: [ + { key: "psnr", code: "psnr" }, + { key: "ssim", code: "ssim" }, + { key: "vlm-i", code: "vlm_consistency_i" }, + { key: "vlm-ii", code: "vlm_consistency_ii" }, + { key: "vlm-iii", code: "vlm_consistency_iii" }, + { key: "vqa", code: "vqa_consistency" }, + ], + }, + { + key: "task-alignment", + code: "task_alignment", + color: "#f97316", + submetrics: [ + { key: "instruction", code: "Instruction_Following" }, + { key: "semantic", code: "semantic_alignment" }, + { key: "jepa", code: "jepa_similarity" }, + ], + }, + { + key: "physical-3d-coherence", + code: "physical_3d_coherence", + color: "#16a34a", + submetrics: [ + { key: "interaction", code: "Interaction_Quality" }, + { key: "perspectivity", code: "Perspectivity" }, + ], + }, + { + key: "motion-quality", + code: "motion_quality", + color: "#7c3aed", + submetrics: [ + { key: "state-alignment", code: "dynamic_state_alignment" }, + { key: "flow", code: "flow_score" }, + { key: "trajectory", code: "trajectory_accuracy" }, + ], + }, + { + key: "temporal-consistency", + code: "temporal_consistency", + color: "#e11d48", + submetrics: [ + { key: "subject", code: "subject_consistency" }, + { key: "background", code: "background_consistency" }, + { key: "photometric", code: "photometric_smoothness" }, + ], + }, + { + key: "visual-quality", + code: "visual_quality", + color: "#0f766e", + submetrics: [ + { key: "image", code: "image_quality" }, + { key: "aesthetic", code: "aesthetic_quality" }, + ], + }, +]; + +export interface TriWorldTableMetric extends TriWorldMetricDefinition { + groupKey: string; + color: string; + isOverall: boolean; + isCategory: boolean; + className: string; +} + +export const TRIWORLD_TABLE_METRICS: readonly TriWorldTableMetric[] = [ + // Keep the total and all second-level category scores together before any third-level metric. + ...TRIWORLD_METRIC_GROUPS.map((group) => ({ + key: group.key, + code: group.code, + groupKey: group.key, + color: group.color, + isOverall: group.code === TRIWORLD_RANKING_CODE, + isCategory: true, + className: "twb-col-category", + })), + ...TRIWORLD_METRIC_GROUPS.flatMap((group) => + group.submetrics.map((metric) => ({ + ...metric, + groupKey: group.key, + color: group.color, + isOverall: false, + isCategory: false, + className: "twb-col-submetric", + })) + ), +]; + +export const TRIWORLD_ALL_METRIC_CODES = TRIWORLD_TABLE_METRICS.map((metric) => metric.code); + +export const TRIWORLD_RADAR_DIMS = TRIWORLD_METRIC_GROUPS + .filter((group) => group.code !== TRIWORLD_RANKING_CODE) + .map((group) => ({ + key: group.key, + code: group.code, + color: group.color, + maxValue: group.code === "visual_quality" ? 50 : 100, + })); + +export interface TriWorldVisualizationPanel { + key: string; + code: string | null; + groupKey: string; + kind: "overall" | "category" | "submetric"; +} + +export const TRIWORLD_VIS_PANELS: readonly TriWorldVisualizationPanel[] = [ + { key: "overall", code: null, groupKey: "twb-score", kind: "overall" }, + ...TRIWORLD_METRIC_GROUPS + .filter((group) => group.code !== TRIWORLD_RANKING_CODE) + .flatMap((group) => [ + { + key: group.key, + code: group.code, + groupKey: group.key, + kind: "category" as const, + }, + ...group.submetrics.map((metric) => ({ + key: metric.key, + code: metric.code, + groupKey: group.key, + kind: "submetric" as const, + })), + ]), +]; + +export type TriWorldMetricCode = string; + +export interface TriWorldBoardEntry { + rank: number; + modelName: string; + teamName: string; + score: number | null; + normalizedScore: number | null; + status: string; + metrics: Record; + normalizedMetrics: Record; +} diff --git a/src/lib/csv-parser.ts b/src/lib/csv-parser.ts new file mode 100644 index 0000000000000000000000000000000000000000..eeae77dbaa0ba25242fa257c6d02e2fa3d0f70dc --- /dev/null +++ b/src/lib/csv-parser.ts @@ -0,0 +1,63 @@ +/** CSV/TXT parser for participantEmail + modelName batch score uploads. */ +export interface ParsedCsvRow { + participantEmail: string; + modelName: string; + scores: Record; +} + +export interface CsvParseResult { + rows: ParsedCsvRow[]; + errors: string[]; + metricCodes: string[]; +} + +export function parseCsv(text: string, validMetricCodes: string[]): CsvParseResult { + const errors: string[] = []; + const rows: ParsedCsvRow[] = []; + const lines = text.replace(/^\uFEFF/, "").replace(/\r\n/g, "\n").replace(/\r/g, "\n") + .split("\n").filter((line) => line.trim()); + if (lines.length < 2) { + return { rows, errors: ["The file must include a header row and at least one data row"], metricCodes: [] }; + } + + const delimiter = lines[0].includes("\t") ? "\t" : ","; + const headers = lines[0].split(delimiter).map((header) => header.trim()); + const emailIndex = headers.findIndex((header) => header.toLowerCase() === "participantemail"); + const modelNameIndex = headers.findIndex((header) => header.toLowerCase() === "modelname"); + if (emailIndex < 0 || modelNameIndex < 0) { + return { rows, errors: ["The header must include participantEmail and modelName"], metricCodes: [] }; + } + + const columns = new Map(); + headers.forEach((header, index) => { + if (index === emailIndex || index === modelNameIndex) return; + const metric = validMetricCodes.find((code) => code.toLowerCase() === header.toLowerCase()); + if (metric) columns.set(index, metric); + else errors.push(`Column ${index + 1} "${header}" is not a valid metric code and was skipped`); + }); + if (!columns.size) { + return { rows, errors: [...errors, "No valid metric code columns were found"], metricCodes: [] }; + } + + lines.slice(1).forEach((line, rowIndex) => { + const cells = line.split(delimiter).map((cell) => cell.trim()); + const participantEmail = cells[emailIndex] || ""; + const modelName = cells[modelNameIndex] || ""; + if (!participantEmail || !modelName) { + errors.push(`Row ${rowIndex + 2}: participantEmail and modelName are required`); + return; + } + const scores: Record = {}; + columns.forEach((metricCode, columnIndex) => { + const raw = cells[columnIndex]; + if (!raw) return; + const value = Number(raw); + if (Number.isNaN(value)) errors.push(`Row ${rowIndex + 2}: ${metricCode} value "${raw}" is not numeric`); + else scores[metricCode] = value; + }); + if (Object.keys(scores).length) rows.push({ participantEmail, modelName, scores }); + else errors.push(`Row ${rowIndex + 2}: no valid scores were found`); + }); + + return { rows, errors, metricCodes: [...new Set(columns.values())] }; +} diff --git a/src/lib/data/announcements.ts b/src/lib/data/announcements.ts new file mode 100644 index 0000000000000000000000000000000000000000..a42b09e0ec54d4b8443a5b01ca3fca7b24162d7b --- /dev/null +++ b/src/lib/data/announcements.ts @@ -0,0 +1,9 @@ +import { getDb } from "@/lib/db"; +import { all } from "@/lib/db/helpers"; +import type { Announcement } from "@/lib/db/schema"; + +export function getAnnouncements(): Announcement[] { + return all( + getDb().prepare("SELECT * FROM announcements ORDER BY published_at DESC, id DESC") + ); +} diff --git a/src/lib/data/contacts.ts b/src/lib/data/contacts.ts new file mode 100644 index 0000000000000000000000000000000000000000..5e45c2f892c7eb68fcda62014a3ce3f7369928d2 --- /dev/null +++ b/src/lib/data/contacts.ts @@ -0,0 +1,16 @@ +import { getDb } from "@/lib/db"; +import { all, get as dbGet } from "@/lib/db/helpers"; +import type { ContactInfo, OtherInformation } from "@/lib/db/schema"; +import { localized } from "@/lib/i18n"; + +export function getContacts(): ContactInfo[] { + return all(getDb().prepare("SELECT * FROM contact_info ORDER BY sort_order, id")).map((contact) => ({ + ...contact, + labelText: localized(contact.label_en ?? contact.label, contact.label_zh), + descriptionText: localized(contact.description_en, contact.description_zh), + })); +} + +export function getOtherInformation(): OtherInformation | null { + return dbGet(getDb().prepare("SELECT * FROM other_information ORDER BY id LIMIT 1")); +} diff --git a/src/lib/data/datasets.ts b/src/lib/data/datasets.ts new file mode 100644 index 0000000000000000000000000000000000000000..79eea87d154aaa00ca62952d9c4537ba469ad543 --- /dev/null +++ b/src/lib/data/datasets.ts @@ -0,0 +1,51 @@ +import { getDb } from "@/lib/db"; +import { all } from "@/lib/db/helpers"; +import type { Dataset, UploadRequirement, SubmissionFileType } from "@/lib/db/schema"; +import { contentValue, hasLocalizedText, localized } from "@/lib/i18n"; + +export function getDatasetsWithVersions(): { + datasets: Dataset[]; + uploadRequirements: UploadRequirement[]; + fileTypes: SubmissionFileType[]; +} { + const db = getDb(); + const uploadRequirements = all( + db.prepare("SELECT * FROM upload_requirements ORDER BY sort_order, id") + ) + .map((row) => ({ + ...row, + titleText: localized(row.title_en || row.title, row.title_zh), + bodyText: localized(row.body_en || row.body, row.body_zh), + })) + .filter((row) => hasLocalizedText(row.titleText) || hasLocalizedText(row.bodyText)); + const fileTypes = all( + db.prepare("SELECT * FROM submission_file_types ORDER BY id") + ) + .map((row) => ({ + ...row, + accepted_extensions: contentValue(row.accepted_extensions), + labelText: localized(row.label_en || row.label, row.label_zh), + descriptionText: localized(row.description_en || row.description || "", row.description_zh), + })) + .filter( + (row) => + hasLocalizedText(row.labelText) || + hasLocalizedText(row.descriptionText) || + Boolean(row.accepted_extensions) + ); + return { + datasets: all(db.prepare( + `SELECT d.*, v.version_label, v.release_date, v.download_url, v.checksum, v.notes AS version_notes + FROM datasets d LEFT JOIN dataset_versions v ON v.dataset_id = d.id AND v.is_latest = 1 ORDER BY d.id` + )), + uploadRequirements, + fileTypes, + }; +} + +export function getDatasets(): Dataset[] { + return all(getDb().prepare( + `SELECT d.*, v.version_label, v.release_date, v.download_url, v.checksum, v.notes AS version_notes + FROM datasets d LEFT JOIN dataset_versions v ON v.dataset_id = d.id AND v.is_latest = 1 ORDER BY d.id` + )); +} diff --git a/src/lib/data/evaluation.ts b/src/lib/data/evaluation.ts new file mode 100644 index 0000000000000000000000000000000000000000..8cfc7c5ca5afb9accd52a4d5dee1d9e3e770843a --- /dev/null +++ b/src/lib/data/evaluation.ts @@ -0,0 +1,9 @@ +import { getDb } from "@/lib/db"; +import { all } from "@/lib/db/helpers"; +import type { EvaluationSection } from "@/lib/db/schema"; + +export function getEvaluationSections(): EvaluationSection[] { + return all( + getDb().prepare("SELECT * FROM evaluation_sections ORDER BY sort_order, id") + ); +} diff --git a/src/lib/data/important-dates.ts b/src/lib/data/important-dates.ts new file mode 100644 index 0000000000000000000000000000000000000000..96cd6128544ce1ff1d2ce386f6344426bf9ab6f1 --- /dev/null +++ b/src/lib/data/important-dates.ts @@ -0,0 +1,41 @@ +import { getDb } from "@/lib/db"; +import { all } from "@/lib/db/helpers"; +import { getDateStatus } from "@/lib/utils"; +import type { ImportantDate } from "@/lib/db/schema"; +import { hasLocalizedText, localized } from "@/lib/i18n"; + +function formatDate(value: string, locale: "en" | "zh"): string { + const date = new Date(value); + if (Number.isNaN(date.getTime())) return value; + return new Intl.DateTimeFormat(locale === "zh" ? "zh-CN" : "en-US", { + month: locale === "zh" ? "long" : "short", + day: "2-digit", + year: "numeric", + timeZone: "UTC", + }).format(date); +} + +export function getImportantDates(): ImportantDate[] { + const rows = all( + getDb().prepare("SELECT * FROM important_dates ORDER BY sort_order, starts_at") + ); + return rows + .map((row) => ({ + ...row, + status: getDateStatus(row.starts_at, row.ends_at), + titleText: localized(row.title_en || row.title, row.title_zh), + dateLabelText: localized( + row.date_label_en || formatDate(row.starts_at, "en"), + row.date_label_zh || formatDate(row.starts_at, "zh") + ), + bodyText: localized(row.body_en || row.body, row.body_zh), + ctaLabelText: localized(row.cta_label_en || row.cta_label || "", row.cta_label_zh), + })) + .filter( + (row) => + hasLocalizedText(row.titleText) || + hasLocalizedText(row.dateLabelText) || + hasLocalizedText(row.bodyText) || + hasLocalizedText(row.ctaLabelText) + ); +} diff --git a/src/lib/data/leaderboard.ts b/src/lib/data/leaderboard.ts new file mode 100644 index 0000000000000000000000000000000000000000..4a690752260228d63cd213f97ada279b1c184837 --- /dev/null +++ b/src/lib/data/leaderboard.ts @@ -0,0 +1,153 @@ +import { getDb } from "@/lib/db"; +import { get as dbGet, all } from "@/lib/db/helpers"; +import { latestScoresForSubmissions } from "@/lib/data/metrics"; +import type { LeaderboardSnapshot, LeaderboardEntry, RadarEntry } from "@/lib/db/schema"; + +export const DEFAULT_RADAR_METRICS = [ + "tri_view_consistency", "task_alignment", "physical_3d_coherence", + "motion_quality", "temporal_consistency", "visual_quality", +]; +export const PUBLIC_LEADERBOARD_LIMIT = 10_000; + +export function latestSnapshot(snapshotParam?: string | null): LeaderboardSnapshot | null { + const db = getDb(); + if (snapshotParam && snapshotParam !== "latest") { + return ( + dbGet(db.prepare("SELECT * FROM leaderboard_snapshots WHERE id = ?"), snapshotParam) || + dbGet(db.prepare("SELECT * FROM leaderboard_snapshots WHERE label = ?"), snapshotParam) + ); + } + return dbGet( + db.prepare("SELECT * FROM leaderboard_snapshots ORDER BY is_latest DESC, snapshot_time DESC, id DESC LIMIT 1") + ); +} + +export function getSnapshotHistory(): LeaderboardSnapshot[] { + return all( + getDb().prepare("SELECT * FROM leaderboard_snapshots ORDER BY snapshot_time DESC, id DESC") + ); +} + +export function getLeaderboard( + snapshotParam?: string | null, + limit = PUBLIC_LEADERBOARD_LIMIT +): { + snapshot: LeaderboardSnapshot | null; + entries: LeaderboardEntry[]; +} { + const db = getDb(); + const snapshot = latestSnapshot(snapshotParam); + if (!snapshot) return { snapshot: null, entries: [] }; + const safeLimit = Math.max(1, Math.min(limit, PUBLIC_LEADERBOARD_LIMIT)); + + const rawEntries = db + .prepare( + `SELECT e.rank, e.status_label, e.updated_label, e.submission_id, + t.id AS team_id, t.slug AS team_slug, t.name AS team_name, t.affiliation, t.strengths, + mo.id AS model_id, mo.slug AS model_slug, mo.name AS model_name, + s.version_label, s.status AS submission_status, s.dataset_split, s.submitted_at, + sr.normalized_value, sr.percentile, sr.raw_value + FROM leaderboard_snapshot_entries e + JOIN submissions s ON s.id = e.submission_id + JOIN models mo ON mo.id = s.model_id + JOIN teams t ON t.id = mo.team_id + JOIN score_records sr ON sr.id = e.score_record_id + WHERE e.snapshot_id = ? ORDER BY e.rank LIMIT ?` + ) + .all(snapshot.id, safeLimit) as Array>; + + const submissionIds = rawEntries.map((e) => e.submission_id as number); + const scoresBySubmission = latestScoresForSubmissions(submissionIds); + + const entries: LeaderboardEntry[] = rawEntries.map((entry) => ({ + rank: entry.rank as number, + statusLabel: entry.status_label as string | null, + updatedLabel: entry.updated_label as string | null, + team: { + id: entry.team_id as number, slug: entry.team_slug as string, + name: entry.team_name as string, affiliation: entry.affiliation as string | null, + strengths: entry.strengths as string | null, + }, + model: { + id: entry.model_id as number, slug: entry.model_slug as string, + name: entry.model_name as string, + }, + submission: { + id: entry.submission_id as number, versionLabel: entry.version_label as string, + status: entry.submission_status as string, datasetSplit: entry.dataset_split as string | null, + submittedAt: entry.submitted_at as string, + }, + score: { + rawValue: entry.raw_value as number | null, + normalizedValue: entry.normalized_value as number | null, + percentile: entry.percentile as number | null, + }, + metrics: scoresBySubmission.get(entry.submission_id as number) || {}, + })); + + return { snapshot, entries }; +} + +export function getRadarData( + metricCodes?: string[], + top = 8 +): { metricCodes: string[]; entries: RadarEntry[] } { + const codes = metricCodes?.length ? metricCodes : DEFAULT_RADAR_METRICS; + const board = getLeaderboard("latest"); + const entries = board.entries.slice(0, top).map((entry) => ({ + rank: entry.rank, model: entry.model, team: entry.team, score: entry.score, + axes: codes.map((code) => { + const metric = entry.metrics[code]; + return { code, label: metric ? metric.displayName : code, value: metric?.percentile ?? null }; + }), + })); + return { metricCodes: codes, entries }; +} + +export function rerankSnapshot(snapshotId: number): void { + const db = getDb(); + const rows = db + .prepare( + `SELECT e.id, sr.raw_value FROM leaderboard_snapshot_entries e + JOIN score_records sr ON sr.id = e.score_record_id + WHERE e.snapshot_id = ? ORDER BY sr.raw_value DESC, e.id` + ) + .all(snapshotId) as Array<{ id: number; raw_value: number | null }>; + + for (const row of rows) { + db.prepare("UPDATE leaderboard_snapshot_entries SET rank = ? WHERE id = ?").run(-row.id, row.id); + } + rows.forEach((_row, index) => { + db.prepare("UPDATE leaderboard_snapshot_entries SET rank = ? WHERE id = ?").run(index + 1, rows[index].id); + }); +} + +export function getModelScores(modelId: string): { + model: Record | null; + submission: Record | null; + scores: Array>; +} { + const db = getDb(); + const model = db.prepare( + `SELECT mo.*, t.name AS team_name FROM models mo JOIN teams t ON t.id = mo.team_id WHERE mo.id = ? OR mo.slug = ?` + ).get(modelId, modelId) as Record | null; + + if (!model) return { model: null, submission: null, scores: [] }; + + const modelIdNum = model.id as number; + const submission = db.prepare( + "SELECT * FROM submissions WHERE model_id = ? ORDER BY submitted_at DESC, id DESC LIMIT 1" + ).get(modelIdNum) as Record | null; + + if (!submission) return { model, submission: null, scores: [] }; + + const subId = submission.id as number; + const scores = db.prepare( + `SELECT m.code, m.display_name, m.category, sr.raw_value, sr.normalized_value, sr.percentile, sr.recorded_at + FROM score_records sr JOIN metrics m ON m.id = sr.metric_id + JOIN (SELECT metric_id, MAX(id) AS latest_id FROM score_records WHERE submission_id = ? GROUP BY metric_id) latest ON latest.latest_id = sr.id + ORDER BY m.sort_order` + ).all(subId) as Array>; + + return { model, submission, scores }; +} diff --git a/src/lib/data/metrics.ts b/src/lib/data/metrics.ts new file mode 100644 index 0000000000000000000000000000000000000000..bf3ad26d82b0f871494007acca47b05d58ad0192 --- /dev/null +++ b/src/lib/data/metrics.ts @@ -0,0 +1,60 @@ +import { getDb } from "@/lib/db"; +import { all, get as dbGet } from "@/lib/db/helpers"; +import type { Metric, MetricExplanation, MetricScore } from "@/lib/db/schema"; +import { localized } from "@/lib/i18n"; + +export function getMetrics(): Metric[] { + return all(getDb().prepare("SELECT * FROM metrics ORDER BY sort_order, id")).map((row) => ({ + ...row, + displayNameText: localized(row.display_name_en || row.display_name, row.display_name_zh), + shortLabelText: localized(row.short_label_en || row.display_name_en || row.display_name, row.short_label_zh || row.display_name_zh), + descriptionText: localized(row.description_en || row.description || "", row.description_zh), + })); +} + +export function getMetricExplanations(): MetricExplanation[] { + return all(getDb().prepare("SELECT * FROM metric_explanations ORDER BY id")); +} + +export function latestScoresForSubmissions( + submissionIds: number[] +): Map> { + const db = getDb(); + if (!submissionIds.length) return new Map(); + + const placeholders = submissionIds.map(() => "?").join(","); + const rows = db + .prepare( + `SELECT sr.*, m.* + FROM score_records sr JOIN metrics m ON m.id = sr.metric_id + JOIN (SELECT submission_id, metric_id, MAX(id) AS latest_id + FROM score_records WHERE submission_id IN (${placeholders}) + GROUP BY submission_id, metric_id) latest ON latest.latest_id = sr.id + ORDER BY m.sort_order` + ) + .all(...submissionIds) as Array>; + + const grouped = new Map>(); + for (const row of rows) { + const sid = row.submission_id as number; + if (!grouped.has(sid)) grouped.set(sid, {}); + grouped.get(sid)![row.code as string] = { + code: row.code as string, + displayName: row.display_name as string, + displayNameText: localized( + (row.display_name_en as string | null) || (row.display_name as string), + row.display_name_zh as string | null + ), + shortLabelText: localized( + (row.short_label_en as string | null) || (row.display_name_en as string | null) || (row.display_name as string), + (row.short_label_zh as string | null) || (row.display_name_zh as string | null) + ), + category: row.category as string, + rawValue: row.raw_value as number | null, + normalizedValue: row.normalized_value as number | null, + percentile: row.percentile as number | null, + recordedAt: row.recorded_at as string, + }; + } + return grouped; +} diff --git a/src/lib/data/overview.ts b/src/lib/data/overview.ts new file mode 100644 index 0000000000000000000000000000000000000000..c1b0b37114673a67d125513fb84799a61d6a2231 --- /dev/null +++ b/src/lib/data/overview.ts @@ -0,0 +1,13 @@ +import { getDb } from "@/lib/db"; +import { get as dbGet } from "@/lib/db/helpers"; +import type { OverviewContent } from "@/lib/db/schema"; + +export function getOverview(): OverviewContent | null { + const row = dbGet( + getDb().prepare("SELECT * FROM overview_content ORDER BY id LIMIT 1") + ); + if (row?.stat_json) { + try { row.stats = JSON.parse(row.stat_json); } catch { row.stats = []; } + } + return row; +} diff --git a/src/lib/data/page-data.ts b/src/lib/data/page-data.ts new file mode 100644 index 0000000000000000000000000000000000000000..d1ad61bb78e07f4387c3136c85d25aa785ce524d --- /dev/null +++ b/src/lib/data/page-data.ts @@ -0,0 +1,27 @@ +import { getSiteInfo, getHeroContent } from "@/lib/data/site-info"; +import { getEvaluationSections } from "@/lib/data/evaluation"; +import { getResearchSections, getAcademicReferences } from "@/lib/data/research"; +import { getParticipationInfo } from "@/lib/data/participation"; +import { getVenueHost } from "@/lib/data/venue"; +import { getPolicies } from "@/lib/data/policies"; +import { getContacts, getOtherInformation } from "@/lib/data/contacts"; +import { getLeaderboard } from "@/lib/data/leaderboard"; +import { getImportantDates } from "@/lib/data/important-dates"; + +/** Fetch all database content used by the public site. */ +export function getSharedPageData() { + return { + siteInfo: getSiteInfo(), + hero: getHeroContent(), + evaluation: getEvaluationSections(), + research: getResearchSections(), + references: getAcademicReferences(), + participation: getParticipationInfo(), + venue: getVenueHost(), + policies: getPolicies(), + contacts: getContacts(), + otherInfo: getOtherInformation(), + leaderboard: getLeaderboard("latest"), + dates: getImportantDates(), + }; +} diff --git a/src/lib/data/page-people.ts b/src/lib/data/page-people.ts new file mode 100644 index 0000000000000000000000000000000000000000..a3fcb4a2fbabe26e1fae6d3e889c93f2d8492c4a --- /dev/null +++ b/src/lib/data/page-people.ts @@ -0,0 +1,65 @@ +import { getDb } from "@/lib/db"; +import { all } from "@/lib/db/helpers"; +import type { PageAffiliation, PageAuthor } from "@/lib/db/schema"; +import { hasLocalizedText, localized } from "@/lib/i18n"; + +const FALLBACK_AUTHORS: PageAuthor[] = []; + +const FALLBACK_AFFILIATIONS: PageAffiliation[] = ([ + ["1", "Peking University", "北京大学", "/institution-logos/pku.png", "https://www.pku.edu.cn/"], + ["2", "Tsinghua University", "清华大学", "/institution-logos/tsinghua.png", "https://www.tsinghua.edu.cn/"], + ["3", "Beihang University", "北京航空航天大学", "/institution-logos/buaa.png", "https://www.buaa.edu.cn/"], + ["4", "Shanghai Jiao Tong University", "上海交通大学", "/institution-logos/sjtu.png", "https://www.sjtu.edu.cn/"], + ["5", "University of Science and Technology of China", "中国科学技术大学", "/institution-logos/ustc.png", "https://www.ustc.edu.cn/"], +] as const).map(([ref, name, nameZh, logoPath, websiteUrl], index) => ({ + id: index + 1, + ref, + name, + name_en: name, + name_zh: nameZh, + logo_path: logoPath, + website_url: websiteUrl, + sort_order: index + 1, + updated_at: "", + nameText: localized(name, nameZh), +})); + +function uniqueByLocalizedName(rows: T[]): T[] { + const seen = new Set(); + return rows.filter((row) => { + const key = (row.name_en || row.name).trim().toLowerCase(); + if (seen.has(key)) return false; + seen.add(key); + return true; + }); +} + +export function getPageAuthors(): PageAuthor[] { + try { + const rows = all(getDb().prepare("SELECT * FROM page_authors ORDER BY sort_order, id")); + if (!rows.length) return FALLBACK_AUTHORS; + return uniqueByLocalizedName(rows) + .map((row) => ({ + ...row, + nameText: localized(row.name_en || row.name, row.name_zh), + })) + .filter((row) => hasLocalizedText(row.nameText)); + } catch { + return FALLBACK_AUTHORS; + } +} + +export function getPageAffiliations(): PageAffiliation[] { + try { + const rows = all(getDb().prepare("SELECT * FROM page_affiliations ORDER BY sort_order, id")); + if (!rows.length) return FALLBACK_AFFILIATIONS; + return uniqueByLocalizedName(rows) + .map((row) => ({ + ...row, + nameText: localized(row.name_en || row.name, row.name_zh), + })) + .filter((row) => hasLocalizedText(row.nameText)); + } catch { + return FALLBACK_AFFILIATIONS; + } +} diff --git a/src/lib/data/participation.ts b/src/lib/data/participation.ts new file mode 100644 index 0000000000000000000000000000000000000000..c510a10f36c19b4441c10deb08c249c6dd037f92 --- /dev/null +++ b/src/lib/data/participation.ts @@ -0,0 +1,9 @@ +import { getDb } from "@/lib/db"; +import { all } from "@/lib/db/helpers"; +import type { ParticipationInfo } from "@/lib/db/schema"; + +export function getParticipationInfo(): ParticipationInfo[] { + return all( + getDb().prepare("SELECT * FROM participation_info ORDER BY sort_order, id") + ); +} diff --git a/src/lib/data/policies.ts b/src/lib/data/policies.ts new file mode 100644 index 0000000000000000000000000000000000000000..cffe0466e3e7b7ea76ad146ff4d7743a4b414843 --- /dev/null +++ b/src/lib/data/policies.ts @@ -0,0 +1,14 @@ +import { getDb } from "@/lib/db"; +import { all } from "@/lib/db/helpers"; +import type { PolicyItem } from "@/lib/db/schema"; +import { hasLocalizedText, localized } from "@/lib/i18n"; + +export function getPolicies(): PolicyItem[] { + return all(getDb().prepare("SELECT * FROM policy_items ORDER BY sort_order, id")) + .map((row) => ({ + ...row, + titleText: localized(row.title_en || row.title, row.title_zh), + bodyText: localized(row.body_en || row.body, row.body_zh), + })) + .filter((row) => hasLocalizedText(row.titleText) || hasLocalizedText(row.bodyText)); +} diff --git a/src/lib/data/research.ts b/src/lib/data/research.ts new file mode 100644 index 0000000000000000000000000000000000000000..8248a545dd9dae3bbb6d2db4e0639c9bbb5b4af0 --- /dev/null +++ b/src/lib/data/research.ts @@ -0,0 +1,28 @@ +import { getDb } from "@/lib/db"; +import { all } from "@/lib/db/helpers"; +import type { ResearchSection, AcademicReference } from "@/lib/db/schema"; +import { hasLocalizedText, localized } from "@/lib/i18n"; + +export function getResearchSections(): ResearchSection[] { + const rows = all( + getDb().prepare("SELECT * FROM research_sections ORDER BY sort_order, id") + ); + for (const row of rows) { + if (row.tags_json) { try { (row as any).tags = JSON.parse(row.tags_json); } catch { (row as any).tags = []; } } + } + return rows; +} + +export function getAcademicReferences(): AcademicReference[] { + const rows = all( + getDb().prepare("SELECT * FROM academic_references ORDER BY sort_order, id") + ); + for (const row of rows) { + if (row.tags_json) { try { (row as any).tags = JSON.parse(row.tags_json); } catch { (row as any).tags = []; } } + row.titleText = localized(row.title_en || row.title, row.title_zh); + row.bodyText = localized(row.body_en || row.body, row.body_zh); + } + return rows.filter( + (row) => hasLocalizedText(row.titleText) || hasLocalizedText(row.bodyText) + ); +} diff --git a/src/lib/data/site-info.ts b/src/lib/data/site-info.ts new file mode 100644 index 0000000000000000000000000000000000000000..a640b32ac37b568487ed3a03f31aa0b59a2f2795 --- /dev/null +++ b/src/lib/data/site-info.ts @@ -0,0 +1,15 @@ +import { getDb } from "@/lib/db"; +import { get as dbGet } from "@/lib/db/helpers"; +import type { SiteInfo, HeroContent } from "@/lib/db/schema"; + +export function getSiteInfo(): SiteInfo | null { + return dbGet(getDb().prepare("SELECT * FROM site_info WHERE id = 1")); +} + +export function getHeroContent(): HeroContent | null { + return dbGet(getDb().prepare("SELECT * FROM hero_content ORDER BY id LIMIT 1")); +} + +export function getSiteAndHero(): { site: SiteInfo | null; hero: HeroContent | null } { + return { site: getSiteInfo(), hero: getHeroContent() }; +} diff --git a/src/lib/data/submission-guide.ts b/src/lib/data/submission-guide.ts new file mode 100644 index 0000000000000000000000000000000000000000..82035830d826e32134abc474526759f4bb98cf6c --- /dev/null +++ b/src/lib/data/submission-guide.ts @@ -0,0 +1,132 @@ +import { getDb } from "@/lib/db"; +import { all, get } from "@/lib/db/helpers"; +import { contentValue, hasLocalizedText, localized, type LocalizedText } from "@/lib/i18n"; + +export interface SubmissionGuideMeta { + eyebrowText: LocalizedText; + titleText: LocalizedText; + introText: LocalizedText; + backLabelText: LocalizedText; + backHref: string; +} + +export interface SubmissionGuideNavItem { + id: number; + itemKey: string; + labelText: LocalizedText; + href: string; +} + +export interface SubmissionGuideSection { + id: number; + sectionKey: string; + titleText: LocalizedText; + bodyText: LocalizedText; +} + +export interface HomepageEntrySection { + id: number; + sectionKey: string; + titleText: LocalizedText; + bodyText: LocalizedText; + actionLabelText: LocalizedText; + actionHref: string; +} + +interface MetaRow { + eyebrow_en: string; + eyebrow_zh: string; + title_en: string; + title_zh: string; + intro_en: string; + intro_zh: string; + back_label_en: string; + back_label_zh: string; + back_href: string; +} + +interface NavRow { + id: number; + item_key: string; + label_en: string; + label_zh: string; + href: string; +} + +interface SectionRow { + id: number; + section_key: string; + title_en: string; + title_zh: string; + body_en: string; + body_zh: string; +} + +interface EntryRow extends SectionRow { + action_label_en: string; + action_label_zh: string; + action_href: string; +} + +export function getSubmissionGuideMeta(): SubmissionGuideMeta | null { + const row = get(getDb().prepare("SELECT * FROM triworld_submission_guide_meta WHERE id = 1")); + if (!row) return null; + return { + eyebrowText: localized(row.eyebrow_en, row.eyebrow_zh), + titleText: localized(row.title_en, row.title_zh), + introText: localized(row.intro_en, row.intro_zh), + backLabelText: localized(row.back_label_en, row.back_label_zh), + backHref: contentValue(row.back_href) || "/", + }; +} + +export function getSubmissionGuideNavItems(): SubmissionGuideNavItem[] { + return all( + getDb().prepare( + "SELECT * FROM triworld_submission_guide_nav_items WHERE is_visible = 1 ORDER BY sort_order, id" + ) + ) + .map((row) => ({ + id: row.id, + itemKey: row.item_key, + labelText: localized(row.label_en, row.label_zh), + href: contentValue(row.href), + })) + .filter((row) => hasLocalizedText(row.labelText) && Boolean(row.href)); +} + +export function getSubmissionGuideSections(): SubmissionGuideSection[] { + return all( + getDb().prepare( + "SELECT * FROM triworld_submission_guide_sections WHERE is_visible = 1 ORDER BY sort_order, id" + ) + ) + .map((row) => ({ + id: row.id, + sectionKey: row.section_key, + titleText: localized(row.title_en, row.title_zh), + bodyText: localized(row.body_en, row.body_zh), + })) + .filter((row) => hasLocalizedText(row.titleText) || hasLocalizedText(row.bodyText)); +} + +export function getHomepageEntrySections(): HomepageEntrySection[] { + return all( + getDb().prepare( + "SELECT * FROM triworld_entry_sections WHERE is_visible = 1 ORDER BY sort_order, id" + ) + ) + .map((row) => ({ + id: row.id, + sectionKey: row.section_key, + titleText: localized(row.title_en, row.title_zh), + bodyText: localized(row.body_en, row.body_zh), + actionLabelText: localized(row.action_label_en, row.action_label_zh), + actionHref: contentValue(row.action_href), + })) + .filter((row) => + hasLocalizedText(row.titleText) || + hasLocalizedText(row.bodyText) || + (hasLocalizedText(row.actionLabelText) && Boolean(row.actionHref)) + ); +} diff --git a/src/lib/data/triworld-advantages.ts b/src/lib/data/triworld-advantages.ts new file mode 100644 index 0000000000000000000000000000000000000000..f73f5f1c5ecfd76e4b761630b767377c9a937eb0 --- /dev/null +++ b/src/lib/data/triworld-advantages.ts @@ -0,0 +1,51 @@ +import { getDb } from "@/lib/db"; +import { all } from "@/lib/db/helpers"; +import { contentValue, hasLocalizedText, localized, type LocalizedText } from "@/lib/i18n"; + +export interface TriWorldAdvantage { + id: number; + titleText: LocalizedText; + bodyText: LocalizedText; + them: string; + themNoteText: LocalizedText; + us: string; + usNoteText: LocalizedText; +} + +interface TriWorldAdvantageRow { + id: number; + title_en: string; + title_zh: string; + body_en: string; + body_zh: string; + them: string; + them_note_en: string; + them_note_zh: string; + us: string; + us_note_en: string; + us_note_zh: string; +} + +export function getTriWorldAdvantages(): TriWorldAdvantage[] { + const rows = all( + getDb().prepare("SELECT * FROM triworld_advantages ORDER BY sort_order, id") + ); + return rows + .map((row) => ({ + id: row.id, + titleText: localized(row.title_en, row.title_zh), + bodyText: localized(row.body_en, row.body_zh), + them: contentValue(row.them), + themNoteText: localized(row.them_note_en, row.them_note_zh), + us: contentValue(row.us), + usNoteText: localized(row.us_note_en, row.us_note_zh), + })) + .filter((item) => + hasLocalizedText(item.titleText) || + hasLocalizedText(item.bodyText) || + Boolean(item.them) || + Boolean(item.us) || + hasLocalizedText(item.themNoteText) || + hasLocalizedText(item.usNoteText) + ); +} diff --git a/src/lib/data/triworld-citation.ts b/src/lib/data/triworld-citation.ts new file mode 100644 index 0000000000000000000000000000000000000000..978453763386a7dd1b8da112548fc65cd3efb839 --- /dev/null +++ b/src/lib/data/triworld-citation.ts @@ -0,0 +1,34 @@ +import { getDb } from "@/lib/db"; +import { get } from "@/lib/db/helpers"; +import type { TriWorldCitation } from "@/lib/db/schema"; +import { contentValue } from "@/lib/i18n"; + +const FALLBACK_CITATION: TriWorldCitation = { + id: 1, + lead_en: "If you use TriWorldBench in your research, please cite the benchmark:", + lead_zh: "如果 TriWorldBench 对您的研究有所帮助,请引用本基准:", + bibtex: `@misc{triworldbench2026, + title = {TriWorldBench: Multi-View World Model Video Evaluation}, + author = {TriWorldBench Contributors}, + year = {2026}, + note = {Benchmark website} +}`, + updated_at: "", +}; + +export function getTriWorldCitation(): TriWorldCitation { + try { + const citation = ( + get(getDb().prepare("SELECT * FROM triworld_citation WHERE id = 1")) || + FALLBACK_CITATION + ); + return { + ...citation, + lead_en: contentValue(citation.lead_en), + lead_zh: contentValue(citation.lead_zh), + bibtex: contentValue(citation.bibtex), + }; + } catch { + return FALLBACK_CITATION; + } +} diff --git a/src/lib/data/triworld-content.ts b/src/lib/data/triworld-content.ts new file mode 100644 index 0000000000000000000000000000000000000000..3d71f5de6165dd17668b5a7d863e3900c1487bfe --- /dev/null +++ b/src/lib/data/triworld-content.ts @@ -0,0 +1,201 @@ +import { getDb } from "@/lib/db"; +import { all } from "@/lib/db/helpers"; +import { contentValue, hasLocalizedText, localized, type LocalizedText } from "@/lib/i18n"; + +export interface TriWorldContentSection { + id: number; + sectionKey: string; + titleText: LocalizedText; + bodyText: LocalizedText; + secondaryBodyText: LocalizedText; + imagePath: string | null; + imageAltText: LocalizedText; + captionText: LocalizedText; +} + +export interface TriWorldConsistencyNode { + id: number; + nodeKey: string; + nodeType: "input" | "check" | "protocol" | "output"; + titleText: LocalizedText; + bodyText: LocalizedText; +} + +export interface TriWorldMetricRouting { + id: number; + blockText: LocalizedText; + metricsText: LocalizedText; + inputsText: LocalizedText; + outputText: LocalizedText; +} + +export interface TriWorldMetricDefinitionItem { + id: number; + itemKey: string; + titleText: LocalizedText; + bodyText: LocalizedText; +} + +export interface TriWorldMetricDefinitionGroup { + id: number; + groupKey: string; + titleText: LocalizedText; + summaryText: LocalizedText; + items: TriWorldMetricDefinitionItem[]; +} + +interface ContentSectionRow { + id: number; + section_key: string; + title_en: string; + title_zh: string; + body_en: string; + body_zh: string; + secondary_body_en: string | null; + secondary_body_zh: string | null; + image_path: string | null; + image_alt_en: string | null; + image_alt_zh: string | null; + caption_en: string | null; + caption_zh: string | null; +} + +interface ConsistencyNodeRow { + id: number; + node_key: string; + node_type: TriWorldConsistencyNode["nodeType"]; + title_en: string; + title_zh: string; + body_en: string; + body_zh: string; +} + +interface MetricRoutingRow { + id: number; + block_en: string; + block_zh: string; + metrics_en: string; + metrics_zh: string; + inputs_en: string; + inputs_zh: string; + output_en: string; + output_zh: string; +} + +interface MetricDefinitionGroupRow { + id: number; + group_key: string; + title_en: string; + title_zh: string; + summary_en: string; + summary_zh: string; +} + +interface MetricDefinitionItemRow { + id: number; + group_id: number; + item_key: string; + title_en: string; + title_zh: string; + body_en: string; + body_zh: string; +} + +export function getTriWorldContentSections(): TriWorldContentSection[] { + const rows = all( + getDb().prepare("SELECT * FROM triworld_content_sections ORDER BY sort_order, id") + ); + return rows + .map((row) => ({ + id: row.id, + sectionKey: row.section_key, + titleText: localized(row.title_en, row.title_zh), + bodyText: localized(row.body_en, row.body_zh), + secondaryBodyText: localized(row.secondary_body_en || "", row.secondary_body_zh || ""), + imagePath: contentValue(row.image_path) || null, + imageAltText: localized(row.image_alt_en || row.title_en, row.image_alt_zh || row.title_zh), + captionText: localized(row.caption_en || "", row.caption_zh || ""), + })) + .filter((section) => + hasLocalizedText(section.titleText) || + hasLocalizedText(section.bodyText) || + hasLocalizedText(section.secondaryBodyText) || + Boolean(section.imagePath) + ); +} + +export function getTriWorldConsistencyNodes(): TriWorldConsistencyNode[] { + const rows = all( + getDb().prepare("SELECT * FROM triworld_consistency_nodes ORDER BY sort_order, id") + ); + return rows + .map((row) => ({ + id: row.id, + nodeKey: row.node_key, + nodeType: row.node_type, + titleText: localized(row.title_en, row.title_zh), + bodyText: localized(row.body_en, row.body_zh), + })) + .filter((node) => hasLocalizedText(node.titleText) || hasLocalizedText(node.bodyText)); +} + +export function getTriWorldMetricRouting(): TriWorldMetricRouting[] { + const rows = all( + getDb().prepare("SELECT * FROM triworld_metric_routing ORDER BY sort_order, id") + ); + return rows + .map((row) => ({ + id: row.id, + blockText: localized(row.block_en, row.block_zh), + metricsText: localized(row.metrics_en, row.metrics_zh), + inputsText: localized(row.inputs_en, row.inputs_zh), + outputText: localized(row.output_en, row.output_zh), + })) + .filter((row) => + hasLocalizedText(row.blockText) || + hasLocalizedText(row.metricsText) || + hasLocalizedText(row.inputsText) || + hasLocalizedText(row.outputText) + ); +} + +export function getTriWorldMetricDefinitionGroups(): TriWorldMetricDefinitionGroup[] { + try { + const database = getDb(); + const groups = all( + database.prepare("SELECT * FROM triworld_metric_definition_groups ORDER BY sort_order, id") + ); + const items = all( + database.prepare("SELECT * FROM triworld_metric_definition_items ORDER BY sort_order, id") + ); + const itemsByGroup = new Map(); + for (const item of items) { + const groupItems = itemsByGroup.get(item.group_id) || []; + const mappedItem = { + id: item.id, + itemKey: item.item_key, + titleText: localized(item.title_en, item.title_zh), + bodyText: localized(item.body_en, item.body_zh), + }; + if (hasLocalizedText(mappedItem.titleText) || hasLocalizedText(mappedItem.bodyText)) { + groupItems.push(mappedItem); + } + itemsByGroup.set(item.group_id, groupItems); + } + return groups + .map((group) => ({ + id: group.id, + groupKey: group.group_key, + titleText: localized(group.title_en, group.title_zh), + summaryText: localized(group.summary_en, group.summary_zh), + items: itemsByGroup.get(group.id) || [], + })) + .filter((group) => + hasLocalizedText(group.titleText) || + hasLocalizedText(group.summaryText) || + group.items.length > 0 + ); + } catch { + return []; + } +} diff --git a/src/lib/data/triworld-hero-actions.ts b/src/lib/data/triworld-hero-actions.ts new file mode 100644 index 0000000000000000000000000000000000000000..5364c66b8cd3157a7892f79904aef7645003e779 --- /dev/null +++ b/src/lib/data/triworld-hero-actions.ts @@ -0,0 +1,47 @@ +import { getDb } from "@/lib/db"; +import { all } from "@/lib/db/helpers"; +import { contentValue, hasLocalizedText, localized, type LocalizedText } from "@/lib/i18n"; + +export interface TriWorldHeroAction { + id: number; + actionKey: string; + labelText: LocalizedText; + href: string; + openInNewTab: boolean; +} + +interface HeroActionRow { + id: number; + action_key: string; + label_en: string; + label_zh: string; + href: string; + open_in_new_tab: number; +} + +const FALLBACK_ACTIONS: TriWorldHeroAction[] = [ + { id: 1, actionKey: "submission", labelText: localized("Submission", "提交"), href: "/submission", openInNewTab: false }, + { id: 2, actionKey: "contact_us", labelText: localized("Contact Us", "联系我们"), href: "#contact", openInNewTab: false }, + { id: 3, actionKey: "github", labelText: localized("GitHub", "GitHub"), href: "https://github.com", openInNewTab: true }, + { id: 4, actionKey: "paper", labelText: localized("Paper", "论文"), href: "#citation", openInNewTab: false }, +]; + +export function getTriWorldHeroActions(): TriWorldHeroAction[] { + try { + const rows = all( + getDb().prepare("SELECT * FROM triworld_hero_actions ORDER BY sort_order, id") + ); + if (!rows.length) return FALLBACK_ACTIONS; + return rows + .map((row) => ({ + id: row.id, + actionKey: row.action_key, + labelText: localized(row.label_en, row.label_zh), + href: contentValue(row.href), + openInNewTab: Number(row.open_in_new_tab) > 0, + })) + .filter((action) => hasLocalizedText(action.labelText) && Boolean(action.href)); + } catch { + return FALLBACK_ACTIONS; + } +} diff --git a/src/lib/data/triworld-nav-items.ts b/src/lib/data/triworld-nav-items.ts new file mode 100644 index 0000000000000000000000000000000000000000..5ccd16077f9e3873984dd844ee5e23205ebafd71 --- /dev/null +++ b/src/lib/data/triworld-nav-items.ts @@ -0,0 +1,63 @@ +import { getDb } from "@/lib/db"; +import { all } from "@/lib/db/helpers"; +import { contentValue, hasLocalizedText, localized, type LocalizedText } from "@/lib/i18n"; + +export interface TriWorldNavItem { + id: number; + itemKey: string; + labelText: LocalizedText; + href: string; + openInNewTab: boolean; +} + +interface NavItemRow { + id: number; + item_key: string; + label_en: string; + label_zh: string; + href: string; + open_in_new_tab: number; + is_visible: number; +} + +const FALLBACK_NAV_ITEMS: TriWorldNavItem[] = ([ + ["abstract", "Abstract", "摘要", "#abstract"], + ["overview", "Overview", "概览", "#overview"], + ["advantages", "Advantages", "优势", "#advantages"], + ["cases", "Cases", "案例", "#cases"], + ["metrics", "Metrics", "指标", "#metrics"], + ["leaderboard", "Leaderboard", "榜单", "#leaderboard"], + ["visualization", "Visualization", "可视化", "#visualization"], + ["datasets", "Datasets", "数据集", "#datasets"], + ["policies", "Policy&Rules", "政策与规则", "#policies"], + ["submission", "Submission", "提交", "#submission"], + ["contact", "Contact Us", "联系我们", "#contact"], +] as const).map(([itemKey, labelEn, labelZh, href], index) => ({ + id: index + 1, + itemKey, + labelText: localized(labelEn, labelZh), + href, + openInNewTab: false, +})); + +export function getTriWorldNavItems(): TriWorldNavItem[] { + try { + const rows = all( + getDb().prepare("SELECT * FROM triworld_nav_items ORDER BY sort_order, id") + ); + if (!rows.length) return FALLBACK_NAV_ITEMS; + return rows + .map((row) => ({ + id: row.id, + itemKey: row.item_key, + labelText: localized(row.label_en, row.label_zh), + href: contentValue(row.href), + openInNewTab: Number(row.open_in_new_tab) > 0, + isVisible: Number(row.is_visible) > 0, + })) + .filter((item) => item.isVisible && hasLocalizedText(item.labelText) && Boolean(item.href)) + .map(({ isVisible: _isVisible, ...item }) => item); + } catch { + return FALLBACK_NAV_ITEMS; + } +} diff --git a/src/lib/data/triworld-visual-metrics.ts b/src/lib/data/triworld-visual-metrics.ts new file mode 100644 index 0000000000000000000000000000000000000000..bde80afe19b4766c51bd6b773d068a08a739c046 --- /dev/null +++ b/src/lib/data/triworld-visual-metrics.ts @@ -0,0 +1,36 @@ +import { getDb } from "@/lib/db"; +import { all } from "@/lib/db/helpers"; +import type { TriWorldVisualMetric } from "@/lib/db/schema"; + +export function getTriWorldVisualMetrics(): TriWorldVisualMetric[] { + try { + const rows = all( + getDb().prepare("SELECT * FROM triworld_visual_metrics ORDER BY sort_order, id") + ); + return rows.length ? rows : fallbackVisualMetrics(); + } catch { + return fallbackVisualMetrics(); + } +} + +function fallbackVisualMetrics(): TriWorldVisualMetric[] { + const rows = [ + ["__overall__", "TWB-Score", "TWB 总分", "Overall TWB-Score Ranking", "TWB 总分排名"], + ["tri_view_consistency", "Tri-View", "三视角", "Tri-View Consistency Ranking", "三视角一致性排名"], + ["task_alignment", "Task", "任务", "Task Alignment Ranking", "任务对齐排名"], + ["physical_3d_coherence", "Physical 3D", "物理三维", "Physical and 3D Coherence Ranking", "物理与三维一致性排名"], + ["motion_quality", "Motion", "运动", "Motion Quality Ranking", "运动质量排名"], + ["temporal_consistency", "Temporal", "时间", "Temporal Consistency Ranking", "时间一致性排名"], + ["visual_quality", "Visual", "视觉", "Visual Quality Ranking", "视觉质量排名"], + ] as const; + return rows.map(([metric_code, label_en, label_zh, title_en, title_zh], index) => ({ + id: index + 1, + metric_code, + label_en, + label_zh, + title_en, + title_zh, + sort_order: index, + updated_at: "", + })); +} diff --git a/src/lib/data/venue.ts b/src/lib/data/venue.ts new file mode 100644 index 0000000000000000000000000000000000000000..685de7291a6b96cc40d586a7c5a3e341f5d0457b --- /dev/null +++ b/src/lib/data/venue.ts @@ -0,0 +1,7 @@ +import { getDb } from "@/lib/db"; +import { get as dbGet } from "@/lib/db/helpers"; +import type { VenueHostInfo } from "@/lib/db/schema"; + +export function getVenueHost(): VenueHostInfo | null { + return dbGet(getDb().prepare("SELECT * FROM venue_host_info ORDER BY id LIMIT 1")); +} diff --git a/src/lib/db/helpers.ts b/src/lib/db/helpers.ts new file mode 100644 index 0000000000000000000000000000000000000000..17826716666e5cd55ff1f93b32be8031c95cf130 --- /dev/null +++ b/src/lib/db/helpers.ts @@ -0,0 +1,20 @@ +/** + * Type-safe helpers for node:sqlite queries. + * node:sqlite returns Record[], so we need + * double-casting through unknown for TypeScript compatibility. + */ + +// eslint-disable-next-line @typescript-eslint/no-explicit-any +export function all(stmt: { all(...params: any[]): unknown[] }, ...params: unknown[]): T[] { + return stmt.all(...params) as unknown as T[]; +} + +// eslint-disable-next-line @typescript-eslint/no-explicit-any +export function get(stmt: { get(...params: any[]): unknown }, ...params: unknown[]): T | null { + return (stmt.get(...params) as T) ?? null; +} + +// eslint-disable-next-line @typescript-eslint/no-explicit-any +export function run(stmt: { run(...params: any[]): unknown }, ...params: unknown[]): { lastInsertRowid: number | bigint; changes: number } { + return stmt.run(...params) as unknown as { lastInsertRowid: number | bigint; changes: number }; +} diff --git a/src/lib/db/index.ts b/src/lib/db/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..133c7fe52440f9f33f0d8f4ba97669f8b1838f3d --- /dev/null +++ b/src/lib/db/index.ts @@ -0,0 +1,38 @@ +import { DatabaseSync } from "node:sqlite"; +import fs from "fs"; +import path from "path"; + +function defaultDbPath(): string { + const candidates = [ + path.resolve(process.cwd(), "..", "..", "database", "database.sqlite"), + path.resolve(process.cwd(), "database", "database.sqlite"), + ]; + return candidates.find((candidate) => fs.existsSync(candidate)) || candidates[0]; +} + +const DB_PATH = process.env.TRIWORLDBENCH_DB_PATH || defaultDbPath(); +const READ_ONLY_DB = true; + +let db: DatabaseSync | null = null; + +export function getDb(): DatabaseSync { + if (!db) { + if (!fs.existsSync(DB_PATH)) { + throw new Error("TriWorldBench database was not found at " + DB_PATH); + } + + db = new DatabaseSync(DB_PATH, { readOnly: true }); + db.exec("PRAGMA busy_timeout = 5000"); + db.exec("PRAGMA foreign_keys = ON"); + } + return db; +} + +export function closeDb(): void { + if (db) { + db.close(); + db = null; + } +} + +export { DB_PATH, READ_ONLY_DB }; diff --git a/src/lib/db/schema.ts b/src/lib/db/schema.ts new file mode 100644 index 0000000000000000000000000000000000000000..732668511b3c18430b1276c105f3d3e8e3bc37df --- /dev/null +++ b/src/lib/db/schema.ts @@ -0,0 +1,461 @@ +// ============================================================ +// TypeScript interfaces for all 26 database tables +// Mirrors database/schema.sql +// ============================================================ + +// --- Singleton / meta tables --- + +export interface DataVersion { + id: number; + version: number; + updated_at: string; +} + +export interface SiteInfo { + id: number; + title: string; + short_name: string; + tagline: string; + description: string; + contact_email: string | null; + github_url: string | null; + updated_at: string; +} + +// --- Content tables --- + +export interface HeroContent { + id: number; + eyebrow: string | null; + title: string; + subtitle: string; + primary_cta_label: string | null; + primary_cta_url: string | null; + secondary_cta_label: string | null; + secondary_cta_url: string | null; + updated_at: string; +} + +export interface OverviewContent { + id: number; + title: string; + body: string; + stat_json: string | null; + stats?: string[]; // parsed from stat_json + updated_at: string; +} + +export interface EvaluationSection { + id: number; + title: string; + body: string; + category: string | null; + sort_order: number; + updated_at: string; +} + +export interface ResearchSection { + id: number; + title: string; + body: string; + tags_json: string | null; + tags?: string[]; // parsed from tags_json + sort_order: number; + updated_at: string; +} + +export interface ParticipationInfo { + id: number; + title: string; + body: string; + sort_order: number; + updated_at: string; +} + +export interface VenueHostInfo { + id: number; + host_name: string; + venue_name: string | null; + location: string | null; + body: string; + updated_at: string; +} + +export interface PolicyItem { + id: number; + title: string; + title_en?: string | null; + title_zh?: string | null; + body: string; + body_en?: string | null; + body_zh?: string | null; + sort_order: number; + updated_at: string; + titleText?: { en: string; zh: string }; + bodyText?: { en: string; zh: string }; +} + +export interface ContactInfo { + id: number; + label: string; + label_en?: string | null; + label_zh?: string | null; + value: string; + href: string | null; + image_path?: string | null; + description_en?: string | null; + description_zh?: string | null; + sort_order: number; + updated_at: string; + labelText?: { en: string; zh: string }; + descriptionText?: { en: string; zh: string }; +} + +export interface OtherInformation { + id: number; + title: string; + body: string; + status: string; + updated_at: string; +} + +export interface ImportantDate { + id: number; + phase: string; + title: string; + title_en?: string | null; + title_zh?: string | null; + body: string; + body_en?: string | null; + body_zh?: string | null; + starts_at: string; + date_label_en?: string | null; + date_label_zh?: string | null; + ends_at: string | null; + cta_label: string | null; + cta_label_en?: string | null; + cta_label_zh?: string | null; + cta_url: string | null; + sort_order: number; + updated_at: string; + // Computed + status?: "upcoming" | "live" | "closed"; + titleText?: { en: string; zh: string }; + dateLabelText?: { en: string; zh: string }; + bodyText?: { en: string; zh: string }; + ctaLabelText?: { en: string; zh: string }; +} + +export interface Dataset { + id: number; + slug: string; + name: string; + description: string; + task_count: number | null; + modality: string | null; + status: string; + updated_at: string; + // Joined from dataset_versions (latest) + version_label?: string; + release_date?: string; + download_url?: string; + checksum?: string; + version_notes?: string; +} + +export interface DatasetVersion { + id: number; + dataset_id: number; + version_label: string; + release_date: string | null; + download_url: string | null; + checksum: string | null; + notes: string | null; + is_latest: number; + created_at: string; +} + +export interface UploadRequirement { + id: number; + title: string; + title_en?: string | null; + title_zh?: string | null; + body: string; + body_en?: string | null; + body_zh?: string | null; + required: number; + sort_order: number; + updated_at: string; + titleText?: { en: string; zh: string }; + bodyText?: { en: string; zh: string }; +} + +export interface SubmissionFileType { + id: number; + code: string; + label: string; + label_en?: string | null; + label_zh?: string | null; + description: string | null; + description_en?: string | null; + description_zh?: string | null; + accepted_extensions: string | null; + required: number; + updated_at: string; + labelText?: { en: string; zh: string }; + descriptionText?: { en: string; zh: string }; +} + +export interface Announcement { + id: number; + title: string; + body: string; + severity: string; + published_at: string; + updated_at: string; +} + +export interface AcademicReference { + id: number; + title: string; + title_en?: string | null; + title_zh?: string | null; + body: string; + body_en?: string | null; + body_zh?: string | null; + url: string | null; + tags_json: string | null; + tags?: string[]; + sort_order: number; + updated_at: string; + titleText?: { en: string; zh: string }; + bodyText?: { en: string; zh: string }; +} + +export interface MetricExplanation { + id: number; + metric_code: string; + short_label: string; + explanation: string; + updated_at: string; +} + +// --- Competition tables --- + +export interface Team { + id: number; + slug: string; + name: string; + participant_email: string; + affiliation: string | null; + country_region: string | null; + strengths: string | null; + status: string; + created_at: string; + updated_at: string; +} + +export interface Model { + id: number; + team_id: number; + slug: string; + name: string; + model_card_url: string | null; + brief_introduction?: string | null; + created_at: string; + updated_at: string; +} + +export interface Submission { + id: number; + model_id: number; + version_label: string; + submitted_at: string; + status: string; + dataset_split: string | null; + artifact_uri: string | null; + notes: string | null; + created_at: string; + updated_at: string; +} + +export interface Metric { + id: number; + code: string; + display_name: string; + display_name_en?: string | null; + display_name_zh?: string | null; + short_label_en?: string | null; + short_label_zh?: string | null; + category: string; + direction: string; + unit: string | null; + description: string | null; + description_en?: string | null; + description_zh?: string | null; + sort_order: number; + updated_at: string; + displayNameText?: { en: string; zh: string }; + shortLabelText?: { en: string; zh: string }; + descriptionText?: { en: string; zh: string }; +} + +export interface ScoreRecord { + id: number; + submission_id: number; + metric_id: number; + raw_value: number | null; + normalized_value: number | null; + percentile: number | null; + evaluation_version: string; + source_note: string | null; + recorded_at: string; +} + +export interface LeaderboardSnapshot { + id: number; + label: string; + snapshot_time: string; + status: string; + ranking_policy: string; + notes: string | null; + is_latest: number; + created_at: string; +} + +export interface LeaderboardSnapshotEntry { + id: number; + snapshot_id: number; + rank: number; + submission_id: number; + score_record_id: number; + status_label: string | null; + updated_label: string | null; +} + +// --- Composite / API response types --- + +export interface MetricScore { + code: string; + displayName: string; + displayNameText?: { en: string; zh: string }; + shortLabelText?: { en: string; zh: string }; + category: string; + rawValue: number | null; + normalizedValue: number | null; + percentile: number | null; + recordedAt: string; +} + +export interface LeaderboardEntry { + rank: number; + statusLabel: string | null; + updatedLabel: string | null; + team: { + id: number; + slug: string; + name: string; + affiliation: string | null; + strengths: string | null; + }; + model: { + id: number; + slug: string; + name: string; + }; + submission: { + id: number; + versionLabel: string; + status: string; + datasetSplit: string | null; + submittedAt: string; + }; + score: { + rawValue: number | null; + normalizedValue: number | null; + percentile: number | null; + }; + metrics: Record; +} + +export interface RadarEntry { + rank: number; + model: { name: string; slug: string }; + team: { name: string }; + score: { percentile: number | null }; + axes: Array<{ code: string; label: string; value: number | null }>; +} + +export interface PageAuthor { + id: number; + name: string; + name_en: string | null; + name_zh: string | null; + url: string | null; + affiliation_refs: string | null; + sort_order: number; + updated_at: string; + nameText?: { en: string; zh: string }; +} + +export interface PageAffiliation { + id: number; + ref: string; + name: string; + name_en: string | null; + name_zh: string | null; + logo_path?: string | null; + website_url?: string | null; + sort_order: number; + updated_at: string; + nameText?: { en: string; zh: string }; +} + +export interface TriWorldCitation { + id: number; + lead_en: string; + lead_zh: string; + bibtex: string; + updated_at: string; +} + +export interface TriWorldVisualMetric { + id: number; + metric_code: string; + label_en: string; + label_zh: string; + title_en: string; + title_zh: string; + sort_order: number; + updated_at: string; +} + +// Site section text (database-driven unique section content) +export interface SiteSectionText { + id: number; + site_id: string; + section_key: string; + title: string; + description: string; + items_json: string; + updated_at: string; +} + +// Legacy — keep for backward compatibility with existing API routes +export interface SiteSection { + id: number; + site_id: string; + section_key: string; + section_data_json: string; + updated_at: string; +} + +// Parsed site section (items_json already parsed) +export interface ParsedSiteSection { + id: number; + siteId: string; + sectionKey: string; + title: string; + description: string; + items: Record[]; +} diff --git a/src/lib/i18n.ts b/src/lib/i18n.ts new file mode 100644 index 0000000000000000000000000000000000000000..d655dafd8ba986dea7cb0527be1f17d0cabf1bcc --- /dev/null +++ b/src/lib/i18n.ts @@ -0,0 +1,33 @@ +export type Language = "en" | "zh"; + +export interface LocalizedText { + en: string; + zh: string; +} + +export const EMPTY_CONTENT_MARKER = "#empty#"; + +export function isEmptyContentMarker(value: string | null | undefined): boolean { + if (typeof value !== "string") return false; + const normalized = value.trim().toLowerCase(); + return normalized === EMPTY_CONTENT_MARKER || /^#empty#[。..!!??,,;;::、…]*$/i.test(normalized); +} + +export function contentValue(value: string | null | undefined): string { + if (!value || isEmptyContentMarker(value) || !value.trim()) return ""; + return value; +} + +export function hasLocalizedText(text: LocalizedText | null | undefined): boolean { + return Boolean(contentValue(text?.en) || contentValue(text?.zh)); +} + +export function localized(en: string | null | undefined, zh?: string | null): LocalizedText { + const english = contentValue(en); + const chineseIsEmptyMarker = isEmptyContentMarker(zh); + const chinese = contentValue(zh); + return { + en: english, + zh: chinese || (chineseIsEmptyMarker ? "" : english), + }; +} diff --git a/src/lib/utils.ts b/src/lib/utils.ts new file mode 100644 index 0000000000000000000000000000000000000000..ee386f47bb45aa7d9e8c3d0ac9e9e49126af1a5c --- /dev/null +++ b/src/lib/utils.ts @@ -0,0 +1,44 @@ +/** Parse a JSON string field on a row object, replacing the _json suffix key */ +export function parseJsonField( + row: Record | null, + field: string +): Record | null { + if (!row || !row[field]) return row; + try { + const cleanKey = field.replace(/_json$/, ""); + (row as Record)[cleanKey] = JSON.parse( + row[field] as string + ); + delete row[field]; + } catch { + (row as Record)[field.replace(/_json$/, "")] = []; + delete row[field]; + } + return row; +} + +/** Determine if a date range is upcoming, live, or closed */ +export function getDateStatus( + startsAt: string, + endsAt?: string | null +): "upcoming" | "live" | "closed" { + const now = new Date(); + const start = new Date(startsAt); + const end = endsAt ? new Date(endsAt) : start; + if (now < start) return "upcoming"; + if (now >= start && now <= end) return "live"; + return "closed"; +} + +/** Slugify a string: lowercase, replace non-alphanumeric with dashes */ +export function slugify(value: string): string { + return String(value) + .toLowerCase() + .replace(/[^a-z0-9]+/g, "-") + .replace(/^-|-$/g, ""); +} + +/** Clamp a number between min and max */ +export function clamp(value: number, min = 0, max = 100): number { + return Math.max(min, Math.min(max, Number(value.toFixed(2)))); +} diff --git a/src/styles/triworldbench.css b/src/styles/triworldbench.css new file mode 100644 index 0000000000000000000000000000000000000000..6be25e233004fe1ce972f27da724faa205f3e0a5 --- /dev/null +++ b/src/styles/triworldbench.css @@ -0,0 +1,5934 @@ +@font-face{font-family:Inter;font-style:normal;font-weight:300;font-display:swap;src:url('/fonts/editorial/Inter-300.ttf') format('truetype')} +@font-face{font-family:Inter;font-style:normal;font-weight:400;font-display:swap;src:url('/fonts/editorial/Inter-400.ttf') format('truetype')} +@font-face{font-family:Inter;font-style:normal;font-weight:500;font-display:swap;src:url('/fonts/editorial/Inter-500.ttf') format('truetype')} +@font-face{font-family:Inter;font-style:normal;font-weight:600;font-display:swap;src:url('/fonts/editorial/Inter-600.ttf') format('truetype')} +@font-face{font-family:Inter;font-style:normal;font-weight:700;font-display:swap;src:url('/fonts/editorial/Inter-700.ttf') format('truetype')} +@font-face{font-family:Inter;font-style:normal;font-weight:800;font-display:swap;src:url('/fonts/editorial/Inter-800.ttf') format('truetype')} +@font-face{font-family:'JetBrains Mono';font-style:normal;font-weight:400;font-display:swap;src:url('/fonts/editorial/JetBrainsMono-400.ttf') format('truetype')} +@font-face{font-family:'JetBrains Mono';font-style:normal;font-weight:500;font-display:swap;src:url('/fonts/editorial/JetBrainsMono-500.ttf') format('truetype')} +@font-face{font-family:'Source Serif 4';font-style:normal;font-weight:400;font-display:swap;src:url('/fonts/editorial/SourceSerif4-400.ttf') format('truetype')} +@font-face{font-family:'Source Serif 4';font-style:normal;font-weight:600;font-display:swap;src:url('/fonts/editorial/SourceSerif4-600.ttf') format('truetype')} +@font-face{font-family:'Source Serif 4';font-style:normal;font-weight:700;font-display:swap;src:url('/fonts/editorial/SourceSerif4-700.ttf') format('truetype')} +*{box-sizing:border-box}html{scroll-behavior:smooth}body{margin:0;font-family:Inter, Segoe UI, Arial, sans-serif;color:#10201d;background:#eef7f5;line-height:1.6}a{color:inherit;text-decoration:none}.site-nav{position:sticky;top:0;z-index:20;display:flex;justify-content:space-between;align-items:center;gap:24px;padding:18px clamp(18px,4vw,56px);background:#ffffff;border-bottom:1px solid #0f766e;backdrop-filter:blur(18px)}.brand{font-weight:900;letter-spacing:.14em}.site-nav nav{display:flex;flex-wrap:wrap;gap:12px;font-size:.86rem}.site-nav nav a{padding:7px 10px;border-radius:999px}.hero{min-height:72vh;display:grid;grid-template-columns:minmax(0,1.35fr) minmax(280px,.65fr);gap:34px;align-items:center;padding:clamp(46px,8vw,96px) clamp(20px,5vw,78px)}.eyebrow{color:#0f766e;font-weight:800;text-transform:uppercase;letter-spacing:.16em}h1{margin:0;font-size:clamp(3rem,8vw,7rem);line-height:.94;letter-spacing:-.01em}.subtitle{max-width:850px;font-size:clamp(1.05rem,2vw,1.35rem)}.actions{display:flex;gap:14px;flex-wrap:wrap;margin-top:28px}.actions a{padding:13px 18px;border:1px solid #0f766e;background:#0f766e;color:#eef7f5;font-weight:800}.actions a+a{background:transparent;color:#10201d}.hero-panel,.section,.board-window,.feature-grid article,.timeline article{background:#ffffff;border:1px solid #0f766e}.hero-panel{padding:28px;border-radius:28px;box-shadow:0 24px 60px rgba(0,0,0,.12)}.hero-panel span{color:#0f766e;font-weight:900;font-size:2rem;display:block}main{width:min(1180px,calc(100% - 34px));margin:0 auto 70px;display:grid;gap:28px}.section{padding:clamp(24px,4vw,44px);border-radius:24px}.section-head{display:flex;align-items:baseline;gap:14px;margin-bottom:18px}.section-head span{color:#0f766e;font-weight:900}h2{margin:0;font-size:clamp(1.8rem,4vw,3rem);line-height:1}h3{margin:0 0 8px}.stat-strip,.feature-grid,.timeline{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:14px;margin-top:24px}.stat-strip b,.feature-grid article,.timeline article{padding:18px;border-radius:18px}.feature-grid{grid-template-columns:repeat(3,minmax(0,1fr))}.board-window{border-radius:20px;overflow:hidden}.board-top{display:flex;justify-content:space-between;gap:16px;padding:16px 18px;background:#0f766e;color:#eef7f5}table{width:100%;border-collapse:collapse}th,td{padding:14px 16px;border-bottom:1px solid #0f766e;text-align:left}.coming{margin-top:18px;padding:24px;border-radius:18px;background:#0f766e;color:#eef7f5;font-size:1.6rem;font-weight:900;text-align:center}footer{padding:36px;text-align:center;opacity:.72}@media(max-width:820px){.hero{grid-template-columns:1fr}.stat-strip,.feature-grid,.timeline{grid-template-columns:1fr}.site-nav{align-items:flex-start;flex-direction:column}} +body.dashboard{background:radial-gradient(circle at 0 0,#d7fffa,transparent 30%),#eef7f5}.dashboard main{grid-template-columns:repeat(2,minmax(0,1fr))}.dashboard .overview,.dashboard .benchmark{grid-column:1/-1}.dashboard .section{border-radius:12px}@media(max-width:900px){.dashboard main{grid-template-columns:1fr}} + +/* layout-differentiation-pass */ +body h1,.brand,.eyebrow{letter-spacing:0} +.research-extension{position:relative;overflow:hidden} +.research-extension .research-grid{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:14px;margin-top:22px} +.research-extension .research-grid article,.metric-card{padding:16px;border:1px solid currentColor;border-radius:14px;background:rgba(255,255,255,.12)} +.research-extension .paper-tags{display:flex;flex-wrap:wrap;gap:8px;margin-top:18px} +.research-extension .paper-tags span,.metric-card small{display:inline-flex;font-weight:900;font-size:.78rem;text-transform:uppercase} +.metric-panel{margin-top:18px;padding:16px;border:1px solid currentColor;border-radius:18px;background:rgba(255,255,255,.1)} +.metric-panel h3{margin:0 0 12px;font-size:1rem} +.metric-grid{display:grid;grid-template-columns:repeat(5,minmax(130px,1fr));gap:10px} +.metric-card b{display:block;margin:6px 0;font-size:1.02rem} +.metric-card span{display:flex;justify-content:space-between;gap:10px;font-size:.86rem} +@media(max-width:900px){.research-extension .research-grid,.metric-grid{grid-template-columns:1fr}main{display:grid!important;grid-template-columns:1fr!important}.section{grid-column:auto!important;grid-row:auto!important}} + +.layout-dashboard main{width:min(1320px,calc(100% - 24px));grid-template-columns:repeat(12,minmax(0,1fr));grid-auto-flow:dense} +.layout-dashboard .benchmark{grid-column:1/9}.layout-dashboard .evaluation{grid-column:9/13}.layout-dashboard .research-extension{grid-column:1/7}.layout-dashboard .dates{grid-column:7/13}.layout-dashboard .participation{grid-column:1/5}.layout-dashboard .overview{grid-column:5/13}.layout-dashboard .venue,.layout-dashboard .policies{grid-column:span 6}.layout-dashboard .contact{grid-column:1/-1} +.layout-dashboard .section-head{justify-content:space-between}.layout-dashboard .metric-grid{grid-template-columns:repeat(5,minmax(0,1fr))} + +/* distinct-random-block */ +.layout-dashboard .telemetry-queue{grid-column:9/13;grid-row:1;background:#101c1f;color:#d7fffa} +.queue-board{display:grid;grid-template-columns:1fr 1fr;gap:10px} +.queue-board article{padding:14px;border:1px solid #00aa94;background:#14282c} +.queue-board b{display:block;color:#00aa94}.queue-board strong{display:block;font-size:2rem;line-height:1}.queue-board span{font-size:.82rem} + +/* more-distinct-random-blocks */ +.layout-dashboard .phase-monitor{grid-column:1/5}.layout-dashboard .ops-stack{grid-column:5/9} +.phase-bars{display:grid;gap:10px}.phase-bars span{position:relative;padding:10px;background:#d7fffa;color:#102124;font-weight:900}.phase-bars span::after{content:'';position:absolute;left:0;bottom:0;height:5px;width:calc(var(--p)*1%);background:#00aa94} +.ops-stack ul{display:grid;grid-template-columns:1fr 1fr;gap:10px;margin:0;padding:0;list-style:none}.ops-stack li{padding:12px;border:1px solid #00aa94;background:#14282c;color:#d7fffa} + +/* MOXIVERSE leaderboard start */ +.twb-leader { + position: relative; + margin: clamp(34px, 7vw, 86px) auto; + padding: clamp(22px, 4vw, 48px); + overflow: hidden; + isolation: isolate; + max-width: min(1180px, 100%); + box-sizing: border-box; + grid-column: 1 / -1 !important; + width: 100%; + justify-self: stretch; + clear: both; +} +.twb-leader *, +.twb-leader *::before, +.twb-leader *::after { + box-sizing: border-box; + min-width: 0; +} +.twb-leader h2 { + margin: 0; + letter-spacing: 0; + overflow-wrap: anywhere; + line-height: 1.05; +} +.twb-leader p { + max-width: 72ch; + overflow-wrap: anywhere; +} +.twb-leader table { + width: 100%; + border-collapse: collapse; + min-width: 680px; +} +.twb-leader th, +.twb-leader td { + text-align: left; + padding: 12px 14px; + overflow-wrap: anywhere; +} +.twb-leader pre { + max-width: 100%; + overflow-x: auto; +} +.twb-leader svg, +.twb-leader figure { + max-width: 100%; +} +.twb-kicker { + font-size: 0.78rem; + text-transform: uppercase; + letter-spacing: 0.12em; + margin-bottom: 10px; +} +.twb-leader meter { + width: 100%; + height: 12px; +} +.twb-rich { + display: grid; + gap: 18px; + margin-top: 28px; +} +.twb-rich-card { + padding: clamp(16px, 2.5vw, 24px); + border: 1px solid currentColor; + background: color-mix(in srgb, currentColor 5%, transparent); + overflow: hidden; +} +.twb-rich-title { + display: flex; + justify-content: space-between; + gap: 16px; + align-items: baseline; + margin-bottom: 14px; +} +.twb-rich-title span { + text-transform: uppercase; + font-size: .75rem; + letter-spacing: .08em; +} +.twb-rich-title h3 { + margin: 0; + font-size: clamp(1.1rem, 2.2vw, 1.65rem); + line-height: 1.15; + overflow-wrap: anywhere; +} +.twb-wide { + grid-column: 1 / -1; +} +.twb-table-wrap { + width: 100%; + overflow-x: auto; + border: 1px solid currentColor; + max-width: 100%; + -webkit-overflow-scrolling: touch; +} +.twb-dense-table { + min-width: 2260px !important; + border-collapse: separate !important; + border-spacing: 0; + table-layout: auto; + font-size: .82rem; + line-height: 1.28; +} +.twb-dense-table th, +.twb-dense-table td { + padding: 10px 12px; + white-space: nowrap; + overflow-wrap: normal; + border-right: 1px solid color-mix(in srgb, currentColor 14%, transparent); + border-bottom: 1px solid color-mix(in srgb, currentColor 18%, transparent); + vertical-align: middle; +} +.twb-dense-table th { + font-size: .77rem; + text-transform: uppercase; + letter-spacing: .02em; +} +.twb-dense-table td:first-child, +.twb-dense-table th:first-child { + min-width: 190px; + max-width: 230px; +} +.twb-dense-table td:first-child b { + display: block; + white-space: normal; +} +.twb-dense-table td:first-child small { + display: block; + margin-top: 4px; + opacity: .72; + white-space: normal; +} +.twb-dense-table tbody tr:nth-child(odd) { + background: color-mix(in srgb, currentColor 3%, transparent); +} +.twb-col-score { + background: color-mix(in srgb, #0ea5e9 13%, transparent); + font-weight: 800; +} +.twb-col-dim { + background: color-mix(in srgb, #a855f7 10%, transparent); + font-weight: 700; +} +.twb-col-action { + background: color-mix(in srgb, #10b981 12%, transparent); +} +.twb-col-metric { + background: color-mix(in srgb, #f59e0b 8%, transparent); +} +.twb-col-robot { + background: color-mix(in srgb, #06b6d4 10%, transparent); +} +.twb-col-status { + font-weight: 700; +} +.twb-rank-cell { + text-align: center !important; + font-weight: 800; +} +.twb-best { + background: color-mix(in srgb, #22c55e 27%, transparent) !important; + color: color-mix(in srgb, #00a05d 84%, currentColor); + font-weight: 900; +} +.twb-trophy { + display: inline-block; + margin-left: 5px; + padding: 1px 5px; + border: 1px solid currentColor; + border-radius: 999px; + font-size: .62rem; + line-height: 1.25; +} +.twb-metric-vis { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(min(220px, 100%), 1fr)); + gap: 10px; +} +.twb-metric-vis div { + display: grid; + gap: 7px; +} +.twb-metric-vis b { + display: block; + width: 100%; + font-size: .88rem; + overflow-wrap: anywhere; +} +.twb-metric-vis i { + font-style: normal; + padding: 6px 8px; + background: linear-gradient(90deg, currentColor var(--v), color-mix(in srgb, currentColor 12%, transparent) 0); + color: color-mix(in srgb, canvas 90%, white); + min-height: 28px; +} +.twb-dimension { + margin-top: 20px; + padding: clamp(12px, 2vw, 18px); + border: 1px solid color-mix(in srgb, currentColor 34%, transparent); + background: color-mix(in srgb, currentColor 4%, transparent); + overflow: hidden; +} +.twb-dim-head { + display: flex; + justify-content: space-between; + gap: 14px; + align-items: baseline; + margin-bottom: 14px; +} +.twb-dim-head span { + text-transform: uppercase; + letter-spacing: .08em; + font-size: .72rem; +} +.twb-dim-head b { + font-size: clamp(1rem, 2vw, 1.35rem); + line-height: 1.1; + overflow-wrap: anywhere; +} +.twb-radar-board { + display: grid; + gap: 16px; + align-items: start; +} +.twb-radar-layout-overlay, +.twb-radar-layout-focus, +.twb-radar-layout-ranked { + grid-template-columns: minmax(270px, 1.2fr) minmax(220px, .78fr); +} +.twb-radar-layout-split { + grid-template-columns: repeat(2, minmax(250px, 1fr)); +} +.twb-radar-layout-split .twb-radar-side, +.twb-radar-layout-overlay .twb-radar-callouts, +.twb-radar-layout-ranked .twb-radar-callouts, +.twb-radar-values { + grid-column: 1 / -1; +} +.twb-radar-layout-multiples { + grid-template-columns: minmax(280px, 1fr) minmax(220px, .55fr); +} +.twb-radar-multiple-grid { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(min(210px, 100%), 1fr)); + gap: 12px; +} +.twb-radar-multiple-grid article, +.twb-radar-layout-split article, +.twb-radar-side { + border: 1px solid color-mix(in srgb, currentColor 28%, transparent); + background: color-mix(in srgb, currentColor 5%, transparent); + padding: 12px; +} +.twb-radar-multiple-grid h4, +.twb-radar-layout-split h4, +.twb-radar-side h4 { + margin: 0 0 10px; + font-size: 1rem; + line-height: 1.15; +} +.twb-radar-multiple-grid small { + display: block; + margin-bottom: 8px; + opacity: .7; +} +.twb-radar-figure { + margin: 0; + min-width: 0; +} +.twb-radar-svg { + display: block; + width: 100%; + max-width: 540px; + margin: 0 auto; + overflow: visible; +} +.twb-radar-medium .twb-radar-svg { + max-width: 390px; +} +.twb-radar-small .twb-radar-svg { + max-width: 230px; +} +.twb-radar-ring, +.twb-radar-axis { + fill: none; + stroke: currentColor; + stroke-width: .9; + opacity: .22; + vector-effect: non-scaling-stroke; +} +.twb-radar-scale { + fill: currentColor; + font-size: 9px; + opacity: .45; +} +.twb-radar-label { + fill: currentColor; + font-size: 12px; + font-weight: 800; + text-anchor: middle; + dominant-baseline: middle; +} +.twb-radar-area { + fill: var(--c); + fill-opacity: .08; + stroke: none; +} +.twb-radar-line { + fill: none; + stroke: var(--c); + stroke-width: 2.35; + stroke-linejoin: round; + stroke-linecap: round; + vector-effect: non-scaling-stroke; +} +.twb-radar-series circle { + fill: var(--c); + stroke: color-mix(in srgb, canvas 88%, white); + stroke-width: 1.2; + vector-effect: non-scaling-stroke; +} +.twb-radar-legend { + list-style: none; + padding: 0; + margin: 0; + display: grid; + gap: 8px; +} +.twb-radar-legend li { + display: grid; + grid-template-columns: 14px minmax(0, 1fr); + gap: 7px 9px; + align-items: start; + padding: 8px; + border: 1px solid color-mix(in srgb, currentColor 18%, transparent); +} +.twb-radar-legend i { + width: 12px; + height: 12px; + border-radius: 50%; + margin-top: 3px; + background: var(--c); +} +.twb-radar-legend b, +.twb-radar-legend span { + grid-column: 2; + min-width: 0; + overflow-wrap: anywhere; +} +.twb-radar-legend b { + line-height: 1.15; +} +.twb-radar-legend span { + font-size: .78rem; + opacity: .75; +} +.twb-radar-callouts { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(min(160px, 100%), 1fr)); + gap: 8px; +} +.twb-radar-callouts div { + border: 1px solid color-mix(in srgb, currentColor 22%, transparent); + padding: 10px; + background: color-mix(in srgb, currentColor 4%, transparent); +} +.twb-radar-callouts b, +.twb-radar-callouts span, +.twb-radar-callouts i { + display: block; +} +.twb-radar-callouts span { + margin: 4px 0; + opacity: .72; + overflow-wrap: anywhere; +} +.twb-radar-callouts i { + font-style: normal; + font-weight: 900; +} +.twb-radar-values { + max-width: 100%; + overflow-x: auto; + border: 1px solid color-mix(in srgb, currentColor 26%, transparent); +} +.twb-radar-values table { + min-width: 760px; + width: 100%; + border-collapse: collapse; +} +.twb-radar-values th, +.twb-radar-values td { + padding: 8px 10px; + border-bottom: 1px solid color-mix(in srgb, currentColor 18%, transparent); + white-space: nowrap; +} +.twb-radar-score-strip { + display: grid; + gap: 8px; +} +.twb-radar-score-strip span { + display: grid; + grid-template-columns: 1fr; + gap: 4px; + align-items: center; + min-height: 34px; + padding: 7px 9px; + background: linear-gradient(90deg, var(--c) var(--v), color-mix(in srgb, currentColor 8%, transparent) 0); +} +.twb-radar-score-strip b { + overflow-wrap: anywhere; + width: 100%; + min-width: min(150px, 100%); +} +.twb-radar-score-strip i { + font-style: normal; + font-weight: 900; + justify-self: flex-end; +} +.twb-radar-layout-multiples .twb-radar-score-strip span { + min-width: min(220px, 100%); +} +.twb-radar-terminal .twb-radar-line, +.twb-radar-command .twb-radar-line { + stroke-dasharray: 8 5; +} +.twb-radar-console .twb-radar-svg, +.twb-radar-blueprint .twb-radar-svg, +.twb-radar-stage .twb-radar-svg { + filter: drop-shadow(0 0 10px color-mix(in srgb, currentColor 28%, transparent)); +} +.twb-radar-swiss .twb-radar-area, +.twb-radar-ledger .twb-radar-area, +.twb-radar-gazette .twb-radar-area { + fill-opacity: .035; +} +.twb-radar-poster .twb-radar-multiple-grid article, +.twb-radar-zine .twb-radar-side, +.twb-radar-garden .twb-radar-multiple-grid article { + border-radius: 18px; +} +.twb-radar-executive .twb-radar-line, +.twb-radar-stage .twb-radar-line { + stroke-width: 3; +} +.twb-radar-audit .twb-radar-values table, +.twb-radar-registry .twb-radar-score-strip, +.twb-radar-ledger .twb-radar-legend { + font-family: ui-monospace, SFMono-Regular, Consolas, monospace; +} +.twb-compare-scroll { + max-width: 100%; + overflow-x: auto; + border: 1px solid color-mix(in srgb, currentColor 28%, transparent); +} +.twb-compare-grid { + display: grid; + grid-template-columns: minmax(170px, 1.2fr) repeat(var(--metric-count), minmax(82px, 1fr)); + min-width: 980px; +} +.twb-compare-grid > * { + min-width: 0; + padding: 9px 10px; + border-right: 1px solid color-mix(in srgb, currentColor 16%, transparent); + border-bottom: 1px solid color-mix(in srgb, currentColor 16%, transparent); +} +.twb-compare-grid .twb-grid-head { + background: color-mix(in srgb, currentColor 10%, transparent); + font-size: .74rem; + text-transform: uppercase; + letter-spacing: .02em; +} +.twb-compare-grid strong { + display: flex; + align-items: center; + gap: 8px; + font-size: .86rem; + line-height: 1.2; +} +.twb-compare-grid strong span { + opacity: .66; + font-size: .72rem; +} +.twb-compare-grid i { + display: grid; + align-items: center; + min-height: 34px; + font-style: normal; + background: linear-gradient(90deg, color-mix(in srgb, currentColor 42%, transparent) var(--v), color-mix(in srgb, currentColor 8%, transparent) 0); +} +.twb-compare-grid i span { + font-weight: 800; +} +.twb-compare-grid .twb-heat-best { + background: linear-gradient(90deg, color-mix(in srgb, #22c55e 70%, currentColor 12%) var(--v), color-mix(in srgb, #22c55e 12%, transparent) 0); +} +.twb-grouped-bars { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(min(260px, 100%), 1fr)); + gap: 12px; +} +.twb-grouped-bars section, +.twb-detail-chart details, +.twb-small-multiples article { + border: 1px solid color-mix(in srgb, currentColor 28%, transparent); + background: color-mix(in srgb, currentColor 5%, transparent); + padding: 12px; +} +.twb-grouped-bars h4, +.twb-small-multiples h4 { + margin: 0 0 10px; + font-size: 1rem; + line-height: 1.15; +} +.twb-grouped-bars div, +.twb-detail-chart details div { + display: grid; + gap: 7px; +} +.twb-grouped-bars span, +.twb-detail-chart details span, +.twb-small-multiples span { + display: grid; + grid-template-columns: minmax(0, 1fr) auto; + gap: 8px; + align-items: center; + padding: 7px 9px; + min-height: 32px; + background: linear-gradient(90deg, color-mix(in srgb, currentColor 28%, transparent) var(--v), color-mix(in srgb, currentColor 7%, transparent) 0); +} +.twb-grouped-bars span b, +.twb-detail-chart details span b, +.twb-small-multiples span b { + overflow-wrap: anywhere; + font-size: .78rem; + line-height: 1.15; +} +.twb-grouped-bars span i, +.twb-detail-chart details span i, +.twb-small-multiples span i { + font-style: normal; + font-weight: 800; +} +.twb-detail-chart { + display: grid; + gap: 10px; +} +.twb-detail-chart summary { + cursor: default; + font-weight: 800; + padding-bottom: 10px; +} +.twb-scatter-wrap { + display: grid; + grid-template-columns: minmax(260px, 1fr) minmax(190px, .55fr); + gap: 14px; + align-items: stretch; +} +.twb-scatter-plot { + position: relative; + min-height: 310px; + border-left: 2px solid currentColor; + border-bottom: 2px solid currentColor; + background: + linear-gradient(90deg, color-mix(in srgb, currentColor 9%, transparent) 1px, transparent 1px), + linear-gradient(color-mix(in srgb, currentColor 9%, transparent) 1px, transparent 1px); + background-size: 20% 20%; + overflow: hidden; +} +.twb-scatter-plot span { + position: absolute; + left: var(--x); + top: var(--y); + width: var(--s); + height: var(--s); + transform: translate(-50%, -50%); + border-radius: 999px; + display: grid; + place-items: center; + background: currentColor; + color: color-mix(in srgb, canvas 90%, white); + font-size: .68rem; +} +.twb-scatter-plot em { + position: absolute; + font-style: normal; + font-size: .72rem; + opacity: .72; +} +.twb-axis-x { + right: 8px; + bottom: 8px; +} +.twb-axis-y { + left: 8px; + top: 8px; +} +.twb-scatter-wrap ul { + list-style: none; + padding: 0; + margin: 0; + display: grid; + gap: 7px; + max-height: 310px; + overflow: auto; +} +.twb-scatter-wrap li { + display: grid; + grid-template-columns: auto minmax(0, 1fr) auto; + gap: 8px; + align-items: center; + padding: 8px; + border: 1px solid color-mix(in srgb, currentColor 20%, transparent); +} +.twb-scatter-wrap li span { + overflow-wrap: anywhere; + font-size: .82rem; +} +.twb-scatter-wrap li i { + font-style: normal; + font-size: .78rem; + opacity: .78; +} +.twb-small-multiples { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(min(220px, 100%), 1fr)); + gap: 12px; +} +.twb-small-multiples small { + display: block; + margin: -4px 0 10px; + opacity: .68; +} +.twb-upload-window, +.twb-dataset-list { + display: grid; + gap: 12px; +} +.twb-upload-window label, +.twb-dataset-list div { + display: grid; + gap: 5px; + padding: 12px; + border: 1px solid color-mix(in srgb, currentColor 30%, transparent); +} +.twb-upload-actions { + display: flex; + flex-wrap: wrap; + gap: 10px; +} +.twb-upload-actions button, +.twb-dataset-list button { + border: 1px solid currentColor; + background: transparent; + color: inherit; + padding: 9px 12px; + min-height: 38px; + cursor: default; +} +.twb-dataset-entry p { + margin: 0; + max-width: none; +} +.twb-dataset-entry a { + display: inline-flex; + width: fit-content; + border: 1px solid currentColor; + color: inherit; + padding: 9px 12px; + font-weight: 800; +} +.twb-rich-ledger { grid-template-columns: 1.2fr .9fr; } +.twb-rich-console { grid-template-columns: .85fr 1.15fr; } +.twb-rich-glass { grid-template-columns: 1fr 1fr; } +.twb-rich-terminal { grid-template-columns: 1fr .8fr; } +.twb-rich-garden { grid-template-columns: .9fr 1fr; } +.twb-rich-orbit { grid-template-columns: 1.25fr .75fr; } +.twb-rich-swiss { grid-template-columns: repeat(2, minmax(0, 1fr)); } +.twb-rich-executive { grid-template-columns: 1.4fr .8fr; } +.twb-rich-poster { grid-template-columns: .8fr 1.2fr; } +.twb-rich-registry { grid-template-columns: 1fr 1fr; } +.twb-rich-atlas { grid-template-columns: .9fr 1.1fr; } +.twb-rich-command { grid-template-columns: .75fr 1.25fr; } +.twb-rich-museum { grid-template-columns: 1.25fr .75fr; } +.twb-rich-blueprint { grid-template-columns: repeat(2, minmax(0, 1fr)); } +.twb-rich-gazette { grid-template-columns: 1.35fr .85fr; } +.twb-rich-observatory { grid-template-columns: 1fr 1fr; } +.twb-rich-kanban { grid-template-columns: .85fr 1.15fr; } +.twb-rich-zine { grid-template-columns: 1fr 1fr; } +.twb-rich-audit { grid-template-columns: 1.15fr .85fr; } +.twb-rich-stage { grid-template-columns: 1.25fr .75fr; } +.twb-v02 { background:#08131e; color:#e8fbff; border:1px solid #3ae6ff; box-shadow:0 0 32px rgba(58,230,255,.18); } +.twb-v02-top { display:flex; justify-content:space-between; gap:18px; align-items:flex-end; border-bottom:1px solid rgba(58,230,255,.45); padding-bottom:16px; } +.twb-v02-top span { color:#79f7b2; text-transform:uppercase; } +.twb-v02-grid { display:grid; grid-template-columns:1.3fr 1fr 1fr 1fr; gap:14px; margin-top:20px; } +.twb-v02-grid article { background:rgba(15,44,67,.84); border:1px solid rgba(121,247,178,.32); padding:18px; } +.twb-v02-grid .prime strong { display:block; font-size:clamp(2.4rem,6vw,4.6rem); color:#79f7b2; } +.twb-v02-rank { display:grid; grid-template-columns:repeat(4,1fr); gap:10px; padding:0; margin:18px 0 0; list-style:none; } +.twb-v02-rank li { border-top:3px solid #3ae6ff; padding-top:10px; } +.twb-v02-rank em { display:block; color:#79f7b2; font-style:normal; } +.twb-v02-bars { display:grid; gap:8px; margin-top:18px; } +.twb-v02-bars span { padding:8px 10px; background:linear-gradient(90deg,#79f7b2 var(--v),rgba(121,247,178,.13) 0); color:#06121c; font-weight:700; } +@media (max-width: 900px) { + .twb-v01-layout, + .twb-v02-grid, + .twb-v03-shell, + .twb-v05-bed, + .twb-v06-orbits, + .twb-v08-brief, + .twb-v08-kpis, + .twb-v09-wall, + .twb-v11-nodes, + .twb-v13-gallery, + .twb-v14-blueprint, + .twb-v15-columns, + .twb-v16-radial, + .twb-v17-kanban, + .twb-v17-stacks, + .twb-v19-receipts, + .twb-v20-acts, + .museum .gallery { + grid-template-columns: 1fr; + } + .museum .deep, + .museum .research-pack, + .museum .metric-pack, + .museum .date-pack, + .museum .participation-pack, + .museum .policy-pack, + .museum .contact-pack { + grid-column: 1 / -1 !important; + } + .twb-v02-rank, + .twb-v07-grid { + grid-template-columns: 1fr; + } + .twb-v09-wall { + grid-template-columns: repeat(2, minmax(0, 1fr)); + } + .twb-v10-ledger div, + .twb-v10-ledger dd { + grid-template-columns: 1fr; + display: grid; + } + .twb-v10-stack { + height: auto; + flex-direction: column; + } + .twb-v10-stack span { + width: 100%; + min-height: 34px; + } + .twb-v13-gallery h2 { + writing-mode: horizontal-tb; + } + .twb-v11-scatter { + height: 210px; + } + .twb-v13-lollipop span { + padding-left: 0; + padding-top: 26px; + } + .twb-leader { + margin-inline: 0; + } + .twb-rich { + grid-template-columns: 1fr !important; + } + .twb-rich-title { + display: grid; + } + .twb-radar-layout-overlay, + .twb-radar-layout-focus, + .twb-radar-layout-ranked, + .twb-radar-layout-split, + .twb-radar-layout-multiples { + grid-template-columns: 1fr; + } + .twb-radar-layout-split .twb-radar-side, + .twb-radar-layout-overlay .twb-radar-callouts, + .twb-radar-layout-ranked .twb-radar-callouts, + .twb-radar-values { + grid-column: auto; + } + .twb-radar-svg { + max-width: min(470px, 100%); + } + .twb-v05-title { + display: grid; + align-items: start; + } + .museum .module-list { + grid-template-columns: 1fr !important; + } + .twb-radar-layout-multiples { + grid-template-columns: 1fr !important; + } + .twb-radar-layout-multiples .twb-radar-side { + width: 100%; + } + .twb-scatter-wrap { + grid-template-columns: 1fr; + } + .twb-scatter-wrap ul { + max-height: none; + } +} +@media (max-width: 560px) { + .twb-leader { + max-width: 100%; + margin-inline: 0; + padding: 18px; + } + .twb-leader h2 { + font-size: clamp(1.45rem, 11vw, 2.6rem); + } + .twb-v09-wall, + .twb-v14-heat, + .twb-v17-stacks { + grid-template-columns: 1fr; + } + .twb-v06-orbits article, + .twb-v16-radial article { + max-width: 240px; + width: 100%; + justify-self: center; + } + .twb-v08-donuts span, + .twb-v18-cutpie { + width: min(190px, 70vw); + } + .twb-v11-scatter span { + width: 58px; + font-size: .68rem; + } + .twb-v19-waterfall { + height: auto; + flex-direction: column; + align-items: stretch; + } + .twb-v19-waterfall span { + width: 100%; + min-height: 34px; + height: auto; + } + .twb-rich { + grid-template-columns: 1fr !important; + } + .twb-rich-title { + display: grid; + } + .twb-dim-head { + display: grid; + } + .twb-dense-table { + font-size: .76rem; + } + .twb-radar-label { + font-size: 10px; + } + .twb-radar-scale { + display: none; + } + .twb-radar-multiple-grid { + grid-template-columns: 1fr; + } + .twb-scatter-plot { + min-height: 240px; + } +} +/* page layout overflow guard */ +html, +body { + max-width: 100%; + overflow-x: clip; +} +@supports not (overflow: clip) { + html, + body { + overflow-x: hidden; + } +} +main, +[class*="layout-"] { + min-width: 0; +} +.nav { + max-width: 100%; + overflow-x: auto; +} +.section, +.hero-panel, +.board-window, +.feature-grid article, +.timeline article, +.date-grid article, +.part-grid article, +.paper-grid article, +.metric-grid article { + min-width: 0; + max-width: 100%; + overflow: hidden; + overflow-wrap: anywhere; + word-break: normal; +} +.board, +.board-window, +.benchmark-board, +.rank-table, +.score-table { + max-width: 100%; + overflow-x: auto; + -webkit-overflow-scrolling: touch; +} +.board table, +.board-window table, +.benchmark-board table, +.rank-table table, +.score-table table { + min-width: 540px; +} +.newspaper .paper { + columns: auto !important; + column-count: auto !important; + column-width: auto !important; + display: grid !important; + grid-template-columns: repeat(auto-fit, minmax(min(320px, 100%), 1fr)); + gap: 18px; +} +.newspaper .paper > .twb-leader { + grid-column: 1 / -1 !important; +} +.section h1, +.section h2, +.section h3, +.hero-panel h1, +.hero-panel h2, +.hero-panel h3, +.date-grid b, +.timeline b, +.part-grid b { + overflow-wrap: anywhere; + line-height: 1.08; +} +.timeline, +.date-grid, +.feature-grid, +.part-grid, +.paper-grid, +.metric-grid, +.stat-strip, +.lens-stack, +.slate-columns, +.gate-row, +.office-grid, +.committee-row, +.tickets, +.review-matrix .matrix-cells, +.method-index .index-lines, +.research-extension .research-grid { + grid-template-columns: repeat(auto-fit, minmax(min(230px, 100%), 1fr)) !important; +} +.research-extension, +.layout-summit .research-extension { + position: relative !important; + inset: auto !important; + top: auto !important; + right: auto !important; + bottom: auto !important; + left: auto !important; + transform: none !important; + z-index: 0 !important; + max-width: 100% !important; +} +.layout-summit .research-extension, +.layout-executive .research-extension, +.layout-dashboard .research-extension { + grid-column: 1 / -1 !important; +} +.layout-brutal .contact, +.layout-brutal .venue, +.layout-brutal .policies { + grid-column: 1 / -1 !important; +} +.research-extension article, +.briefing-panel, +.floating-panel, +.side-panel { + min-width: 0 !important; + overflow-wrap: anywhere; +} +.metric-grid b, +.review-matrix b, +.lens-stack b, +.gallery b, +.deep b, +.module-list b, +.twb-dim-head b { + display: block; + width: 100%; +} +.twb-v09 { + transform: none !important; +} +.atlas .metric-pack, +.atlas .metrics { + min-width: 0 !important; + max-width: 100% !important; +} +.layout-journal .venue, +.layout-journal .participation, +.layout-journal .policies, +.layout-journal .contact, +.layout-journal .dates, +.layout-campus .venue, +.layout-campus .participation, +.layout-campus .policies, +.layout-campus .contact, +.layout-campus .dates, +.layout-poster .venue, +.layout-poster .participation, +.layout-poster .policies, +.layout-poster .contact, +.layout-poster .dates, +.layout-swiss .venue, +.layout-swiss .participation, +.layout-swiss .policies, +.layout-swiss .contact, +.layout-swiss .dates, +.layout-dashboard .dates, +.layout-glass .dates, +.layout-brutal .dates, +.layout-soft .dates, +.layout-mission .dates, +.layout-summit .dates { + grid-column: 1 / -1 !important; +} +.layout-journal .policies, +.layout-journal .participation, +.layout-campus .policies, +.layout-campus .participation, +.layout-poster .policies, +.layout-poster .participation, +.layout-journal .dates, +.layout-campus .dates, +.layout-poster .dates, +.layout-swiss .dates { + min-width: min(420px, 100%); +} +.dates .timeline, +.date-pack .date-grid, +.timeline { + align-items: stretch; +} +.dates .timeline article, +.date-pack .date-grid article, +.timeline article { + min-height: 160px; + display: grid; + align-content: start; +} +.dates .timeline time, +.date-pack .date-grid span { + display: block; + margin-bottom: 8px; + overflow-wrap: anywhere; +} +@media (max-width: 1200px) { + .atlas .shell { + grid-template-columns: minmax(160px, 210px) minmax(0, 1fr) !important; + } + .atlas .metrics, + .atlas .metric-pack { + grid-column: 1 / -1 !important; + grid-row: auto !important; + } + .layout-journal .venue, + .layout-journal .participation, + .layout-journal .policies, + .layout-journal .contact, + .layout-campus .venue, + .layout-campus .participation, + .layout-campus .policies, + .layout-campus .contact, + .layout-poster .venue, + .layout-poster .participation, + .layout-poster .policies, + .layout-poster .contact, + .layout-swiss .venue, + .layout-swiss .participation, + .layout-swiss .policies, + .layout-swiss .contact { + grid-column: 1 / -1 !important; + } +} +.section-head { + display: grid !important; + grid-template-columns: auto minmax(0, 1fr); + align-items: start; + max-width: 100%; +} +.section-head span { + white-space: nowrap; +} +.section-head h2 { + max-width: 100%; + overflow-wrap: anywhere; + word-break: normal; + hyphens: none; +} +@media (max-width: 1100px) { + .section-head h2 { + font-size: clamp(1.8rem, 6vw, 3.4rem) !important; + } +} +@media (max-width: 760px) { + .hero, + .layout-glass .hero, + .radial .orbit, + .ledger .hero { + display: grid !important; + grid-template-columns: 1fr !important; + width: 100% !important; + max-width: 100% !important; + aspect-ratio: auto !important; + } + .hero-panel { + width: 100% !important; + max-width: 100% !important; + } + .atlas .shell, + .radial .shell, + .ledger .shell, + .stage .shell, + .zine .shell { + display: block !important; + padding-inline: 16px !important; + overflow-x: clip !important; + } + .atlas .nav, + .radial .nav, + .ledger .nav, + .stage .nav, + .zine .nav { + position: static !important; + transform: none !important; + left: auto !important; + right: auto !important; + top: auto !important; + bottom: auto !important; + max-width: 100% !important; + flex-wrap: wrap !important; + } + .ledger .block { + display: block !important; + } + .ledger .block b, + .ledger .block span { + display: block !important; + border-right: 0 !important; + } + .section-head { + grid-template-columns: auto minmax(0, 1fr); + align-items: start; + } + .section-head h2 { + font-size: clamp(1.55rem, 10vw, 2.8rem) !important; + } + .timeline, + .date-grid, + .feature-grid, + .part-grid, + .paper-grid, + .metric-grid, + .stat-strip { + grid-template-columns: 1fr !important; + } + .timeline article, + .date-grid article, + .part-grid article { + min-height: auto !important; + } +} + +/* ============ Editorial-inspired public document refresh ============ */ +.twb-doc[data-page="triworldbench"] { + --twb-ink: #181b1f; + --twb-muted: #646b73; + --twb-line: #e2e5e8; + --twb-soft: #f5f6f7; + --twb-accent: #008a82; + --twb-link: #235fc7; + position: relative; + isolation: isolate; + min-height: 100vh; + overflow-x: clip; + color: var(--twb-ink); + background: #fff; + font-family: "Segoe UI Variable Text", Aptos, "Segoe UI", Arial, sans-serif; + font-size: 16px; + line-height: 1.68; +} +.twb-doc[data-page="triworldbench"]::before { + content: "TriWorldBench"; + position: fixed; + z-index: -1; + top: 45%; + left: 50%; + color: rgba(28, 35, 40, .035); + font-family: "Segoe UI Variable Display", Aptos Display, "Segoe UI", sans-serif; + font-size: 112px; + font-weight: 800; + line-height: 1; + letter-spacing: 0; + white-space: nowrap; + pointer-events: none; + transform: translate(-50%, -50%) rotate(-18deg); +} +.twb-doc[data-page="triworldbench"] *, +.twb-doc[data-page="triworldbench"] *::before, +.twb-doc[data-page="triworldbench"] *::after { + letter-spacing: 0; +} +.twb-doc[data-page="triworldbench"] a { color: inherit; } + +/* Navigation and language segmented control */ +.twb-doc .site-nav { + position: sticky; + top: 0; + z-index: 50; + display: grid; + grid-template-columns: auto minmax(0, 1fr) auto; + align-items: center; + gap: 24px; + min-height: 62px; + padding: 10px max(22px, calc((100vw - 1240px) / 2)); + border: 0; + border-bottom: 1px solid var(--twb-line); + background: rgba(255, 255, 255, .96); + color: var(--twb-ink); + box-shadow: none; + backdrop-filter: blur(12px); +} +.twb-doc .site-nav .brand { + color: var(--twb-ink); + font-family: "Segoe UI Variable Display", Aptos Display, "Segoe UI", sans-serif; + font-size: 20px; + font-weight: 800; + text-decoration: none; + white-space: nowrap; +} +.twb-doc .site-nav .brand::before { + content: "T"; + display: inline-grid; + width: 28px; + height: 28px; + margin-right: 9px; + place-items: center; + border: 1px solid var(--twb-accent); + border-radius: 5px; + color: #fff; + background: var(--twb-accent); + font-size: 15px; +} +.twb-doc .site-nav nav { + display: flex; + min-width: 0; + justify-content: center; + gap: 4px; + overflow-x: auto; + scrollbar-width: none; +} +.twb-doc .site-nav nav::-webkit-scrollbar { display: none; } +.twb-doc .site-nav nav a { + flex: none; + padding: 7px 8px; + border-radius: 4px; + color: #50565d; + font-size: 13px; + font-weight: 650; + line-height: 1; + text-decoration: none; + white-space: nowrap; +} +.twb-doc .site-nav nav a:hover, +.twb-doc .site-nav nav a:focus-visible { + color: var(--twb-ink); + background: var(--twb-soft); + outline: none; +} +.twb-doc .language-menu { + display: inline-flex; + width: auto; + padding: 3px; + border: 1px solid #ccd1d5; + border-radius: 6px; + background: #fff; +} +.twb-doc .language-menu > button { + min-height: 30px; + padding: 5px 10px; + border: 0; + border-radius: 4px; + color: #626970; + background: transparent; + font: inherit; + font-size: 12px; + font-weight: 750; + cursor: pointer; +} +.twb-doc .language-menu > button:hover { color: var(--twb-ink); } +.twb-doc .language-menu > button.is-active { + color: #fff; + background: var(--twb-ink); +} + +/* Academic-project title area */ +.twb-doc .twb-hero { + min-height: 0; + padding: 68px 24px 54px; + overflow: visible; + color: var(--twb-ink); + background: transparent; + text-align: center; +} +.twb-doc .twb-hero-bg { display: none; } +.twb-doc .twb-hero-inner { + width: min(1120px, 100%); + max-width: none; + margin: 0 auto; +} +.twb-doc .twb-hero .eyebrow { + margin: 0 0 12px; + color: var(--twb-accent); + font-size: 13px; + font-weight: 800; + text-transform: uppercase; +} +.twb-doc .twb-hero h1 { + max-width: 980px; + margin: 0 auto; + color: var(--twb-ink); + font-family: "Segoe UI Variable Display", Aptos Display, "Segoe UI", sans-serif; + font-size: 58px; + font-weight: 800; + line-height: 1.08; +} +.twb-doc .twb-accent { + color: var(--twb-ink); + font-size: .58em; + font-weight: 650; +} +.twb-doc .twb-hero .subtitle { + max-width: 850px; + margin: 22px auto 0; + color: #4f565d; + font-size: 18px; + line-height: 1.65; +} +.twb-doc .actions, +.twb-doc .ds-actions { + display: flex; + justify-content: center; + gap: 9px; + margin-top: 24px; +} +.twb-doc .actions a, +.twb-doc .ds-btn { + display: inline-flex; + min-height: 40px; + align-items: center; + justify-content: center; + padding: 8px 16px; + border: 1px solid var(--twb-ink); + border-radius: 6px; + color: #fff; + background: var(--twb-ink); + font-size: 13px; + font-weight: 750; + line-height: 1.2; + text-decoration: none; + box-shadow: 0 3px 8px rgba(20, 24, 28, .12); +} +.twb-doc .actions a + a, +.twb-doc .ds-btn.ghost { + color: var(--twb-ink); + background: #fff; +} +.twb-doc .actions a:hover, +.twb-doc .ds-btn:hover { transform: translateY(-1px); } +.twb-doc .actions a:active, +.twb-doc .ds-btn:active { transform: scale(.98); } +.twb-doc .twb-authors { + max-width: 1080px; + margin: 30px auto 0; + padding-top: 24px; + border-top: 1px solid var(--twb-line); +} +.twb-doc .twb-authors-list { + max-width: none; + margin: 0; + color: #30353a; + font-size: 15px; + line-height: 2; +} +.twb-doc .twb-authors-list a { + color: var(--twb-link); + border: 0; + text-decoration: none; +} +.twb-doc .twb-authors-list a:hover { text-decoration: underline; } +.twb-doc .twb-authors-list sup, +.twb-doc .twb-affiliations sup { color: var(--twb-accent); } +.twb-doc .twb-affiliations { + justify-content: center; + margin: 8px 0 0; + color: var(--twb-muted); + font-size: 13px; + opacity: 1; +} +.twb-institutions { + display: flex; + max-width: 1080px; + margin: 24px auto 0; + align-items: stretch; + justify-content: center; + gap: 10px; + overflow-x: auto; + padding: 2px 0 8px; + scrollbar-width: thin; +} +.twb-institutions > a, +.twb-institutions > div { + display: grid; + flex: 0 0 148px; + min-height: 74px; + grid-template-rows: 42px auto; + place-items: center; + gap: 6px; + padding: 8px; + border: 1px solid var(--twb-line); + border-radius: 6px; + color: #4c5359; + background: rgba(255,255,255,.86); + font-size: 11px; + line-height: 1.25; + text-align: center; + text-decoration: none; +} +.twb-institutions > a:hover { border-color: #aeb5ba; background: var(--twb-soft); } +.twb-institutions img { + display: block; + width: 120px; + height: 40px; + object-fit: contain; +} +.twb-institution-mark { + display: grid; + width: 42px; + height: 42px; + place-items: center; + border: 1px solid #bfc5ca; + border-radius: 6px; + color: #394047; + background: #f4f5f6; + font-size: 12px; + font-weight: 850; +} + +/* Unframed document sections */ +.twb-doc main { + display: block; + width: min(1180px, calc(100% - 40px)); + margin: 0 auto 72px; +} +.twb-doc main > .section, +.twb-doc main > #leaderboard.twb-v02 { + width: 100%; + margin: 0; + padding: 62px 0; + overflow: visible; + border: 0 !important; + border-top: 1px solid var(--twb-line) !important; + border-radius: 0; + color: var(--twb-ink) !important; + background: transparent !important; + box-shadow: none !important; +} +.twb-doc main > #overview { border-top: 0 !important; } +.twb-doc .section-head { + display: grid; + grid-template-columns: 42px minmax(0, 1fr); + align-items: baseline; + gap: 10px; + margin-bottom: 24px; +} +.twb-doc .section-head > span { + color: var(--twb-accent); + font-family: "Cascadia Mono", Consolas, monospace; + font-size: 12px; + font-weight: 800; +} +.twb-doc .section-head h2, +.twb-doc .twb-v02-top h2 { + margin: 0; + overflow-wrap: normal; + color: var(--twb-ink) !important; + font-family: "Segoe UI Variable Display", Aptos Display, "Segoe UI", sans-serif; + font-size: 32px; + font-weight: 780; + line-height: 1.2; + word-break: normal; +} +.twb-doc .section > p { + max-width: 920px; + margin: 0 0 15px; + color: #424950; +} +.twb-doc .section h3, +.twb-doc .section h4 { + overflow-wrap: normal; + word-break: normal; +} +.twb-keywords { + display: flex; + margin-top: 24px; + flex-wrap: wrap; + gap: 7px; +} +.twb-keywords b { + padding: 6px 10px; + border: 1px solid #d7dbde; + border-radius: 4px; + color: #4d555c; + background: #fff; + box-shadow: none; + font-size: 12px; + font-weight: 700; + text-align: left; +} + +/* Why TriWorldBench */ +.adv-grid { + display: grid; + grid-template-columns: repeat(2, minmax(0, 1fr)); + align-items: stretch; + gap: 34px 42px; + margin-top: 30px; +} +.adv-grid article { + display: grid; + min-width: 0; + grid-template-rows: auto 1fr auto; + gap: 10px; + padding: 20px 0 0; + overflow: visible; + border: 0; + border-top: 2px solid #252a2f; + border-radius: 0; + background: transparent; +} +.adv-grid article h3 { + margin: 0; + color: var(--twb-ink); + font-size: 19px; + line-height: 1.35; + overflow-wrap: break-word; +} +.adv-grid article > p { + margin: 0; + color: var(--twb-muted); + font-size: 14px; + line-height: 1.65; + overflow-wrap: break-word; + word-break: normal; +} +.adv-vs { + display: grid; + grid-template-columns: minmax(0, 1fr) 26px minmax(0, 1fr); + align-items: stretch; + gap: 7px; + margin-top: auto; + padding-top: 12px; +} +.adv-vs > span { + display: grid; + min-height: 62px; + align-content: center; + gap: 3px; + padding: 9px 10px; + border: 1px solid #dadddf; + border-radius: 5px; + line-height: 1.25; + text-decoration: none; +} +.adv-vs small { font-size: 11px; font-weight: 550; } +.adv-them { color: #6c7379; background: #f4f5f6; } +.adv-us { color: #fff; border-color: var(--twb-accent) !important; background: var(--twb-accent); } +.adv-vs em { + display: grid; + align-self: stretch; + place-items: center; + color: #767d83; + font-size: 11px; + font-style: normal; + font-weight: 800; +} + +/* Visualization cases */ +.case-intro { + max-width: none !important; + padding: 17px 20px; + border-left: 3px solid var(--twb-accent); + background: rgba(246,247,248,.86); +} +.case-tabs { + display: inline-flex; + gap: 3px; + margin: 20px 0 18px; + padding: 3px; + border: 1px solid #ccd1d5; + border-radius: 6px; + background: #fff; +} +.case-tab { + min-width: 112px; + padding: 7px 14px; + border: 0; + border-radius: 4px; + color: #5b6269; + background: transparent; + font-size: 13px; + font-weight: 750; + cursor: pointer; +} +.case-tab.is-active { color: #fff; background: var(--twb-ink); } +.case-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 18px; } +.case-item { + margin: 0; + overflow: hidden; + border: 1px solid #d9dde0; + border-radius: 6px; + background: #fff; + box-shadow: none; + transform: none !important; +} +.case-item:hover { transform: none !important; box-shadow: none; } +.case-item video { width: 100%; background: #111417; } +.case-item figcaption { + min-height: 44px; + padding: 11px 13px; + overflow-wrap: break-word; + color: #343a40; + background: #fff; + font-size: 13px; + font-weight: 700; +} +.case-panel.is-active { padding-right: 7px; } + +/* Editorial-style leaderboard */ +.twb-v02-top { + display: flex; + align-items: flex-end; + justify-content: space-between; + gap: 20px; + padding: 0 0 22px; + border: 0 !important; +} +.twb-v02-top > div { display: grid; gap: 5px; } +.twb-v02-top > span, +.twb-section-kicker, +#leaderboard.twb-v02 .twb-v02-top span { + color: var(--twb-muted); + font-size: 12px; + font-weight: 700; + text-transform: uppercase; +} +.twb-section-kicker { color: var(--twb-accent) !important; } +#leaderboard .twb-rich-card, +#leaderboard .twb-overall { + margin: 0; + padding: 0; + border: 0; + border-radius: 0; + color: var(--twb-ink); + background: transparent; + box-shadow: none; +} +#leaderboard .twb-rich-title { + display: flex; + align-items: baseline; + justify-content: space-between; + gap: 20px; + margin-bottom: 7px; +} +#leaderboard .twb-rich-title span { color: var(--twb-accent); font-size: 11px; } +#leaderboard .twb-rich-title h3 { + margin: 0; + color: var(--twb-ink); + font-size: 20px; +} +#leaderboard .twb-board-note { + max-width: 900px; + margin: 0 0 16px; + color: var(--twb-muted); + font-size: 13px; +} +#leaderboard .twb-table-wrap { + max-width: 100%; + overflow: auto; + border: 1px solid #d8dcdf; + border-radius: 6px; + background: #fff; + scrollbar-color: #aeb5ba #f1f2f3; +} +#leaderboard .twb-dense-table { + width: max-content; + min-width: 2080px; + border-collapse: separate; + border-spacing: 0; + color: var(--twb-ink); + font-size: 12px; +} +#leaderboard .twb-dense-table th, +#leaderboard .twb-dense-table td { + min-width: 104px; + padding: 10px 11px; + border: 0; + border-right: 1px solid #e7e9eb; + border-bottom: 1px solid #e7e9eb; + background: #fff; + text-align: center; + white-space: nowrap; +} +#leaderboard .twb-dense-table th { + position: sticky; + top: 0; + z-index: 3; + color: #383e44; + background: #f3f4f5; + font-size: 11px; + font-weight: 800; +} +#leaderboard .twb-dense-table tbody tr:nth-child(odd) td { background: #fff; } +#leaderboard .twb-dense-table tbody tr:hover td, +#leaderboard .twb-dense-table tbody tr:hover .twb-sticky-col, +#leaderboard .twb-dense-table tbody tr:hover .twb-sticky-rank { + background: #e9ecef !important; +} +#leaderboard .twb-col-rank { + width: 70px; + min-width: 70px !important; + max-width: 70px; +} +#leaderboard .twb-sticky-rank { + position: sticky; + left: 0; + z-index: 4; + background: #fff; +} +#leaderboard thead .twb-sticky-rank { z-index: 6; background: #f3f4f5; } +#leaderboard .twb-sticky-col { + position: sticky; + left: 70px; + z-index: 4; + min-width: 190px !important; + max-width: 240px; + background: #fff; + text-align: left; +} +#leaderboard thead .twb-sticky-col { z-index: 6; background: #f3f4f5; } +#leaderboard .twb-sticky-col b, +#leaderboard .twb-sticky-col small { display: block; } +#leaderboard .twb-sticky-col b { color: #20252a; font-size: 13px; } +#leaderboard .twb-sticky-col small { color: #7a8187; font-size: 10px; } +#leaderboard .twb-best { + color: #09665f !important; + background: #e7f5f2 !important; + box-shadow: none; + font-weight: 850; +} +.twb-rank-badge { + display: inline-grid; + width: 30px; + height: 30px; + place-items: center; + border: 1px solid #cbd0d4; + border-radius: 5px; + color: #5d646a; + background: #fff; + font-weight: 850; +} +.twb-rank-badge.rank-1 { border-color: #cfaa43; color: #72570d; background: #fff5d6; } +.twb-rank-badge.rank-2 { border-color: #aeb5bb; color: #4e565d; background: #f0f2f3; } +.twb-rank-badge.rank-3 { border-color: #bd7d56; color: #704025; background: #fae8dd; } + +/* Radar and filter controls */ +.twb-vis-top { + display: grid; + grid-template-columns: minmax(0, 1.75fr) minmax(230px, .6fr); + align-items: stretch; + gap: 28px; + margin: 30px 0 22px; +} +.twb-vis-top .twb-vis-radar { + display: grid; + min-height: 620px; + margin: 0; + place-items: center; +} +.twb-vis-top .twb-vis-radar svg { + width: min(700px, 100%); + max-width: none; + overflow: visible; +} +.twb-vis-top .twb-vis-models { + min-width: 0; + padding: 15px; + border: 1px solid #d8dcdf; + border-radius: 6px; + color: var(--twb-ink); + background: rgba(255,255,255,.9); +} +.twb-models-head { margin-bottom: 10px; } +.twb-models-head h4 { color: #30363b; font-size: 14px; } +.twb-present-all, +.twb-model-chip, +.ms-btn { + min-height: 32px; + border: 1px solid #cbd0d4; + border-radius: 4px; + color: #4f565c; + background: #fff; + font: inherit; + font-size: 12px; + font-weight: 700; + cursor: pointer; +} +.twb-present-all { padding: 5px 11px; } +.twb-present-all:hover { border-color: #8e969c; color: var(--twb-ink); background: var(--twb-soft); } +.twb-model-chips { + display: flex; + max-height: 540px; + flex-direction: column; + gap: 4px; + overflow-y: auto; + padding-right: 4px; +} +.twb-model-chip { + display: flex; + min-width: 0; + align-items: center; + gap: 8px; + padding: 7px 9px; + overflow: hidden; + text-align: left; + text-overflow: ellipsis; + white-space: nowrap; +} +.twb-model-chip i { width: 9px; height: 9px; flex: none; border-radius: 50%; background: var(--c); } +.twb-model-chip:hover { background: var(--twb-soft); } +.twb-model-chip.is-active { border-color: var(--twb-ink); color: #fff; background: var(--twb-ink); } +.twb-filter-control { + display: grid; + grid-template-columns: 70px minmax(0, 1fr); + align-items: start; + gap: 12px; + padding: 14px 0; + border-top: 1px solid var(--twb-line); + border-bottom: 1px solid var(--twb-line); +} +.twb-filter-label { + padding-top: 7px; + color: #3d444a; + font-size: 13px; + font-weight: 800; +} +.twb-metric-selector { + display: flex; + margin: 0; + flex-wrap: wrap; + gap: 5px; +} +.ms-btn { padding: 6px 10px; } +.ms-btn:hover { border-color: #8e969c; background: var(--twb-soft); } +.ms-btn.is-active { border-color: var(--twb-ink); color: #fff; background: var(--twb-ink); } +.twb-vis-ranked { margin-top: 26px; } +.twb-vis-ranked h4 { margin: 0 0 12px; font-size: 17px; } +.twb-bar-list { display: grid; gap: 6px; } +.twb-bar-list span { + position: relative; + isolation: isolate; + display: grid; + min-height: 36px; + grid-template-columns: minmax(0, 1fr) auto; + align-items: center; + gap: 10px; + padding: 8px 11px; + overflow: hidden; + border: 1px solid #e1e4e6; + border-radius: 4px; + color: #252a2f; + background: #f4f5f6; +} +.twb-bar-list span::before { + content: ""; + position: absolute; + z-index: -1; + inset: 0 auto 0 0; + width: var(--v); + background: color-mix(in srgb, var(--c) 24%, #fff); +} +.twb-bar-list span b { overflow-wrap: break-word; font-size: 12px; } +.twb-bar-list span i { font-size: 12px; font-style: normal; font-weight: 850; } +.visualization .twb-radar-ring, +.visualization .twb-radar-axis { stroke: #8e969d; opacity: .35; } +.visualization .twb-radar-label { fill: #394047; font-size: 12px; } +.visualization .twb-radar-scale { fill: #747b81; } +.visualization .twb-radar-vtx-val { fill: #22272b; } +.twb-metric-glossary, +.twb-metric-glossary[open] { + margin-top: 30px; + padding: 16px 0 0; + border: 0; + border-top: 1px solid var(--twb-line); + border-radius: 0; + background: transparent; +} +.twb-metric-glossary summary { color: #30363b; font-size: 14px; } +.twb-glossary-grid { gap: 14px 26px; } +.twb-glossary-grid div { padding-top: 10px; border-top: 1px solid #eceeef; } + +/* Remaining content follows the same light document rhythm */ +.timeline, +.contact-grid, +.sub-card { margin-top: 22px; } +.timeline article, +.ds-card, +.contact-card, +.ac-lineage article, +.tips-grid article { + border: 0; + border-top: 1px solid #cfd4d7; + border-radius: 0; + background: transparent; + box-shadow: none; +} +.timeline article, +.ds-card, +.contact-card { padding: 17px 0; } +.policies ul { padding-left: 20px; } +.policies li { margin-bottom: 10px; color: #434a50; } +.ac-article { + max-width: 960px; + columns: 1 !important; +} +.ac-article h3 { color: var(--twb-ink); } +.ac-article p { color: #434a50; font-size: 15px; } +.submission-layout { + display: grid; + grid-template-columns: minmax(0, .8fr) minmax(0, 1.2fr); + align-items: start; + gap: 48px; +} +.submission-main p { margin: 0; color: #424950; } +.submission-main .actions { justify-content: flex-start; } +.submission .sub-card { display: grid; gap: 0; margin: 0; } +.submission .sub-row { + display: grid; + grid-template-columns: 44px minmax(0, 1fr); + gap: 12px; + padding: 15px 0; + border: 0; + border-top: 1px solid #d8dcdf; + border-radius: 0; + background: transparent; +} +.submission .sub-row:first-child { border-top: 2px solid var(--twb-ink); } +.submission .sub-row > i { + color: var(--twb-link); + font-family: "Cascadia Mono", Consolas, monospace; + font-size: 18px; + font-style: normal; + font-weight: 800; +} +.submission .sub-row > span { display: grid; gap: 4px; } +.submission .sub-row b { color: var(--twb-ink); } +.submission .sub-row small { color: var(--twb-muted); font-size: 13px; } +.contact-card span { color: var(--twb-accent); } +.contact-card a { color: var(--twb-link); } +.contact-card .contact-download-link { + display: inline; + width: auto; + min-height: 0; + padding: 0; + border: 0; + border-radius: 0; + background: transparent; + color: #000; + box-shadow: none; + text-decoration: underline; + text-decoration-thickness: 1px; + text-underline-offset: 3px; +} +.contact-card .contact-download-link:hover { + border-color: transparent; + background: transparent; + color: #000; + text-decoration-thickness: 2px; +} +.coming { border-radius: 4px; } +.citation-code, +.sub-code { + max-width: 920px; + overflow-x: auto; + margin: 18px 0 0; + padding: 18px 20px; + border: 1px solid #d8dcdf; + border-radius: 6px; + color: #2c3338; + background: #f6f7f8; + font-family: "Cascadia Mono", "Cascadia Code", Consolas, monospace; + font-size: 13px; + line-height: 1.6; + white-space: pre; +} +.sub-token { + border-color: #d3d8db; + border-radius: 4px; + color: #294f4c; + background: #f1f5f4; + font-family: "Cascadia Mono", Consolas, monospace; +} +.sub-table-wrap { border-color: #d8dcdf; border-radius: 6px; } +.sub-table thead th, +.sub-table tbody th { color: #30363b; background: #f3f4f5; } +.sub-note { border-left-color: var(--twb-accent); background: #f2f7f6; } +.twb-doc footer { + padding: 28px 20px; + border-top: 1px solid var(--twb-line); + color: #747b81; + background: #fff; + font-size: 12px; + text-align: center; +} + +@media (max-width: 980px) { + .twb-doc .site-nav { grid-template-columns: auto auto; gap: 12px; } + .twb-doc .site-nav nav { + grid-column: 1 / -1; + grid-row: 2; + justify-content: flex-start; + width: 100%; + padding-bottom: 2px; + } + .twb-doc .language-menu { justify-self: end; } + .twb-doc .twb-hero { padding-top: 52px; } + .twb-doc .twb-hero h1 { font-size: 48px; } + .adv-grid { grid-template-columns: 1fr; } + .twb-vis-top { grid-template-columns: 1fr; } + .twb-vis-top .twb-vis-radar { min-height: 520px; } + .twb-model-chips { max-height: 300px; } + .submission-layout { grid-template-columns: 1fr; gap: 24px; } +} + +@media (max-width: 680px) { + .twb-doc[data-page="triworldbench"] { font-size: 15px; } + .twb-doc[data-page="triworldbench"]::before { font-size: 58px; } + .twb-doc .site-nav { padding: 9px 12px; } + .twb-doc .site-nav .brand { font-size: 17px; } + .twb-doc .site-nav .brand::before { width: 25px; height: 25px; } + .twb-doc .site-nav nav { display: flex; grid-template-columns: none; gap: 2px; } + .twb-doc .site-nav nav a { padding: 7px; font-size: 12px; } + .twb-doc .language-menu, + .twb-doc .language-trigger { width: auto; } + .twb-doc .twb-hero { padding: 42px 16px 36px; } + .twb-doc .twb-hero h1 { font-size: 38px; } + .twb-doc .twb-hero .subtitle { font-size: 16px; } + .twb-doc .twb-authors-list { font-size: 13px; } + .twb-institutions { justify-content: flex-start; } + .twb-doc main { width: min(100% - 28px, 1180px); } + .twb-doc main > .section, + .twb-doc main > #leaderboard.twb-v02 { padding: 42px 0; margin: 0; } + .twb-doc .section-head { grid-template-columns: 32px minmax(0, 1fr); } + .twb-doc .section-head h2, + .twb-doc .twb-v02-top h2 { font-size: 27px; } + .twb-keywords { display: flex; grid-template-columns: none; } + .adv-grid { gap: 26px; } + .adv-vs { grid-template-columns: 1fr; } + .adv-vs em { min-height: 22px; } + .case-tabs { display: inline-flex; width: 100%; grid-template-columns: none; } + .case-tab { min-width: 0; width: 50%; } + .case-grid { grid-template-columns: 1fr; } + .case-panel.is-active { max-height: var(--case-panel-max-height, 720px); } + .twb-v02-top { align-items: flex-start; flex-direction: column; } + #leaderboard .twb-rich-title { align-items: flex-start; flex-direction: column; } + .twb-vis-top .twb-vis-radar { min-height: 410px; } + .twb-filter-control { grid-template-columns: 1fr; gap: 4px; } + .twb-filter-label { padding-top: 0; } + .twb-metric-selector { display: flex; grid-template-columns: none; } + .ms-btn, + .twb-present-all { width: auto; } + .twb-bar-list span { grid-template-columns: minmax(0, 1fr) auto; } + .twb-glossary-grid { grid-template-columns: 1fr; } + .twb-doc .actions, + .twb-doc .ds-actions { display: flex; grid-template-columns: none; flex-direction: column; } + .twb-doc .actions a, + .twb-doc .ds-btn { width: 100%; } + .citation-code, + .sub-code { font-size: 11px; } +} +/* ============ end Editorial-inspired refresh ============ */ +/* MOXIVERSE leaderboard end */ + +/* radar-layout-expansion start */ +.twb-rich > .twb-metrics-card { + grid-column: 1 / -1 !important; + width: 100% !important; + align-self: stretch; +} +.twb-metrics-card .twb-dimension { + width: 100%; + margin-top: clamp(24px, 3vw, 40px); + padding: clamp(20px, 3.2vw, 38px); +} +.twb-radar-board { + width: 100%; + gap: clamp(18px, 3vw, 32px); +} +.twb-radar-main, +.twb-radar-figure { + display: grid; + place-items: center; + width: 100%; + min-width: 0; +} +.twb-radar-layout-overlay, +.twb-radar-layout-focus, +.twb-radar-layout-ranked { + grid-template-columns: minmax(0, 1.55fr) minmax(280px, .55fr) !important; +} +.twb-radar-layout-split { + grid-template-columns: repeat(auto-fit, minmax(min(430px, 100%), 1fr)) !important; +} +.twb-radar-layout-multiples { + grid-template-columns: 1fr !important; +} +.twb-radar-multiple-grid { + grid-template-columns: repeat(auto-fit, minmax(min(340px, 100%), 1fr)) !important; + gap: clamp(14px, 2.4vw, 24px) !important; +} +.twb-radar-multiple-grid article { + min-width: 0; + display: grid; + align-content: start; +} +.twb-radar-svg { + max-width: min(720px, 100%) !important; +} +.twb-radar-medium .twb-radar-svg { + max-width: min(560px, 100%) !important; +} +.twb-radar-small .twb-radar-svg, +.twb-radar-layout-multiples .twb-radar-small .twb-radar-svg { + max-width: min(430px, 100%) !important; +} +.twb-radar-label { + font-size: 13px !important; +} +.twb-radar-small .twb-radar-label { + font-size: 11px !important; +} +.twb-radar-side { + min-width: 0; + width: 100%; +} +.twb-radar-layout-multiples .twb-radar-side { + grid-column: 1 / -1; +} +.twb-radar-score-strip { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(min(190px, 100%), 1fr)); + gap: 10px; +} +.twb-radar-score-strip span, +.twb-radar-layout-multiples .twb-radar-score-strip span { + min-width: 0 !important; + align-content: center; +} +.twb-radar-values { + width: 100%; +} +@media (max-width: 1100px) { + .twb-radar-layout-overlay, + .twb-radar-layout-focus, + .twb-radar-layout-ranked { + grid-template-columns: 1fr !important; + } + .twb-radar-svg { + max-width: min(620px, 100%) !important; + } +} +@media (max-width: 760px) { + .twb-metrics-card .twb-dimension { + padding: 16px; + } + .twb-radar-svg, + .twb-radar-medium .twb-radar-svg, + .twb-radar-small .twb-radar-svg { + max-width: min(520px, 100%) !important; + } + .twb-radar-label, + .twb-radar-small .twb-radar-label { + font-size: 10px !important; + } + .twb-radar-multiple-grid { + grid-template-columns: 1fr !important; + } +} + +body .twb-doc[data-page="triworldbench"] #contact .contact-card, +body .twb-doc[data-page="triworldbench"] #contact .contact-card b, +body .twb-doc[data-page="triworldbench"] #contact .contact-card a, +body .twb-doc[data-page="triworldbench"] #contact .contact-card p, +body .twb-doc[data-page="triworldbench"] #contact .contact-card p span { + color: #000 !important; +} +/* radar-layout-expansion end */ + +/* radar-wide-layout-v2 start */ +.twb-rich > .twb-metrics-card { + grid-column: 1 / -1 !important; + width: 100% !important; + max-width: 100% !important; +} +.twb-metrics-card { + display: block !important; +} +.twb-metrics-card > .twb-rich-title, +.twb-metrics-card > .twb-metric-vis, +.twb-metrics-card > .twb-dimension { + width: 100% !important; + max-width: 100% !important; +} +.twb-metric-vis { + grid-template-columns: repeat(auto-fit, minmax(min(240px, 100%), 1fr)) !important; + margin-bottom: clamp(22px, 3vw, 42px); +} +.twb-metrics-card > .twb-dimension, +.twb-dimension { + display: block !important; + overflow: visible !important; + min-width: 0 !important; +} +.twb-radar-board { + width: 100% !important; + max-width: 100% !important; +} +.twb-radar-layout-overlay, +.twb-radar-layout-focus, +.twb-radar-layout-ranked { + grid-template-columns: minmax(520px, 1.45fr) minmax(260px, .55fr) !important; +} +.twb-radar-layout-split { + grid-template-columns: repeat(auto-fit, minmax(min(480px, 100%), 1fr)) !important; +} +.twb-radar-layout-multiples { + grid-template-columns: 1fr !important; +} +.twb-radar-multiple-grid { + grid-template-columns: repeat(auto-fit, minmax(min(360px, 100%), 1fr)) !important; + align-items: stretch; +} +.twb-radar-multiple-grid article { + min-width: 0 !important; +} +.twb-radar-svg { + max-width: min(760px, 100%) !important; +} +.twb-radar-medium .twb-radar-svg { + max-width: min(640px, 100%) !important; +} +.twb-radar-small .twb-radar-svg, +.twb-radar-layout-multiples .twb-radar-small .twb-radar-svg { + max-width: min(500px, 100%) !important; +} +.twb-radar-main { + min-height: 420px; +} +.twb-radar-layout-multiples .twb-radar-main, +.twb-radar-layout-split .twb-radar-main { + min-height: 0; +} +.twb-radar-label { + font-size: 14px !important; +} +.twb-radar-small .twb-radar-label { + font-size: 12px !important; +} +.twb-radar-score-strip { + grid-template-columns: repeat(auto-fit, minmax(min(210px, 100%), 1fr)) !important; +} +@media (max-width: 1180px) { + .twb-radar-layout-overlay, + .twb-radar-layout-focus, + .twb-radar-layout-ranked { + grid-template-columns: 1fr !important; + } + .twb-radar-main { + min-height: 0; + } +} +@media (max-width: 760px) { + .twb-metric-vis { + grid-template-columns: 1fr !important; + } + .twb-radar-multiple-grid { + grid-template-columns: 1fr !important; + } + .twb-radar-svg, + .twb-radar-medium .twb-radar-svg, + .twb-radar-small .twb-radar-svg { + max-width: min(540px, 100%) !important; + } +} +/* radar-wide-layout-v2 end */ + + +/* ============ TriWorldBench restructure-2030 additions ============ */ +/* hero with sci-fi background */ +.twb-hero { + position: relative; + overflow: hidden; + color: #e8fbff; + background: #06101a; + padding: clamp(48px, 9vw, 110px) clamp(20px, 5vw, 78px) clamp(38px, 5vw, 64px); +} +.twb-hero-bg { + position: absolute; + inset: 0; + z-index: 0; + background: + radial-gradient(circle at 18% 20%, rgba(58,230,255,.22), transparent 42%), + radial-gradient(circle at 82% 12%, rgba(121,247,178,.16), transparent 40%), + linear-gradient(180deg, #06101a 0%, #081a26 100%); +} +.twb-hero-bg::after { + content: ""; + position: absolute; + inset: 0; + background-image: + linear-gradient(rgba(58,230,255,.10) 1px, transparent 1px), + linear-gradient(90deg, rgba(58,230,255,.10) 1px, transparent 1px); + background-size: 46px 46px; + mask-image: radial-gradient(circle at 50% 30%, #000 0%, transparent 78%); + -webkit-mask-image: radial-gradient(circle at 50% 30%, #000 0%, transparent 78%); +} +.twb-hero-inner { position: relative; z-index: 1; max-width: 1440px; margin: 0 auto; } +.twb-hero .eyebrow { color: #79f7b2; font-size: 1rem; } +.twb-hero h1 { color: #e8fbff; font-size: clamp(3rem, 8vw, 7rem); } +.twb-accent { color: #3ae6ff; } +.twb-hero .subtitle { max-width: 1000px; font-size: clamp(1.1rem, 2vw, 1.5rem); opacity: .92; } +.twb-hero .actions a { border-color: #3ae6ff; background: #3ae6ff; color: #06101a; } +.twb-hero .actions a + a { background: transparent; color: #e8fbff; } +.twb-authors { margin-top: 30px; border-top: 1px solid rgba(58,230,255,.3); padding-top: 18px; } +.twb-authors-list { line-height: 2.1; font-size: 1.08rem; max-width: 1320px; } +.twb-authors-list a { color: #cdfcff; border-bottom: 1px dotted rgba(205,252,255,.5); } +.twb-authors-list a:hover { color: #3ae6ff; border-bottom-color: #3ae6ff; } +.twb-authors-list sup { color: #79f7b2; font-size: .68rem; } +.twb-affiliations { margin-top: 10px; display: flex; flex-wrap: wrap; gap: 6px 20px; font-size: .92rem; opacity: .82; } +.twb-affiliations sup { color: #79f7b2; margin-right: 2px; } + +/* advantages */ +.adv-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(260px, 100%), 1fr)); gap: 16px; margin-top: 22px; } +.adv-grid article { padding: 18px; border: 1px solid #0f766e; border-radius: 16px; background: #fff; display: grid; align-content: start; gap: 8px; } +.adv-tag { display: inline-flex; align-self: start; font-size: .72rem; font-weight: 800; text-transform: uppercase; letter-spacing: .04em; color: #0f766e; background: rgba(15,118,110,.1); padding: 4px 9px; border-radius: 999px; } + +/* video cases */ +.case-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 16px; } +.case-item { margin: 0; border: 1px solid #0f766e; border-radius: 16px; overflow: hidden; background: #06101a; display: grid; grid-template-rows: minmax(0, auto) auto; } +.case-item video { display: block; width: 100%; height: auto; object-fit: contain; background: #02060b; } +.case-item figcaption { padding: 10px 12px; font-size: .82rem; font-weight: 700; color: #eef7f5; background: #0f766e; overflow-wrap: anywhere; } + +/* metric leaders / recent highlights */ +.twb-sub { margin: 26px 0 12px; font-size: 1.05rem; color: #79f7b2; text-transform: uppercase; letter-spacing: .06em; } +.twb-leaders-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(220px, 100%), 1fr)); gap: 12px; } +.twb-leaders-grid article { padding: 14px; border: 1px solid rgba(121,247,178,.32); background: rgba(15,44,67,.84); border-radius: 12px; display: grid; gap: 4px; } +.twb-leaders-grid span { font-size: .72rem; text-transform: uppercase; letter-spacing: .05em; color: #79f7b2; } +.twb-leaders-grid b { font-size: 1rem; } +.twb-leaders-grid i { font-style: normal; font-weight: 900; font-size: 1.5rem; color: #3ae6ff; } +.twb-leaders-grid p { font-size: .8rem; opacity: .85; max-width: none; margin: 2px 0 0; } + +/* sticky first column in dense table */ +.twb-dense-table .twb-sticky-col { + position: sticky; + left: 0; + z-index: 3; + background: #0c1c28; +} +.twb-dense-table tbody tr:nth-child(odd) .twb-sticky-col { background: #102433; } +.twb-dense-table thead .twb-sticky-col { z-index: 4; background: #0a2030; } + +/* visualization metric selector */ +.twb-metric-selector { display: flex; flex-wrap: wrap; gap: 8px; margin: 18px 0; } +.ms-btn { border: 1px solid #3ae6ff; background: transparent; color: inherit; padding: 8px 14px; border-radius: 999px; font-weight: 700; font-size: .82rem; cursor: pointer; } +.ms-btn.is-active { background: #3ae6ff; color: #06101a; } +.twb-vis-panel { display: none; } +.twb-vis-panel.is-active { display: block; } +.twb-vis-panel h4 { margin: 0 0 12px; } +.twb-bar-list { display: grid; gap: 7px; } +.twb-bar-list span { + display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 10px; align-items: center; + padding: 8px 11px; min-height: 34px; + background: linear-gradient(90deg, #79f7b2 var(--v), rgba(121,247,178,.12) 0); + color: #06121c; font-weight: 700; border-radius: 6px; +} +.twb-bar-list span b { overflow-wrap: anywhere; font-size: .82rem; } +.twb-bar-list span i { font-style: normal; font-weight: 900; } +.twb-metric-glossary { margin-top: 22px; border: 1px solid rgba(58,230,255,.3); border-radius: 12px; padding: 12px 16px; } +.twb-metric-glossary summary { cursor: pointer; font-weight: 800; } +.twb-glossary-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(240px, 100%), 1fr)); gap: 12px; margin-top: 12px; } +.twb-glossary-grid div { display: grid; gap: 3px; } +.twb-glossary-grid b { font-size: .85rem; } +.twb-glossary-grid span { font-size: .8rem; opacity: .8; } + +/* datasets */ +.ds-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(260px, 100%), 1fr)); gap: 16px; margin-top: 20px; } +.ds-card { border: 1px solid #0f766e; border-radius: 16px; padding: 18px; background: #fff; display: grid; gap: 10px; align-content: start; } +.ds-head { display: flex; justify-content: space-between; align-items: baseline; gap: 10px; } +.ds-head b { font-size: 1.1rem; } +.ds-head span { font-size: .75rem; font-weight: 800; color: #0f766e; } +.ds-card ul { margin: 0; padding-left: 18px; font-size: .82rem; opacity: .82; display: grid; gap: 3px; } +.ds-actions, .ds-upload-actions { display: flex; flex-wrap: wrap; gap: 10px; } +.ds-btn { display: inline-flex; align-items: center; padding: 9px 16px; border: 1px solid #0f766e; background: #0f766e; color: #eef7f5; font-weight: 800; border-radius: 999px; font-size: .82rem; } +.ds-btn.ghost { background: transparent; color: #0f766e; } +.ds-upload { margin-top: 20px; padding: 20px; border: 1px dashed #0f766e; border-radius: 16px; background: rgba(15,118,110,.05); } +.ds-upload h3 { margin: 0 0 8px; } + +/* academic */ +.ac-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(300px, 100%), 1fr)); gap: 16px; margin-top: 20px; } +.ac-grid article { border: 1px solid #0f766e; border-radius: 16px; padding: 18px; background: #fff; } +.ac-grid ul { margin: 8px 0 0; padding-left: 18px; display: grid; gap: 6px; font-size: .9rem; } + +/* submission */ +.sub-card { display: grid; gap: 10px; margin: 18px 0; } +.sub-row { display: grid; grid-template-columns: minmax(120px, 180px) minmax(0, 1fr); gap: 12px; padding: 12px 14px; border: 1px solid #0f766e; border-radius: 12px; background: #fff; } +.sub-row b { color: #0f766e; } +.sub-row span { font-size: .88rem; } +.sub-host { margin-top: 12px; font-size: .9rem; } +.sub-table-wrap { width: 100%; overflow-x: auto; margin: 18px 0; border: 1px solid rgba(15,118,110,.35); border-radius: 14px; background: #fff; } +.sub-table { min-width: 680px; width: 100%; border-collapse: collapse; } +.sub-table th, +.sub-table td { padding: 12px 14px; border-bottom: 1px solid rgba(15,118,110,.18); vertical-align: top; text-align: left; } +.sub-table thead th, +.sub-table tbody th { color: #0f766e; font-weight: 900; background: rgba(15,118,110,.06); } +.sub-table tr:last-child th, +.sub-table tr:last-child td { border-bottom: 0; } +.sub-minor-title { margin-top: 26px; color: #0f766e; } +.sub-note { padding: 14px 16px; border-left: 4px solid #0f766e; background: #eef8f5; font-weight: 700; } +.sub-token { + display: inline-block; + margin: 0 2px; + padding: 1px 7px; + border: 1px solid rgba(15,118,110,.22); + border-radius: 999px; + background: #f4fbf8; + color: #0b635d; + font-family: inherit; + font-size: .86em; + font-weight: 800; + line-height: 1.65; + white-space: nowrap; +} +.sub-code { + overflow-x: auto; + padding: 16px 18px; + border: 1px solid rgba(15,118,110,.24); + border-radius: 14px; + background: #f7fbf8; + color: #173330; + font-family: "Cascadia Mono", "Cascadia Code", Consolas, "SFMono-Regular", "Liberation Mono", Menlo, monospace; + font-size: .9rem; + line-height: 1.58; + box-shadow: inset 0 0 0 1px rgba(255,255,255,.72); +} +.sub-list, +.sub-steps { display: grid; gap: 10px; padding-left: 22px; } +.sub-steps li { padding-left: 4px; } +.sub-steps b { color: #0f766e; } + +@media (max-width: 760px) { + .sub-row { grid-template-columns: 1fr; } + .twb-affiliations { font-size: .74rem; } + .case-grid { grid-template-columns: 1fr; } +} +/* ============ end TriWorldBench restructure-2030 additions ============ */ + +/* ============ TriWorldBench single-column layout fix ============ */ +/* The restructured page is a single-column document, NOT the dashboard grid. + Force one column and neutralize any inherited multi-column / grid-column rules. */ +.twb-doc main { + width: min(1180px, calc(100% - 34px)); + margin: 28px auto 70px; + display: block; /* override display:grid from base/dashboard rules */ +} +.twb-doc main > .section { + display: block; + width: 100%; + grid-column: auto !important; + grid-row: auto !important; + margin-bottom: 28px; + background: #fff; + border: 1px solid #0f766e; + border-radius: 16px; +} +/* keep the wide leaderboard table scrolling inside its column */ +.twb-doc .twb-table-wrap { max-width: 100%; overflow-x: auto; } +.twb-doc .twb-dense-table { min-width: 1600px; } +/* leaderboard section is dark-themed; keep its own bg */ +.twb-doc main > #leaderboard.twb-v02 { + background: #08131e; + border: 1px solid #3ae6ff; + color: #e8fbff; +} +/* harden leaderboard text colors so nothing renders white-on-white */ +#leaderboard.twb-v02 .twb-v02-top h2 { color: #3ae6ff; } +#leaderboard.twb-v02 .twb-v02-top span { color: #79f7b2; } +#leaderboard.twb-v02 .twb-sub { color: #79f7b2; } +#leaderboard.twb-v02 .twb-rich-card, +#leaderboard.twb-v02 .twb-overall { + background: rgba(15,44,67,.6); + border: 1px solid rgba(58,230,255,.3); + color: #e8fbff; +} +#leaderboard.twb-v02 .twb-rich-title span { color: #79f7b2; } +#leaderboard.twb-v02 .twb-rich-title h3, +#leaderboard.twb-v02 .twb-overall p { color: #e8fbff; } +/* dense table readable on dark */ +#leaderboard .twb-dense-table { color: #dff6ff; } +#leaderboard .twb-dense-table th { color: #cdfcff; background: rgba(58,230,255,.08); } +#leaderboard .twb-dense-table td { border-color: rgba(120,200,220,.18); } +#leaderboard .twb-best { color: #04140d; } +/* the section number + title row should stay horizontal */ +.twb-doc .section-head { grid-template-columns: auto minmax(0,1fr); align-items: baseline; } +/* ============ end single-column layout fix ============ */ + +/* ============ TriWorldBench modify-2030 additions ============ */ +/* overview bright keyword blocks (8) */ +.twb-keywords { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(180px,100%),1fr)); gap: 12px; margin-top: 24px; } +.twb-keywords b { + display: block; padding: 16px 18px; border-radius: 14px; font-weight: 900; font-size: .98rem; + color: #06121c; text-align: center; + background: linear-gradient(135deg, #79f7b2, #3ae6ff); + box-shadow: 0 6px 18px rgba(58,230,255,.25); +} + +/* why TriWorldBench — stronger vs comparison */ +.adv-vs { display: grid; grid-template-columns: 1fr auto 1fr; align-items: stretch; gap: 8px; margin-top: 6px; } +.adv-vs > span { display: grid; gap: 2px; align-content: center; padding: 10px 12px; border-radius: 12px; font-weight: 900; line-height: 1.1; } +.adv-vs small { display: block; font-weight: 600; font-size: .68rem; opacity: .85; } +.adv-them { background: #f1f5f9; color: #64748b; border: 1px dashed #cbd5e1; text-decoration: line-through; text-decoration-color: rgba(100,116,139,.5); } +.adv-them small { text-decoration: none; } +.adv-us { background: linear-gradient(135deg,#0f766e,#0ea5e9); color: #fff; } +.adv-vs em { align-self: center; font-style: normal; font-weight: 900; color: #0f766e; font-size: .8rem; } + +/* video case tabs */ +.case-tabs { display: flex; gap: 10px; margin: 18px 0 16px; flex-wrap: wrap; } +.case-tab { border: 1px solid #0f766e; background: transparent; color: #0f766e; padding: 9px 18px; border-radius: 999px; font-weight: 800; cursor: pointer; } +.case-tab.is-active { background: #0f766e; color: #eef7f5; } +.case-panel { display: none; } +.case-panel.is-active { + --case-card-estimate: clamp(250px, 25vw, 360px); + display: block; + max-height: var(--case-panel-max-height, calc((var(--case-card-estimate) * 2) + 16px)); + overflow-y: auto; + overflow-x: hidden; + padding-right: 6px; + scrollbar-gutter: stable; + -webkit-overflow-scrolling: touch; +} + +/* new reference-metric column tint */ +.twb-col-ref { background: color-mix(in srgb, #e11d48 9%, transparent); font-weight: 700; } +#leaderboard .twb-col-ref { background: rgba(244,63,94,.14); } + +/* overall radar (all models) */ +.twb-overall-radar { display: grid; grid-template-columns: minmax(320px,1.4fr) minmax(220px,.7fr); gap: 22px; align-items: start; margin: 18px 0 26px; } +.twb-radar-figure { margin: 0; } +.twb-radar-figure svg { display: block; width: 100%; max-width: 560px; margin: 0 auto; overflow: visible; } +.twb-radar-figure figcaption { text-align: center; font-size: .82rem; opacity: .7; margin-bottom: 6px; } +.twb-radar-legend-host h4 { margin: 0 0 10px; } +.twb-radar-legend-host .twb-radar-legend { max-height: 420px; overflow: auto; } +#leaderboard .twb-radar-scale, .visualization .twb-radar-scale { fill: currentColor; font-size: 9px; opacity: .55; } +.visualization .twb-radar-ring, .visualization .twb-radar-axis { fill: none; stroke: currentColor; opacity: .22; vector-effect: non-scaling-stroke; } +.visualization .twb-radar-label { fill: currentColor; font-size: 11px; font-weight: 800; text-anchor: middle; dominant-baseline: middle; } +.visualization .twb-radar-area { fill: var(--c); fill-opacity: .06; stroke: none; } +.visualization .twb-radar-line { fill: none; stroke: var(--c); stroke-width: 1.8; vector-effect: non-scaling-stroke; } + +/* per-metric split: bar list + radar */ +.twb-metric-split { display: grid; grid-template-columns: minmax(260px,1fr) minmax(260px,.85fr); gap: 20px; align-items: flex-start; } +.twb-metric-split figure { margin: 0; } +.twb-metric-split figcaption { font-size: .8rem; opacity: .7; text-align: center; margin-bottom: 6px; } +.twb-metric-split svg { display: block; width: 100%; max-width: 420px; margin: 0 auto; overflow: visible; } +@media (max-width: 820px) { .twb-overall-radar, .twb-metric-split { grid-template-columns: 1fr; } } + +/* academic lineage blocks */ +.ac-block h3 { margin: 0 0 14px; } +.ac-lineage { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(300px,100%),1fr)); gap: 16px; } +.ac-lineage article { border: 1px solid #0f766e; border-radius: 16px; padding: 18px; background: #fff; } +.ac-lineage article h4 { margin: 0 0 8px; color: #0f766e; font-size: 1.05rem; } +.ac-lineage .ac-goal { background: linear-gradient(135deg, rgba(15,118,110,.08), rgba(14,165,233,.08)); border-color: #0ea5e9; } + +/* optimization tips grid */ +.tips-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(240px,100%),1fr)); gap: 14px; margin-top: 6px; } +.tips-grid article { border: 1px solid #0f766e; border-radius: 14px; padding: 16px; background: #fff; } +.tips-grid b { display: block; color: #0f766e; margin-bottom: 6px; } +.tips-grid p { margin: 0; font-size: .9rem; } + +/* contact blocks */ +.contact-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(240px,100%),1fr)); gap: 16px; margin-top: 6px; } +.contact-card { border: 1px solid #0f766e; border-radius: 16px; padding: 18px; background: #fff; display: grid; gap: 6px; align-content: start; } +.contact-card span { font-size: .72rem; text-transform: uppercase; letter-spacing: .05em; color: #0f766e; font-weight: 800; } +.contact-card b { font-size: 1.1rem; } +.contact-card a { color: #0ea5e9; font-weight: 700; word-break: break-all; } +.contact-card p { margin: 4px 0 0; font-size: .86rem; opacity: .82; } +.contact-other { background: linear-gradient(135deg, rgba(15,118,110,.06), rgba(14,165,233,.06)); } +/* ============ end TriWorldBench modify-2030 additions ============ */ + +/* ============ TriWorldBench modify-2030 round-2 ============ */ +/* table 'best' as a solid highlight block (no text label) */ +#leaderboard .twb-best { + background: linear-gradient(180deg,#22c55e,#16a34a) !important; + color: #04140d !important; font-weight: 900; + box-shadow: inset 0 0 0 2px rgba(255,255,255,.25); +} + +/* shared visualization stage: radar full-width on top, then ranked | all-models */ +.twb-vis-stage { display: grid; gap: 20px; margin-top: 18px; } +.twb-vis-radar { margin: 0; width: 100%; } +.twb-vis-radar svg { display: block; width: 100%; max-width: 560px; margin: 0 auto; overflow: visible; } +.twb-vis-bottom { display: grid; grid-template-columns: 1.4fr 1fr; gap: 20px; align-items: start; } +@media (max-width: 820px) { .twb-vis-bottom { grid-template-columns: 1fr; } } +.twb-vis-ranked h4, .twb-vis-models h4 { margin: 0 0 10px; } +.twb-vis-models { background: rgba(15,44,67,.5); border: 1px solid rgba(58,230,255,.25); border-radius: 14px; padding: 14px; } +.twb-model-chips { display: flex; flex-direction: column; gap: 6px; max-height: 360px; overflow: auto; } +.twb-model-chip { + display: flex; align-items: center; gap: 9px; text-align: left; + border: 1px solid rgba(58,230,255,.25); background: transparent; color: inherit; + padding: 8px 11px; border-radius: 999px; cursor: pointer; font-weight: 700; font-size: .84rem; +} +.twb-model-chip i { width: 11px; height: 11px; border-radius: 50%; background: var(--c); flex: none; } +.twb-model-chip.is-active { background: var(--c); color: #04121c; border-color: var(--c); } + +/* radar series highlight / dim states */ +.visualization .twb-radar-series.is-dim { opacity: .14; } +.visualization .twb-radar-series.is-hl .twb-radar-line { stroke-width: 3.4; } +.visualization .twb-radar-series.is-hl .twb-radar-area { fill-opacity: .16; } +.visualization .twb-radar-spoke line { stroke: var(--c); stroke-width: 2.2; vector-effect: non-scaling-stroke; } +.visualization .twb-radar-spoke circle { fill: var(--c); } +.visualization .twb-radar-spoke.is-dim { opacity: .16; } +.visualization .twb-radar-spoke.is-hl line { stroke-width: 4; } +.visualization .twb-radar-ring { fill: none; } + +/* ranked bar highlight / dim */ +.visualization .twb-bar-list span.is-dim { opacity: .35; } +.visualization .twb-bar-list span.is-hl { outline: 2px solid #06121c; outline-offset: -2px; box-shadow: 0 4px 14px rgba(0,0,0,.18); } + +/* academic merged article (scrollable long-form) */ +.ac-article { max-width: 80ch; } +.ac-article h3 { margin: 0 0 12px; color: #0f766e; } +.ac-article p { margin: 0 0 14px; } + +/* section 12 other info */ +.other-info .coming { margin-top: 0; } +/* ============ end round-2 ============ */ + +/* ============ TriWorldBench modify-2030 round-3 ============ */ +/* visualization: overall radar | all-models on one row, then buttons, then bar chart */ +.twb-vis-top { display: grid; grid-template-columns: minmax(320px, 1.5fr) minmax(220px, .9fr); gap: 22px; align-items: stretch; margin: 18px 0; } +@media (max-width: 820px) { .twb-vis-top { grid-template-columns: 1fr; } } +.twb-vis-top .twb-vis-radar { margin: 0; display: grid; place-items: center; } +.twb-vis-top .twb-vis-radar svg { width: 100%; max-width: 520px; overflow: visible; } +.twb-vis-top .twb-vis-models { background: #f4fbfa; border: 1px solid #0f766e; } +.twb-vis-top .twb-vis-models .twb-model-chips { max-height: 420px; } +.twb-vis-top .twb-model-chip { color: #10201d; border-color: rgba(15,118,110,.4); } +.twb-vis-top .twb-model-chip.is-active { color: #04121c; } +.twb-metric-selector { margin-top: 4px; } +.twb-vis-ranked { margin-top: 8px; } + +/* per-dimension score values at radar vertices (highlighted model) */ +.visualization .twb-radar-vtx-val { + fill: #10201d; font-size: 11px; font-weight: 900; text-anchor: middle; + paint-order: stroke; stroke: #ffffff; stroke-width: 3px; +} +.visualization .twb-radar-vtx { stroke: #fff; stroke-width: 1.2; } + +/* metric definitions readable when open by default */ +.twb-metric-glossary[open] { background: #f4fbfa; } + +/* ---- lighten the 'overall board' (leaderboard) section: cleaner, brighter ---- */ +.twb-doc main > #leaderboard.twb-v02 { + background: #f3fbff !important; + border: 1px solid #cfe8ee !important; + color: #10201d !important; + box-shadow: 0 10px 30px rgba(15,118,110,.08); +} +#leaderboard.twb-v02 .twb-v02-top { border-bottom: 1px solid #cfe8ee; } +#leaderboard.twb-v02 .twb-v02-top h2 { color: #0f766e; } +#leaderboard.twb-v02 .twb-v02-top span { color: #0ea5e9; } +#leaderboard.twb-v02 .twb-sub { color: #0f766e; } +#leaderboard .twb-leaders-grid article { background: #ffffff; border: 1px solid #cfe8ee; } +#leaderboard .twb-leaders-grid span { color: #0f766e; } +#leaderboard .twb-leaders-grid b { color: #10201d; } +#leaderboard .twb-leaders-grid i { color: #0ea5e9; } +#leaderboard .twb-leaders-grid p { color: #314b48; } +#leaderboard.twb-v02 .twb-rich-card, +#leaderboard.twb-v02 .twb-overall { + background: #ffffff; + border: 1px solid #cfe8ee; + color: #10201d; +} +#leaderboard.twb-v02 .twb-rich-title span { color: #0f766e; } +#leaderboard.twb-v02 .twb-rich-title h3, +#leaderboard.twb-v02 .twb-overall p { color: #10201d; } +#leaderboard .twb-dense-table { color: #10201d; } +#leaderboard .twb-dense-table th { color: #0f766e; background: #eaf6f5; } +#leaderboard .twb-dense-table td { border-color: #e0eef0; } +#leaderboard .twb-dense-table .twb-sticky-col { background: #f7fcfd; } +#leaderboard .twb-dense-table tbody tr:nth-child(odd) .twb-sticky-col { background: #eef8f9; } +#leaderboard .twb-dense-table thead .twb-sticky-col { background: #eaf6f5; } +/* ============ end round-3 ============ */ + +/* ============ TriWorldBench modify-2030 round-4 ============ */ +/* academic merged article: fill the section width, two text columns on wide screens */ +.ac-article { max-width: 100%; } +.ac-article h3 { margin: 0 0 12px; color: #0f766e; } +.ac-article p { margin: 0 0 14px; font-size: 1rem; line-height: 1.7; } +.ac-article p:last-child { margin-bottom: 0; } +@media (min-width: 1000px) { + .ac-article { columns: 2; column-gap: 40px; } + .ac-article h3 { column-span: all; } + .ac-article p { break-inside: avoid; } +} + +/* All models header + Present All button */ +.twb-models-head { display: flex; align-items: center; justify-content: space-between; gap: 10px; margin-bottom: 10px; } +.twb-models-head h4 { margin: 0; } +.twb-present-all { + border: 1px solid #0f766e; background: #0f766e; color: #eef7f5; + padding: 6px 12px; border-radius: 999px; font-weight: 800; font-size: .78rem; cursor: pointer; + white-space: nowrap; +} +.twb-present-all:hover { background: #0ea5e9; border-color: #0ea5e9; } +/* ============ end round-4 ============ */ + +/* App Router container compatibility: pages render inside the root body. */ +.twb-doc { + min-height: 100vh; + font-family: Inter, Segoe UI, Arial, sans-serif; + color: #10201d; + background: #eef7f5; + line-height: 1.6; + max-width: 100%; + overflow-x: clip; +} +@supports not (overflow: clip) { + .twb-doc { overflow-x: hidden; } +} +.twb-doc h1, +.twb-doc .brand, +.twb-doc .eyebrow { + letter-spacing: 0; +} + +.i18n-zh, +html[data-twb-lang="en"] .i18n-zh, +html:not([data-twb-lang="zh"]) .i18n-zh { + display: none !important; +} +html[data-twb-lang="zh"] .i18n-en { + display: none !important; +} +html[data-twb-lang="zh"] .i18n-zh { + display: inline !important; +} +.language-menu { + position: relative; + flex: none; +} +.language-trigger { + display: inline-flex; + align-items: center; + gap: 8px; + min-height: 34px; + padding: 7px 12px; + border: 1px solid rgba(15,118,110,.45); + border-radius: 999px; + background: #f4fbfa; + color: #0f766e; + font: inherit; + font-size: .82rem; + font-weight: 900; + line-height: 1.1; + cursor: pointer; +} +.language-trigger b { + padding-left: 8px; + border-left: 1px solid rgba(15,118,110,.25); + color: #10201d; + font-weight: 800; +} +.language-options { + position: absolute; + top: calc(100% + 8px); + right: 0; + z-index: 40; + min-width: 150px; + padding: 7px; + border: 1px solid rgba(15,118,110,.28); + border-radius: 12px; + background: #fff; + box-shadow: 0 14px 32px rgba(15,43,40,.14); +} +.language-options button { + display: block; + width: 100%; + padding: 8px 10px; + border: 0; + border-radius: 8px; + background: transparent; + color: #10201d; + font: inherit; + font-size: .84rem; + font-weight: 800; + text-align: left; + cursor: pointer; +} +.language-options button:hover, +.language-options button.is-active { + background: #e8f6f4; + color: #0f766e; +} + +/* wider content frame for main and submission pages */ +.twb-doc main { + width: min(1440px, calc(100% - clamp(32px, 5vw, 96px))); +} +.twb-doc main > .section { + padding: clamp(30px, 4vw, 54px) clamp(28px, 4vw, 64px); +} +.twb-doc main > #overview, +.twb-doc main > #advantages { + padding-inline: clamp(36px, 5vw, 76px); +} +.twb-doc .section > p { + max-width: 1120px; +} +.twb-doc #overview > p, +.twb-doc #advantages > p { + max-width: 1180px; +} +.twb-keywords { + grid-template-columns: repeat(4, minmax(0, 1fr)); + gap: 14px; +} +.adv-grid { + grid-template-columns: repeat(4, minmax(0, 1fr)); + gap: 18px; +} +.sub-row { + grid-template-columns: minmax(220px, .32fr) minmax(0, 1fr); + padding: 14px 18px; +} +.sub-table { + min-width: 780px; +} +.sub-table tbody th { + width: clamp(210px, 24%, 320px); +} + +@media (max-width: 1180px) { + .twb-keywords, + .adv-grid { + grid-template-columns: repeat(2, minmax(0, 1fr)); + } +} + +@media (max-width: 760px) { + .twb-keywords, + .adv-grid { + grid-template-columns: 1fr; + } + .sub-row { + grid-template-columns: 1fr; + } +} + +/* mobile browsing polish */ +@media (max-width: 760px) { + .twb-doc .site-nav { + position: sticky; + padding: 12px 14px; + gap: 10px; + } + .twb-doc .site-nav nav { + width: 100%; + display: grid; + grid-template-columns: repeat(2, minmax(0, 1fr)); + gap: 6px; + font-size: .78rem; + } + .twb-doc .site-nav nav a { + min-width: 0; + text-align: center; + padding: 7px 6px; + } + .language-menu, + .language-trigger { + width: 100%; + } + .language-trigger { + justify-content: space-between; + } + .language-options { + left: 0; + right: 0; + } + .twb-hero { + min-height: auto; + padding: 38px 16px 34px; + } + .twb-hero h1 { + font-size: clamp(2.35rem, 16vw, 4rem); + line-height: 1; + } + .twb-hero .subtitle, + .twb-doc .section > p { + font-size: .98rem; + } + .twb-doc main { + width: min(100% - 22px, 1180px); + margin-top: 18px; + } + .twb-doc main > .section { + padding: 18px 14px; + border-radius: 14px; + margin-bottom: 18px; + } + .section-head { + gap: 9px; + } + .section-head h2 { + font-size: clamp(1.55rem, 9vw, 2.25rem); + line-height: 1.05; + } + .actions, + .ds-actions { + display: grid; + grid-template-columns: 1fr; + gap: 8px; + } + .actions a, + .ds-btn, + .twb-dataset-entry a { + justify-content: center; + width: 100%; + text-align: center; + } + .case-tabs { + display: grid; + grid-template-columns: repeat(2, minmax(0, 1fr)); + gap: 8px; + } + .case-tab { + width: 100%; + } + .case-grid { + grid-template-columns: 1fr; + gap: 12px; + } + .case-panel.is-active { + --case-card-estimate: clamp(230px, 70vw, 390px); + max-height: calc((var(--case-card-estimate) * 2) + 12px); + } + .case-item figcaption { + font-size: .76rem; + } + .twb-v02-top, + .twb-models-head { + align-items: stretch; + flex-direction: column; + } + .twb-metric-selector { + display: grid; + grid-template-columns: 1fr; + } + .ms-btn, + .twb-present-all { + width: 100%; + } + .twb-vis-top .twb-vis-radar svg { + max-width: 100%; + } + .twb-bar-list span { + grid-template-columns: 1fr; + gap: 3px; + } + .contact-grid { + grid-template-columns: 1fr; + } +} + +/* Final cascade guard: keep the public refresh authoritative over legacy rules. */ +.twb-doc[data-page="triworldbench"] { + color: var(--twb-ink); + background: #fff; + font-family: "Segoe UI Variable Text", Aptos, "Segoe UI", Arial, sans-serif; + line-height: 1.68; +} +.twb-doc[data-page="triworldbench"] .twb-hero .actions a { + border-color: var(--twb-ink) !important; + color: #fff !important; + background: var(--twb-ink) !important; +} +.twb-doc[data-page="triworldbench"] .twb-hero .actions a + a { + color: var(--twb-ink) !important; + background: #fff !important; +} +.twb-doc[data-page="triworldbench"] .twb-institutions { + justify-content: flex-start; +} +.twb-doc[data-page="triworldbench"] main { + width: min(1180px, calc(100% - 40px)); + margin: 0 auto 72px; +} +.twb-doc[data-page="triworldbench"] main > .section, +.twb-doc[data-page="triworldbench"] main > #leaderboard.twb-v02 { + margin: 0; + padding: 62px 0; + border: 0 !important; + border-top: 1px solid var(--twb-line) !important; + border-radius: 0 !important; + color: var(--twb-ink) !important; + background: transparent !important; + box-shadow: none !important; +} +.twb-doc[data-page="triworldbench"] main > #overview { + border-top: 0 !important; +} +.twb-doc[data-page="triworldbench"] #leaderboard .twb-v02-top { + border: 0 !important; +} +.twb-doc[data-page="triworldbench"] #leaderboard .twb-v02-top h2, +.twb-doc[data-page="triworldbench"] #leaderboard .twb-v02-top h2 > span { + color: var(--twb-ink) !important; + font-size: 32px !important; + font-weight: 780 !important; + line-height: 1.2 !important; + text-transform: none !important; +} +.twb-doc[data-page="triworldbench"] #leaderboard .twb-section-kicker, +.twb-doc[data-page="triworldbench"] #leaderboard .twb-v02-top > span { + color: var(--twb-accent) !important; + font-size: 12px !important; + text-transform: uppercase !important; +} +.twb-doc[data-page="triworldbench"] #leaderboard .twb-rich-card, +.twb-doc[data-page="triworldbench"] #leaderboard .twb-overall { + padding: 0; + border: 0; + color: var(--twb-ink); + background: transparent; +} +.twb-doc[data-page="triworldbench"] #leaderboard .twb-rich-title h3, +.twb-doc[data-page="triworldbench"] #leaderboard .twb-rich-title h3 > span { + color: var(--twb-ink) !important; + font-size: 20px !important; + line-height: 1.3 !important; + text-transform: none !important; +} +.twb-doc[data-page="triworldbench"] #leaderboard .twb-rich-title > span { + color: var(--twb-accent) !important; + font-size: 11px !important; + text-transform: uppercase !important; +} +.twb-doc[data-page="triworldbench"] #leaderboard .twb-dense-table, +.twb-doc[data-page="triworldbench"] #leaderboard .twb-dense-table td { + color: var(--twb-ink); + background: #fff; +} +.twb-doc[data-page="triworldbench"] #leaderboard .twb-dense-table th, +.twb-doc[data-page="triworldbench"] #leaderboard .twb-dense-table thead .twb-sticky-col, +.twb-doc[data-page="triworldbench"] #leaderboard .twb-dense-table thead .twb-sticky-rank { + color: #383e44; + background: #f3f4f5; +} +.twb-doc[data-page="triworldbench"] #leaderboard .twb-dense-table .twb-sticky-col, +.twb-doc[data-page="triworldbench"] #leaderboard .twb-dense-table .twb-sticky-rank, +.twb-doc[data-page="triworldbench"] #leaderboard .twb-dense-table tbody tr:nth-child(odd) .twb-sticky-col { + background: #fff; +} +.twb-doc[data-page="triworldbench"] #leaderboard .twb-best { + color: #09665f !important; + background: #e7f5f2 !important; + box-shadow: none !important; +} +.twb-doc[data-page="triworldbench"] .twb-vis-top { + grid-template-columns: minmax(0, 1.75fr) minmax(250px, .65fr); + gap: 28px; + margin: 30px 0 22px; +} +.twb-doc[data-page="triworldbench"] .twb-vis-top .twb-vis-radar { + min-height: 620px; +} +.twb-doc[data-page="triworldbench"] .twb-vis-top .twb-vis-radar svg { + width: min(700px, 100%); + max-width: none; +} +.twb-doc[data-page="triworldbench"] .twb-vis-top .twb-vis-models { + padding: 15px; + border: 1px solid #d8dcdf; + border-radius: 6px; + color: var(--twb-ink); + background: rgba(255, 255, 255, .9); +} +.twb-doc[data-page="triworldbench"] .twb-vis-top .twb-model-chips { + max-height: 540px; + gap: 4px; +} +.twb-doc[data-page="triworldbench"] .twb-present-all, +.twb-doc[data-page="triworldbench"] .twb-model-chip, +.twb-doc[data-page="triworldbench"] .ms-btn, +.twb-doc[data-page="triworldbench"] .case-tab { + border-radius: 4px !important; +} +.twb-doc[data-page="triworldbench"] .twb-present-all, +.twb-doc[data-page="triworldbench"] .twb-model-chip, +.twb-doc[data-page="triworldbench"] .ms-btn { + min-height: 34px; + border-color: #cbd0d4; + color: #4f565c; + background: #fff; + font-size: 12px; +} +.twb-doc[data-page="triworldbench"] .twb-present-all { + padding: 6px 11px; + color: #fff; + background: var(--twb-ink); +} +.twb-doc[data-page="triworldbench"] .twb-present-all:hover { + border-color: var(--twb-ink); + color: #fff; + background: #30353a; +} +.twb-doc[data-page="triworldbench"] .twb-model-chip { + height: auto; + min-height: 36px; + padding: 8px 9px; + line-height: 1.25; +} +.twb-doc[data-page="triworldbench"] .twb-model-chip:hover, +.twb-doc[data-page="triworldbench"] .ms-btn:hover { + border-color: #8e969c; + background: var(--twb-soft); +} +.twb-doc[data-page="triworldbench"] .twb-model-chip.is-active, +.twb-doc[data-page="triworldbench"] .ms-btn.is-active { + border-color: var(--twb-ink); + color: #fff; + background: var(--twb-ink); +} +.twb-doc[data-page="triworldbench"] .twb-filter-control { + grid-template-columns: 70px minmax(0, 1fr); +} +.twb-doc[data-page="triworldbench"] .twb-metric-selector { + display: flex; + margin: 0; + flex-wrap: wrap; + gap: 5px; +} +.twb-doc[data-page="triworldbench"] .ms-btn { + width: auto; + padding: 6px 10px; +} +.twb-doc[data-page="triworldbench"] .twb-bar-list span { + border: 1px solid #e1e4e6; + border-radius: 4px; + color: #252a2f; + background: #f4f5f6; +} + +@media (max-width: 760px) { + .twb-doc[data-page="triworldbench"] .site-nav { + grid-template-columns: 1fr auto; + padding: 10px 14px; + } + .twb-doc[data-page="triworldbench"] .site-nav nav { + grid-column: 1 / -1; + display: grid; + grid-template-columns: repeat(2, minmax(0, 1fr)); + } + .twb-doc[data-page="triworldbench"] .language-menu { + width: auto; + } + .twb-doc[data-page="triworldbench"] .twb-hero { + padding: 42px 16px 34px; + } + .twb-doc[data-page="triworldbench"] .twb-hero h1 { + font-size: 44px; + line-height: 1.08; + } + .twb-doc[data-page="triworldbench"] main { + width: calc(100% - 28px); + margin: 0 auto 48px; + } + .twb-doc[data-page="triworldbench"] main > .section, + .twb-doc[data-page="triworldbench"] main > #leaderboard.twb-v02 { + margin: 0; + padding: 42px 0; + border-radius: 0 !important; + } + .twb-doc[data-page="triworldbench"] .twb-v02-top { + align-items: flex-start; + } + .twb-doc[data-page="triworldbench"] #leaderboard .twb-v02-top h2, + .twb-doc[data-page="triworldbench"] #leaderboard .twb-v02-top h2 > span { + font-size: 27px !important; + } + .twb-doc[data-page="triworldbench"] .twb-vis-top { + grid-template-columns: 1fr; + } + .twb-doc[data-page="triworldbench"] .twb-vis-top .twb-vis-radar { + min-height: 430px; + } + .twb-doc[data-page="triworldbench"] .twb-filter-control { + grid-template-columns: 1fr; + } + .twb-doc[data-page="triworldbench"] .twb-metric-selector { + display: grid; + grid-template-columns: repeat(2, minmax(0, 1fr)); + } + .twb-doc[data-page="triworldbench"] .ms-btn, + .twb-doc[data-page="triworldbench"] .twb-present-all { + width: 100%; + } +} + +/* Updated PAGES requirements: Editorial typography and neutral visual system. */ +.twb-doc[data-page="triworldbench"] { + --twb-ink: #1a1a1a; + --twb-muted: #666; + --twb-line: #e5e7eb; + --twb-soft: #f0f1f3; + --twb-accent: #4b5563; + --twb-link: #2563eb; + color: var(--twb-ink); + background: #fff; + font-family: Inter, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; + font-size: 16px; + line-height: 1.6; +} +.twb-doc[data-page="triworldbench"]::before { + content: "TriWorldBench"; + top: 50%; + color: rgba(26, 26, 26, .035); + font-family: "Source Serif 4", Georgia, serif; + font-size: 112px; + font-style: normal; + font-weight: 700; + transform: translate(-50%, -50%); +} +.twb-doc[data-page="triworldbench"] .site-nav .brand, +.twb-doc[data-page="triworldbench"] .twb-hero h1, +.twb-doc[data-page="triworldbench"] .section-head h2, +.twb-doc[data-page="triworldbench"] .twb-v02-top h2 { + font-family: "Source Serif 4", Georgia, serif; +} +.twb-doc[data-page="triworldbench"] .site-nav .brand { + font-size: 21px; + font-weight: 700; +} +.twb-doc[data-page="triworldbench"] .site-nav nav a { + color: #4f4f4f; + font-size: 14px; + font-weight: 500; + line-height: 1.6; +} +.twb-doc[data-page="triworldbench"] .site-nav nav a:hover, +.twb-doc[data-page="triworldbench"] .site-nav nav a:focus-visible { + color: var(--twb-ink); + background: var(--twb-soft); +} +.twb-doc[data-page="triworldbench"] .language-menu { + width: fit-content; + padding: 3px; + border: 0; + border-radius: 8px; + background: var(--twb-soft); +} +.twb-doc[data-page="triworldbench"] .language-menu > button { + min-height: 34px; + padding: 7px 14px; + border: 0; + border-radius: 6px; + color: #666; + background: transparent; + font-size: 12px; + font-weight: 500; +} +.twb-doc[data-page="triworldbench"] .language-menu > button.is-active { + color: #fff; + background: var(--twb-ink); +} + +/* Editorial title hierarchy. */ +.twb-doc[data-page="triworldbench"] .twb-hero { + padding: 64px 24px 52px; +} +.twb-doc[data-page="triworldbench"] .twb-hero .eyebrow { + color: #666; + font-size: 13px; + font-weight: 600; +} +.twb-doc[data-page="triworldbench"] .twb-hero h1 { + max-width: 1000px; + color: var(--twb-ink); + font-size: 52px; + font-weight: 700; + line-height: 1.3; +} +.twb-doc[data-page="triworldbench"] .twb-accent { + display: inline-block; + margin-top: 2px; + color: #333; + font-family: Inter, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; + font-size: 26px; + font-weight: 600; + line-height: 1.35; +} +.twb-doc[data-page="triworldbench"] .twb-hero .subtitle { + max-width: 900px; + color: #555; + font-size: 16px; + font-weight: 400; + line-height: 1.6; +} +.twb-doc[data-page="triworldbench"] .twb-hero .actions a, +.twb-doc[data-page="triworldbench"] .actions a, +.twb-doc[data-page="triworldbench"] .ds-btn { + min-height: 38px; + padding: 8px 16px; + border: 1px solid var(--twb-ink) !important; + border-radius: 8px; + color: #fff !important; + background: var(--twb-ink) !important; + font-size: 13px; + font-weight: 600; + line-height: 1.4; + box-shadow: 0 3px 8px rgba(0, 0, 0, .12); +} +.twb-doc[data-page="triworldbench"] .twb-hero .actions a + a { + color: var(--twb-ink) !important; + background: #fff !important; +} +.twb-doc[data-page="triworldbench"] .twb-authors-list { + color: #333; + font-size: 15px; + line-height: 1.6; +} +.twb-doc[data-page="triworldbench"] .twb-authors-list a { + color: var(--twb-link); +} +.twb-doc[data-page="triworldbench"] .twb-affiliations { + color: #777; + font-size: 14px; + line-height: 1.6; +} +.twb-doc[data-page="triworldbench"] .twb-affiliations sup { + color: #777; +} + +/* Institution logos: all visible, no frames or captions. */ +.twb-doc[data-page="triworldbench"] .twb-institutions { + width: 100%; + max-width: 1120px; + align-items: center; + justify-content: center; + flex-wrap: wrap; + gap: 22px 34px; + overflow: visible; + padding: 10px 0 0; +} +.twb-doc[data-page="triworldbench"] .twb-institutions > a, +.twb-doc[data-page="triworldbench"] .twb-institutions > div { + display: grid; + flex: 0 1 190px; + min-height: 88px; + grid-template-rows: none; + place-items: center; + padding: 0; + border: 0; + border-radius: 0; + color: #333; + background: transparent; +} +.twb-doc[data-page="triworldbench"] .twb-institutions > a:hover { + border: 0; + background: transparent; + opacity: .72; +} +.twb-doc[data-page="triworldbench"] .twb-institutions img { + width: 220px; + max-width: 100%; + height: 80px; + object-fit: contain; +} +.twb-doc[data-page="triworldbench"] .twb-institution-mark { + width: 84px; + height: 84px; + border: 0; + border-radius: 0; + color: #333; + background: transparent; + font-size: 25px; + font-weight: 700; +} + +/* Shared document typography. */ +.twb-doc[data-page="triworldbench"] main > .section, +.twb-doc[data-page="triworldbench"] main > #leaderboard.twb-v02 { + padding: 58px 0; +} +.twb-doc[data-page="triworldbench"] main > #overview, +.twb-doc[data-page="triworldbench"] main > #advantages { + padding-inline: 0 !important; +} +.twb-doc[data-page="triworldbench"] .section-head { + grid-template-columns: 34px minmax(0, 1fr); + gap: 8px; + margin-bottom: 20px; +} +.twb-doc[data-page="triworldbench"] .section-head > span { + color: #888; + font-size: 12px; + font-weight: 600; +} +.twb-doc[data-page="triworldbench"] .section-head h2, +.twb-doc[data-page="triworldbench"] .section-head h2 > span, +.twb-doc[data-page="triworldbench"] #leaderboard .twb-v02-top h2, +.twb-doc[data-page="triworldbench"] #leaderboard .twb-v02-top h2 > span { + color: var(--twb-ink) !important; + font-size: 26px !important; + font-weight: 700 !important; + line-height: 1.5 !important; + text-transform: none !important; +} +.twb-doc[data-page="triworldbench"] .section > p, +.twb-doc[data-page="triworldbench"] .section li, +.twb-doc[data-page="triworldbench"] .ac-article p { + color: #555; + font-size: 16px; + line-height: 1.65; +} +.twb-doc[data-page="triworldbench"] main h3, +.twb-doc[data-page="triworldbench"] main h4, +.twb-doc[data-page="triworldbench"] main strong, +.twb-doc[data-page="triworldbench"] main b, +.twb-doc[data-page="triworldbench"] main time { + color: var(--twb-ink); +} +.twb-doc[data-page="triworldbench"] main a { + color: var(--twb-ink); +} + +/* Overview light-gray content blocks. */ +.twb-doc[data-page="triworldbench"] #overview .case-intro { + padding: 18px 20px; + border: 0; + border-radius: 8px; + color: #444; + background: #f1f2f3; +} +.twb-doc[data-page="triworldbench"] #overview .twb-keywords { + display: grid; + grid-template-columns: repeat(4, minmax(0, 1fr)); + gap: 10px; +} +.twb-doc[data-page="triworldbench"] #overview .twb-keywords b { + display: grid; + min-height: 52px; + place-items: center; + padding: 10px 12px; + border: 0; + border-radius: 8px; + color: #444; + background: #f1f2f3; + font-size: 13px; + font-weight: 600; + line-height: 1.4; + text-align: center; + box-shadow: none; +} + +/* Why TriWorldBench: four equal gray blocks with gray secondary blocks. */ +.twb-doc[data-page="triworldbench"] #advantages .adv-grid { + grid-template-columns: repeat(4, minmax(0, 1fr)); + align-items: stretch; + gap: 14px; + margin-top: 26px; +} +.twb-doc[data-page="triworldbench"] #advantages .adv-grid article { + display: grid; + min-width: 0; + grid-template-rows: auto 1fr auto; + gap: 12px; + padding: 24px 18px 18px; + border: 1px solid #e5e7eb; + border-radius: 8px; + color: var(--twb-ink); + background: #f8f8f9; +} +.twb-doc[data-page="triworldbench"] #advantages .adv-grid article h3 { + margin: 0; + color: var(--twb-ink); + font-family: "Source Serif 4", Georgia, serif; + font-size: 20px; + font-weight: 700; + line-height: 1.35; + text-align: center; +} +.twb-doc[data-page="triworldbench"] #advantages .adv-grid article > p { + margin: 0; + color: #5f5f5f; + font-size: 14px; + line-height: 1.6; + text-align: center; +} +.twb-doc[data-page="triworldbench"] #advantages .adv-vs { + grid-template-columns: minmax(0, 1fr) 24px minmax(0, 1fr); + gap: 5px; + padding-top: 4px; +} +.twb-doc[data-page="triworldbench"] #advantages .adv-vs > span { + min-height: 68px; + padding: 9px 8px; + border: 0 !important; + border-radius: 6px; + color: #444; + background: #e9eaec !important; + font-size: 12px; + font-weight: 600; + line-height: 1.3; + text-align: center; + text-decoration: none; +} +.twb-doc[data-page="triworldbench"] #advantages .adv-vs .adv-us { + color: #222; + background: #dfe1e4 !important; +} +.twb-doc[data-page="triworldbench"] #advantages .adv-vs small { + color: #666; + font-size: 11px; + font-weight: 400; +} +.twb-doc[data-page="triworldbench"] #advantages .adv-vs em { + color: #777; + font-size: 11px; +} + +/* Visualization Cases: compact Editorial controls and unframed videos. */ +.twb-doc[data-page="triworldbench"] #cases > p { + color: #666; + font-size: 15px; + line-height: 1.6; +} +.twb-doc[data-page="triworldbench"] .case-tabs { + display: inline-flex !important; + width: fit-content; + max-width: 100%; + gap: 0; + margin: 18px 0 16px; + padding: 3px; + border: 0 !important; + border-radius: 8px; + background: var(--twb-soft); +} +.twb-doc[data-page="triworldbench"] .case-tab { + width: auto; + min-width: 94px; + min-height: 36px; + padding: 7px 16px; + border: 0 !important; + border-radius: 6px !important; + color: #666; + background: transparent; + font-family: Inter, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; + font-size: 12px; + font-weight: 500; +} +.twb-doc[data-page="triworldbench"] .case-tab:hover { + color: var(--twb-ink); +} +.twb-doc[data-page="triworldbench"] .case-tab.is-active { + color: #fff; + background: var(--twb-ink); +} +.twb-doc[data-page="triworldbench"] .case-grid { + grid-template-columns: repeat(2, minmax(0, 1fr)); + gap: 20px 18px; +} +.twb-doc[data-page="triworldbench"] .case-item, +.twb-doc[data-page="triworldbench"] .case-item:hover { + overflow: visible; + border: 0 !important; + border-radius: 0; + background: transparent; + box-shadow: none; + transform: none !important; +} +.twb-doc[data-page="triworldbench"] .case-item video { + display: block; + width: 100%; + border: 1px solid #eee; + border-radius: 8px; + background: #111; +} +.twb-doc[data-page="triworldbench"] .case-item figcaption { + min-height: 0; + padding: 7px 4px 0; + color: var(--twb-ink); + background: transparent !important; + font-size: 14px; + font-weight: 600; + line-height: 1.4; + text-align: center; +} + +/* Editorial leaderboard table, without model icons. */ +.twb-doc[data-page="triworldbench"] #leaderboard .twb-section-kicker { + display: none; +} +.twb-doc[data-page="triworldbench"] #leaderboard .twb-v02-top { + align-items: baseline; + padding-bottom: 18px; +} +.twb-doc[data-page="triworldbench"] #leaderboard .twb-v02-top > span { + color: #777 !important; + font-size: 12px !important; + font-weight: 500; + text-transform: none !important; +} +.twb-doc[data-page="triworldbench"] #leaderboard .twb-board-note { + max-width: 940px; + margin: 0 0 16px; + color: #666; + font-size: 15px; + line-height: 1.6; +} +.twb-doc[data-page="triworldbench"] #leaderboard .twb-table-wrap { + border: 1px solid #e5e7eb; + border-radius: 8px; + background: #fff; +} +.twb-doc[data-page="triworldbench"] #leaderboard .twb-dense-table { + min-width: 2320px; + color: var(--twb-ink); + font-family: "JetBrains Mono", Consolas, monospace; + font-size: 14px; +} +.twb-doc[data-page="triworldbench"] #leaderboard .twb-dense-table th { + min-width: 104px; + padding: 12px; + color: #444; + background: #f5f7fa; + font-family: Inter, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; + font-size: 11px; + font-weight: 700; + line-height: 1.6; +} +.twb-doc[data-page="triworldbench"] #leaderboard .twb-dense-table td { + min-width: 104px; + padding: 14px; + border-right: 1px solid #eee; + border-bottom: 1px solid #eee; + color: var(--twb-ink); + background: #fff !important; + font-size: 14px; + line-height: 1.6; +} +.twb-doc[data-page="triworldbench"] #leaderboard .twb-dense-table tbody tr:hover td, +.twb-doc[data-page="triworldbench"] #leaderboard .twb-dense-table tbody tr:hover .twb-sticky-col, +.twb-doc[data-page="triworldbench"] #leaderboard .twb-dense-table tbody tr:hover .twb-sticky-rank { + background: #f0f1f3 !important; +} +.twb-doc[data-page="triworldbench"] #leaderboard .twb-sticky-rank, +.twb-doc[data-page="triworldbench"] #leaderboard .twb-sticky-col { + background: #fff !important; +} +.twb-doc[data-page="triworldbench"] #leaderboard thead .twb-sticky-rank, +.twb-doc[data-page="triworldbench"] #leaderboard thead .twb-sticky-col { + background: #f5f7fa !important; +} +.twb-doc[data-page="triworldbench"] #leaderboard .twb-sticky-col { + min-width: 205px !important; + max-width: 250px; + font-family: Inter, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; +} +.twb-doc[data-page="triworldbench"] #leaderboard .twb-sticky-col b { + color: var(--twb-ink); + font-size: 14px; + font-weight: 600; + line-height: 1.4; +} +.twb-doc[data-page="triworldbench"] #leaderboard .twb-sticky-col small { + margin-top: 3px; + color: #888; + font-size: 11px; + font-weight: 400; + line-height: 1.4; +} +.twb-doc[data-page="triworldbench"] #leaderboard .twb-col-status { + color: #666; + font-family: Inter, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; + font-size: 12px; +} +.twb-doc[data-page="triworldbench"] #leaderboard .twb-best, +.twb-doc[data-page="triworldbench"] #leaderboard .twb-col-ref { + color: var(--twb-ink) !important; + background: #fff !important; + box-shadow: none !important; +} +.twb-doc[data-page="triworldbench"] .twb-rank-badge { + width: 34px; + height: 34px; + border-radius: 6px; + font-size: 13px; +} +.twb-doc[data-page="triworldbench"] .twb-score-value { + font-weight: 500; +} +.twb-doc[data-page="triworldbench"] .twb-cell-rank { + display: inline-block; + margin-left: 6px; + color: #999; + font-family: "JetBrains Mono", Consolas, monospace; + font-size: 10px; + font-weight: 500; + line-height: 1; +} +.twb-doc[data-page="triworldbench"] .twb-cell-rank.rank-1 { color: #9a6d00; } +.twb-doc[data-page="triworldbench"] .twb-cell-rank.rank-2 { color: #6b7280; } +.twb-doc[data-page="triworldbench"] .twb-cell-rank.rank-3 { color: #9a5c36; } + +/* Visualization controls, larger radar, line patterns, and muted bars. */ +.twb-doc[data-page="triworldbench"] .twb-vis-top { + grid-template-columns: minmax(0, 1.85fr) minmax(250px, .55fr); + gap: 24px; +} +.twb-doc[data-page="triworldbench"] .twb-vis-top .twb-vis-radar { + min-height: 720px; +} +.twb-doc[data-page="triworldbench"] .twb-vis-top .twb-vis-radar svg { + width: min(780px, 100%); + max-width: none; +} +.twb-doc[data-page="triworldbench"] .twb-vis-top .twb-vis-models { + padding: 10px; + border: 0; + border-radius: 8px; + color: var(--twb-ink); + background: var(--twb-soft); +} +.twb-doc[data-page="triworldbench"] .twb-models-head h4, +.twb-doc[data-page="triworldbench"] .twb-vis-ranked h4, +.twb-doc[data-page="triworldbench"] .twb-metric-glossary summary, +.twb-doc[data-page="triworldbench"] .twb-glossary-grid b { + color: var(--twb-ink); +} +.twb-doc[data-page="triworldbench"] .twb-present-all, +.twb-doc[data-page="triworldbench"] .twb-model-chip, +.twb-doc[data-page="triworldbench"] .ms-btn { + border: 0; + border-radius: 6px !important; + color: #666; + background: transparent; + font-size: 12px; + font-weight: 500; +} +.twb-doc[data-page="triworldbench"] .twb-present-all, +.twb-doc[data-page="triworldbench"] .twb-model-chip.is-active, +.twb-doc[data-page="triworldbench"] .ms-btn.is-active { + color: #fff; + background: var(--twb-ink); +} +.twb-doc[data-page="triworldbench"] .twb-model-chip:hover, +.twb-doc[data-page="triworldbench"] .ms-btn:hover { + color: var(--twb-ink); + background: #fff; +} +.twb-doc[data-page="triworldbench"] .twb-model-chip.is-active:hover, +.twb-doc[data-page="triworldbench"] .ms-btn.is-active:hover { + color: #fff; + background: var(--twb-ink); +} +.twb-doc[data-page="triworldbench"] .twb-model-chip { + min-height: 36px; + padding: 8px 10px; +} +.twb-doc[data-page="triworldbench"] .twb-model-chip i { + width: 18px; + height: 3px; + border-radius: 2px; +} +.twb-doc[data-page="triworldbench"] .twb-filter-control { + display: flex; + width: 100%; + grid-template-columns: none; + align-items: center; + gap: 0; + padding: 3px; + border: 0; + border-radius: 8px; + background: var(--twb-soft); +} +.twb-doc[data-page="triworldbench"] .twb-filter-label { + flex: none; + padding: 0 10px; + color: #666; + font-size: 12px; + font-weight: 600; +} +.twb-doc[data-page="triworldbench"] .twb-metric-selector { + display: flex; + flex: 1; + margin: 0; + flex-wrap: wrap; + gap: 0; +} +.twb-doc[data-page="triworldbench"] .ms-btn { + width: auto; + min-height: 36px; + padding: 7px 12px; +} +.twb-doc[data-page="triworldbench"] .visualization .twb-radar-label, +.twb-doc[data-page="triworldbench"] .visualization .twb-radar-scale, +.twb-doc[data-page="triworldbench"] .visualization .twb-radar-vtx-val { + fill: #333; +} +.twb-doc[data-page="triworldbench"] .visualization .twb-radar-line { + stroke-dasharray: var(--dash, none); + stroke-linecap: round; +} +.twb-doc[data-page="triworldbench"] .twb-bar-list span { + color: #333; + background: #eceef0; +} +.twb-doc[data-page="triworldbench"] .twb-bar-list span::before { + background: color-mix(in srgb, var(--c) 12%, #d6d9dd); +} +.twb-doc[data-page="triworldbench"] .twb-bar-list span.is-hl::before { + background: color-mix(in srgb, var(--c) 64%, #fff); +} +.twb-doc[data-page="triworldbench"] .twb-bar-list span.is-hl { + opacity: 1; + outline: 2px solid #333; + box-shadow: none; +} +.twb-doc[data-page="triworldbench"] .twb-metric-glossary, +.twb-doc[data-page="triworldbench"] .twb-metric-glossary[open] { + border: 1px solid #e5e7eb; + border-radius: 8px; + color: #444; + background: #f7f7f8; +} +.twb-doc[data-page="triworldbench"] .twb-glossary-grid span { + color: #666; + font-size: 13px; + line-height: 1.55; +} + +/* Neutral content blocks and corrected dataset action. */ +.twb-doc[data-page="triworldbench"] .timeline article, +.twb-doc[data-page="triworldbench"] .date-grid article, +.twb-doc[data-page="triworldbench"] .sub-row, +.twb-doc[data-page="triworldbench"] .contact-card, +.twb-doc[data-page="triworldbench"] .citation-code, +.twb-doc[data-page="triworldbench"] .coming { + border-color: #e5e7eb; + color: #444; + background: #f7f7f8; +} +.twb-doc[data-page="triworldbench"] .timeline time, +.twb-doc[data-page="triworldbench"] .contact-card > span, +.twb-doc[data-page="triworldbench"] .sub-row > i, +.twb-doc[data-page="triworldbench"] .ac-article h3 { + color: #666; +} +.twb-doc[data-page="triworldbench"] .ds-actions { + display: flex; + width: fit-content; + max-width: 100%; +} +.twb-doc[data-page="triworldbench"] .ds-btn { + width: fit-content !important; + max-width: 100%; + text-align: center; + text-decoration: none; +} + +@media (max-width: 1000px) { + .twb-doc[data-page="triworldbench"] #advantages .adv-grid, + .twb-doc[data-page="triworldbench"] #overview .twb-keywords { + grid-template-columns: repeat(2, minmax(0, 1fr)); + } + .twb-doc[data-page="triworldbench"] .twb-vis-top { + grid-template-columns: 1fr; + } + .twb-doc[data-page="triworldbench"] .twb-vis-top .twb-vis-radar { + min-height: 650px; + } +} + +@media (max-width: 760px) { + .twb-doc[data-page="triworldbench"]::before { + font-size: 54px; + } + .twb-doc[data-page="triworldbench"] .twb-hero h1 { + font-size: 42px; + } + .twb-doc[data-page="triworldbench"] .twb-accent { + font-size: 22px; + } + .twb-doc[data-page="triworldbench"] .section-head h2, + .twb-doc[data-page="triworldbench"] .section-head h2 > span, + .twb-doc[data-page="triworldbench"] #leaderboard .twb-v02-top h2, + .twb-doc[data-page="triworldbench"] #leaderboard .twb-v02-top h2 > span { + font-size: 25px !important; + } + .twb-doc[data-page="triworldbench"] #advantages .adv-grid, + .twb-doc[data-page="triworldbench"] #overview .twb-keywords, + .twb-doc[data-page="triworldbench"] .case-grid { + grid-template-columns: 1fr; + } + .twb-doc[data-page="triworldbench"] #advantages .adv-grid article { + padding: 22px 18px 18px; + } + .twb-doc[data-page="triworldbench"] .case-tabs { + display: inline-flex !important; + width: fit-content; + } + .twb-doc[data-page="triworldbench"] .case-tab { + width: auto; + } + .twb-doc[data-page="triworldbench"] .twb-vis-top .twb-vis-radar { + min-height: 440px; + } + .twb-doc[data-page="triworldbench"] .twb-filter-control { + display: grid; + grid-template-columns: 1fr; + padding: 6px; + } + .twb-doc[data-page="triworldbench"] .twb-filter-label { + padding: 4px 7px 6px; + } + .twb-doc[data-page="triworldbench"] .twb-metric-selector { + display: grid; + grid-template-columns: repeat(2, minmax(0, 1fr)); + gap: 2px; + } + .twb-doc[data-page="triworldbench"] .ms-btn { + width: 100%; + } + .twb-doc[data-page="triworldbench"] .ds-btn { + width: fit-content !important; + } +} + +/* Navigation and anchor guard after legacy flex-wrap declarations. */ +.twb-doc[data-page="triworldbench"] .site-nav nav { + display: flex; + max-height: 38px; + flex-wrap: nowrap; + justify-content: center; + gap: 2px; + overflow-x: auto; +} +.twb-doc[data-page="triworldbench"] .site-nav nav a { + padding-inline: 6px; +} +.twb-doc[data-page="triworldbench"] main > section, +.twb-doc[data-page="triworldbench"] #top { + scroll-margin-top: 72px; +} +.twb-doc[data-page="triworldbench"] .twb-glossary-grid b, +.twb-doc[data-page="triworldbench"] .twb-glossary-grid span { + font-size: 14px; +} + +@media (max-width: 760px) { + .twb-doc[data-page="triworldbench"] .site-nav nav { + display: flex; + max-height: 40px; + grid-column: 1 / -1; + flex-wrap: nowrap; + justify-content: flex-start; + gap: 2px; + overflow-x: auto; + } + .twb-doc[data-page="triworldbench"] .site-nav nav a { + flex: none; + width: auto; + padding: 7px 10px; + text-align: center; + } + .twb-doc[data-page="triworldbench"] main > section, + .twb-doc[data-page="triworldbench"] #top { + scroll-margin-top: 112px; + } +} + +/* Hero resources, Editorial medals, and consistent gray-block insets. */ +.twb-doc[data-page="triworldbench"] .twb-hero .actions a.hero-action-primary, +.twb-doc[data-page="triworldbench"] .twb-hero .actions a.hero-action-secondary { + color: #fff !important; + background: var(--twb-ink) !important; + border-color: var(--twb-ink) !important; +} +.twb-doc[data-page="triworldbench"] #leaderboard .twb-rank-badge.rank-1, +.twb-doc[data-page="triworldbench"] #leaderboard .twb-rank-badge.rank-2, +.twb-doc[data-page="triworldbench"] #leaderboard .twb-rank-badge.rank-3 { + border: 0; + color: inherit; + background: transparent; + font-family: "Segoe UI Emoji", "Apple Color Emoji", sans-serif; + font-size: 22px; +} +.twb-doc[data-page="triworldbench"] .twb-cell-rank.rank-1, +.twb-doc[data-page="triworldbench"] .twb-cell-rank.rank-2, +.twb-doc[data-page="triworldbench"] .twb-cell-rank.rank-3 { + color: inherit; + font-family: "Segoe UI Emoji", "Apple Color Emoji", sans-serif; + font-size: 14px; + vertical-align: -1px; +} +.twb-doc[data-page="triworldbench"] #overview .case-intro { + padding-inline: 24px; +} +.twb-doc[data-page="triworldbench"] #overview .twb-keywords b { + padding-inline: 16px; +} +.twb-doc[data-page="triworldbench"] #advantages .adv-grid article { + padding-inline: 22px; +} +.twb-doc[data-page="triworldbench"] #advantages .adv-vs > span { + padding-inline: 12px; +} +.twb-doc[data-page="triworldbench"] .twb-vis-top .twb-vis-models { + padding: 14px; +} +.twb-doc[data-page="triworldbench"] .twb-model-chip { + padding-inline: 12px; +} +.twb-doc[data-page="triworldbench"] .twb-bar-list span { + padding: 10px 16px; +} +.twb-doc[data-page="triworldbench"] .twb-metric-glossary, +.twb-doc[data-page="triworldbench"] .twb-metric-glossary[open] { + padding: 16px 20px; +} +.twb-doc[data-page="triworldbench"] .timeline article, +.twb-doc[data-page="triworldbench"] .date-grid article, +.twb-doc[data-page="triworldbench"] .sub-row, +.twb-doc[data-page="triworldbench"] .contact-card, +.twb-doc[data-page="triworldbench"] .citation-code, +.twb-doc[data-page="triworldbench"] .coming { + padding-inline: 22px; +} + +/* Final neutral-color and readability corrections. */ +.twb-doc[data-page="triworldbench"]::before { + font-size: 138px; +} +.twb-doc[data-page="triworldbench"] .twb-models-head h4, +.twb-doc[data-page="triworldbench"] .twb-models-head h4 > span { + color: #252525 !important; + font-size: 17px; + font-weight: 700; + line-height: 1.4; +} +.twb-doc[data-page="triworldbench"] .twb-metric-glossary summary, +.twb-doc[data-page="triworldbench"] .twb-metric-glossary summary > span { + color: #252525 !important; + font-size: 18px; + font-weight: 700; + line-height: 1.45; +} +.twb-doc[data-page="triworldbench"] .twb-glossary-grid b, +.twb-doc[data-page="triworldbench"] .twb-glossary-grid b > span { + color: #292929 !important; + font-size: 15px; + font-weight: 650; + line-height: 1.5; +} +.twb-doc[data-page="triworldbench"] .twb-glossary-grid > div > span, +.twb-doc[data-page="triworldbench"] .twb-glossary-grid > div > span > span { + color: #4a4a4a !important; + font-size: 15px; + line-height: 1.65; + opacity: 1; +} +.twb-doc[data-page="triworldbench"] .contact-card p, +.twb-doc[data-page="triworldbench"] .contact-card p span { + color: #505050 !important; + opacity: 1; +} + +/* Submission guide: remove legacy green borders and text treatments. */ +.twb-doc[data-page="triworldbench"].submission-guide .site-nav { + border-bottom-color: #e5e7eb; +} +.twb-doc[data-page="triworldbench"].submission-guide .sub-table-wrap { + border: 1px solid #d8dcdf; + border-radius: 8px; + background: #fff; +} +.twb-doc[data-page="triworldbench"].submission-guide .sub-table th, +.twb-doc[data-page="triworldbench"].submission-guide .sub-table td { + border-bottom-color: #e5e7eb; + color: #444; +} +.twb-doc[data-page="triworldbench"].submission-guide .sub-table thead th, +.twb-doc[data-page="triworldbench"].submission-guide .sub-table tbody th { + color: #30363b; + background: #f3f4f5; +} +.twb-doc[data-page="triworldbench"].submission-guide .sub-minor-title, +.twb-doc[data-page="triworldbench"].submission-guide .sub-steps b { + color: #1f2327; +} +.twb-doc[data-page="triworldbench"].submission-guide .sub-note { + border-left-color: #9ca3af; + color: #3f4448; + background: #f3f4f5; +} +.twb-doc[data-page="triworldbench"].submission-guide .sub-token { + border-color: #d6dade; + color: #33383d; + background: #f0f1f3; +} +.twb-doc[data-page="triworldbench"].submission-guide .sub-code { + border-color: #d8dcdf; + color: #2c3338; + background: #f6f7f8; + box-shadow: none; +} +.twb-doc[data-page="triworldbench"].submission-guide .sub-list li, +.twb-doc[data-page="triworldbench"].submission-guide .sub-steps li { + color: #4b5156; +} + +@media (max-width: 760px) { + .twb-doc[data-page="triworldbench"]::before { + font-size: 68px; + } + .twb-doc[data-page="triworldbench"] .twb-metric-glossary summary, + .twb-doc[data-page="triworldbench"] .twb-metric-glossary summary > span { + font-size: 17px; + } +} + +/* Stronger black-and-white contrast while retaining intentional gray UI blocks. */ +.twb-doc[data-page="triworldbench"] { + --twb-ink: #111315; + --twb-muted: #454a4f; + --twb-line: #d8dce0; + --twb-soft: #eef0f2; + color: #202326; + background: #fff; +} +.twb-doc[data-page="triworldbench"] .site-nav, +.twb-doc[data-page="triworldbench"] footer { + background-color: #fff !important; +} +.twb-doc[data-page="triworldbench"] main, +.twb-doc[data-page="triworldbench"] main > .section, +.twb-doc[data-page="triworldbench"] main > #leaderboard.twb-v02, +.twb-doc[data-page="triworldbench"].submission-guide main > .section { + background-color: transparent !important; +} +.twb-doc[data-page="triworldbench"] .site-nav .brand::before { + content: "TWB"; + width: 40px; + height: 30px; + border: 0; + border-radius: 6px; + color: #fff; + background: #17365d; + font-family: Inter, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; + font-size: 10px; + font-weight: 800; + line-height: 1; + letter-spacing: 0; +} +.twb-doc[data-page="triworldbench"] .site-nav nav a { + color: #34383c; +} +.twb-doc[data-page="triworldbench"] .twb-hero .eyebrow, +.twb-doc[data-page="triworldbench"] .section-head > span, +.twb-doc[data-page="triworldbench"] #leaderboard .twb-v02-top > span { + color: #4b5055 !important; +} +.twb-doc[data-page="triworldbench"] .twb-hero .subtitle, +.twb-doc[data-page="triworldbench"] .section > p, +.twb-doc[data-page="triworldbench"] .section li, +.twb-doc[data-page="triworldbench"] .ac-article p, +.twb-doc[data-page="triworldbench"] #cases > p, +.twb-doc[data-page="triworldbench"] #leaderboard .twb-board-note, +.twb-doc[data-page="triworldbench"] .submission-main p, +.twb-doc[data-page="triworldbench"].submission-guide main p, +.twb-doc[data-page="triworldbench"].submission-guide main li { + color: #303438; +} +.twb-doc[data-page="triworldbench"] .twb-authors-list { + color: #25282b; +} +.twb-doc[data-page="triworldbench"] .twb-affiliations, +.twb-doc[data-page="triworldbench"] .twb-affiliations sup, +.twb-doc[data-page="triworldbench"] #leaderboard .twb-sticky-col small, +.twb-doc[data-page="triworldbench"] .sub-row small, +.twb-doc[data-page="triworldbench"] footer { + color: #4b5055; +} +.twb-doc[data-page="triworldbench"] main h2, +.twb-doc[data-page="triworldbench"] main h3, +.twb-doc[data-page="triworldbench"] main h4, +.twb-doc[data-page="triworldbench"] main h2 > span, +.twb-doc[data-page="triworldbench"] main h3 > span, +.twb-doc[data-page="triworldbench"] main h4 > span, +.twb-doc[data-page="triworldbench"] .twb-models-head h4, +.twb-doc[data-page="triworldbench"] .twb-vis-ranked h4, +.twb-doc[data-page="triworldbench"] .sub-minor-title, +.twb-doc[data-page="triworldbench"] .sub-steps b { + color: #111315 !important; +} +.twb-doc[data-page="triworldbench"] #overview .case-intro, +.twb-doc[data-page="triworldbench"] #overview .twb-keywords b, +.twb-doc[data-page="triworldbench"] #advantages .adv-grid article > p, +.twb-doc[data-page="triworldbench"] #advantages .adv-vs > span, +.twb-doc[data-page="triworldbench"] #advantages .adv-vs small, +.twb-doc[data-page="triworldbench"] .timeline article, +.twb-doc[data-page="triworldbench"] .date-grid article, +.twb-doc[data-page="triworldbench"] .contact-card, +.twb-doc[data-page="triworldbench"] .coming { + color: #34383c; +} +.twb-doc[data-page="triworldbench"] #advantages .adv-vs { + grid-template-columns: minmax(0, .85fr) 20px minmax(0, 1.15fr); +} +.twb-doc[data-page="triworldbench"] #advantages .adv-vs > span { + padding-inline: 6px; + font-size: 11px; + word-break: normal; + overflow-wrap: normal; +} +.twb-doc[data-page="triworldbench"] .timeline time, +.twb-doc[data-page="triworldbench"] .contact-card > span, +.twb-doc[data-page="triworldbench"] .sub-row > i, +.twb-doc[data-page="triworldbench"] .ac-article h3 { + color: #34383c; +} +.twb-doc[data-page="triworldbench"] .contact-card p, +.twb-doc[data-page="triworldbench"] .contact-card p span, +.twb-doc[data-page="triworldbench"] .twb-glossary-grid > div > span, +.twb-doc[data-page="triworldbench"] .twb-glossary-grid > div > span > span { + color: #303438 !important; +} +.twb-doc[data-page="triworldbench"] #contact .contact-card p, +.twb-doc[data-page="triworldbench"] #contact .contact-card p span { + color: #111315 !important; +} +.twb-doc[data-page="triworldbench"] #leaderboard .twb-dense-table, +.twb-doc[data-page="triworldbench"] #leaderboard .twb-dense-table td, +.twb-doc[data-page="triworldbench"].submission-guide .sub-table th, +.twb-doc[data-page="triworldbench"].submission-guide .sub-table td, +.twb-doc[data-page="triworldbench"].submission-guide .sub-list li, +.twb-doc[data-page="triworldbench"].submission-guide .sub-steps li { + color: #282c30; +} +.twb-doc[data-page="triworldbench"] .twb-bar-list span { + border-color: #d6dade; + color: #24282c; + background: #f7f8f9; +} +.twb-doc[data-page="triworldbench"] .twb-bar-list span::before { + background: color-mix(in srgb, var(--c) 26%, #f1f3f5); +} +.twb-doc[data-page="triworldbench"] .twb-bar-list span.is-hl::before { + background: color-mix(in srgb, var(--c) 72%, #fff); +} +.twb-doc[data-page="triworldbench"] #leaderboard .twb-table-wrap { + background: transparent; +} +.twb-doc[data-page="triworldbench"] #leaderboard .twb-dense-table { + background: transparent !important; +} +.twb-doc[data-page="triworldbench"] #leaderboard .twb-leaders-grid article, +.twb-doc[data-page="triworldbench"] #leaderboard .twb-dense-table td, +.twb-doc[data-page="triworldbench"] #leaderboard .twb-dense-table .twb-sticky-col, +.twb-doc[data-page="triworldbench"] #leaderboard .twb-dense-table .twb-sticky-rank, +.twb-doc[data-page="triworldbench"] #leaderboard .twb-best, +.twb-doc[data-page="triworldbench"] #leaderboard .twb-col-ref { + background-color: rgba(255, 255, 255, .08) !important; +} +.twb-doc[data-page="triworldbench"] #leaderboard .twb-dense-table th, +.twb-doc[data-page="triworldbench"] #leaderboard .twb-dense-table thead .twb-sticky-col, +.twb-doc[data-page="triworldbench"] #leaderboard .twb-dense-table thead .twb-sticky-rank { + background-color: rgba(245, 247, 250, .58) !important; +} + +@media (max-width: 760px) { + .twb-doc[data-page="triworldbench"] .site-nav .brand, + .twb-doc[data-page="triworldbench"] .site-nav nav a, + .twb-doc[data-page="triworldbench"] .language-menu > button, + .twb-doc[data-page="triworldbench"] .twb-hero .actions a, + .twb-doc[data-page="triworldbench"] .case-tab, + .twb-doc[data-page="triworldbench"] .twb-present-all, + .twb-doc[data-page="triworldbench"] .twb-model-chip, + .twb-doc[data-page="triworldbench"] .ms-btn, + .twb-doc[data-page="triworldbench"] .twb-metric-glossary summary { + min-height: 44px; + } + .twb-doc[data-page="triworldbench"] .site-nav .brand, + .twb-doc[data-page="triworldbench"] .site-nav nav a, + .twb-doc[data-page="triworldbench"] .twb-metric-glossary summary { + display: flex; + align-items: center; + } + .twb-doc[data-page="triworldbench"] .section-head h2, + .twb-doc[data-page="triworldbench"] .section-head h2 > span { + min-width: 0; + white-space: normal !important; + overflow-wrap: break-word; + } + .twb-doc[data-page="triworldbench"].submission-guide .site-nav nav a { + padding-inline: 5px; + font-size: 13px; + } +} + +@media (max-width: 820px) { + .twb-doc[data-page="triworldbench"] .site-nav .brand, + .twb-doc[data-page="triworldbench"] .site-nav nav a, + .twb-doc[data-page="triworldbench"] .language-menu > button, + .twb-doc[data-page="triworldbench"] .twb-hero .actions a, + .twb-doc[data-page="triworldbench"] .case-tab, + .twb-doc[data-page="triworldbench"] .twb-present-all, + .twb-doc[data-page="triworldbench"] .twb-model-chip, + .twb-doc[data-page="triworldbench"] .ms-btn, + .twb-doc[data-page="triworldbench"] .twb-metric-glossary summary { + min-height: 44px; + } + .twb-doc[data-page="triworldbench"] .language-menu > button { + min-width: 48px; + padding-inline: 9px; + white-space: nowrap; + word-break: keep-all; + } +} + +/* Keep the model identity readable while the metric table scrolls horizontally. */ +.twb-doc[data-page="triworldbench"] #leaderboard .twb-dense-table { + --twb-model-col-width: 260px; +} +.twb-doc[data-page="triworldbench"] #leaderboard .twb-sticky-col { + left: 0; + z-index: 7; + width: var(--twb-model-col-width); + min-width: var(--twb-model-col-width) !important; + max-width: var(--twb-model-col-width); + overflow: hidden; + isolation: isolate; + background-color: #fff !important; + background-image: none !important; + text-align: left; + box-shadow: 8px 0 10px -10px rgba(20, 28, 34, .7); +} +.twb-doc[data-page="triworldbench"] #leaderboard thead .twb-sticky-col { + z-index: 9; + background-color: #f5f7fa !important; + background-image: none !important; +} +.twb-doc[data-page="triworldbench"] #leaderboard .twb-sticky-col b, +.twb-doc[data-page="triworldbench"] #leaderboard .twb-sticky-col small { + max-width: 100%; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} +.twb-doc[data-page="triworldbench"] #leaderboard .twb-dense-table tbody tr:hover .twb-sticky-col { + background-color: #f0f1f3 !important; +} +.twb-doc[data-page="triworldbench"] #leaderboard .twb-col-score { + min-width: 132px; +} +.twb-doc[data-page="triworldbench"] #leaderboard .twb-ranked-score { + display: inline-flex; + min-width: 0; + align-items: center; + justify-content: center; + gap: 6px; + white-space: nowrap; +} +.twb-doc[data-page="triworldbench"] #leaderboard .twb-cell-rank { + flex: 0 0 auto; + margin-left: 0; +} + +@media (max-width: 760px) { + .twb-doc[data-page="triworldbench"] #leaderboard .twb-dense-table { + --twb-model-col-width: 210px; + } +} + +/* Give long model names room without allowing the radar to dominate the row. */ +.twb-doc[data-page="triworldbench"] .twb-vis-top { + grid-template-columns: minmax(0, 1fr) minmax(330px, 360px); + gap: 24px; +} +.twb-doc[data-page="triworldbench"] .twb-vis-top .twb-vis-radar { + min-height: 640px; +} +.twb-doc[data-page="triworldbench"] .twb-vis-top .twb-vis-radar svg { + width: min(680px, 100%); +} +.twb-doc[data-page="triworldbench"] .twb-model-chip { + display: grid; + grid-template-columns: 18px minmax(0, 1fr); + align-items: center; + width: 100%; + text-align: left; +} +.twb-doc[data-page="triworldbench"] .twb-model-chip > span { + min-width: 0; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +@media (max-width: 1000px) { + .twb-doc[data-page="triworldbench"] .twb-vis-top { + grid-template-columns: 1fr; + } + .twb-doc[data-page="triworldbench"] .twb-vis-top .twb-vis-radar { + min-height: 560px; + } +} + +@media (max-width: 760px) { + .twb-doc[data-page="triworldbench"] .twb-vis-top .twb-vis-radar { + min-height: 420px; + } +} + +/* Final single-table behavior: only Model and Rank remain fixed on the left. */ +.twb-doc[data-page="triworldbench"] #leaderboard .twb-table-wrap { + position: relative; + isolation: isolate; + overflow: auto; +} +.twb-doc[data-page="triworldbench"] #leaderboard .twb-dense-table .twb-sticky-col { + position: sticky !important; + left: 0 !important; + z-index: 7; + width: 260px; + min-width: 260px !important; + max-width: 260px; + padding: 12px 14px; + overflow: hidden; + background: #fff !important; + background-image: linear-gradient(#fff, #fff) !important; + opacity: 1; + font-family: Inter, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; + text-align: left; +} +.twb-doc[data-page="triworldbench"] #leaderboard .twb-dense-table .twb-sticky-rank { + position: sticky !important; + left: 260px !important; + z-index: 7; + width: 70px; + min-width: 70px !important; + max-width: 70px; + background: #fff !important; + background-image: linear-gradient(#fff, #fff) !important; + opacity: 1; + box-shadow: 8px 0 12px -12px rgba(20, 28, 34, .85); +} +.twb-doc[data-page="triworldbench"] #leaderboard .twb-dense-table thead .twb-sticky-col, +.twb-doc[data-page="triworldbench"] #leaderboard .twb-dense-table thead .twb-sticky-rank { + z-index: 10; + background: #f5f7fa !important; + background-image: linear-gradient(#f5f7fa, #f5f7fa) !important; +} +.twb-doc[data-page="triworldbench"] #leaderboard .twb-dense-table tbody tr:nth-child(odd) .twb-sticky-col, +.twb-doc[data-page="triworldbench"] #leaderboard .twb-dense-table tbody tr:nth-child(odd) .twb-sticky-rank { + background: #fff !important; + background-image: linear-gradient(#fff, #fff) !important; +} +.twb-doc[data-page="triworldbench"] #leaderboard .twb-dense-table tbody tr:hover .twb-sticky-col, +.twb-doc[data-page="triworldbench"] #leaderboard .twb-dense-table tbody tr:hover .twb-sticky-rank { + background: #f0f1f3 !important; + background-image: linear-gradient(#f0f1f3, #f0f1f3) !important; +} +.twb-doc[data-page="triworldbench"] #leaderboard .twb-sticky-col b, +.twb-doc[data-page="triworldbench"] #leaderboard .twb-sticky-col small { + display: block; + max-width: 100%; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} +.twb-doc[data-page="triworldbench"] #leaderboard .twb-sticky-col b { + color: var(--twb-ink); + font-size: 14px; + font-weight: 600; + line-height: 1.4; +} +.twb-doc[data-page="triworldbench"] #leaderboard .twb-sticky-col small { + margin-top: 3px; + color: #888; + font-size: 11px; + font-weight: 400; + line-height: 1.4; +} + +@media (max-width: 760px) { + .twb-doc[data-page="triworldbench"] #leaderboard .twb-dense-table .twb-sticky-col { + width: 180px; + min-width: 180px !important; + max-width: 180px; + padding-inline: 10px; + } + .twb-doc[data-page="triworldbench"] #leaderboard .twb-dense-table .twb-sticky-rank { + left: 180px !important; + width: 58px; + min-width: 58px !important; + max-width: 58px; + } +} +/* Contact copy is intentionally monochrome across both language sites. */ +body .twb-doc[data-page="triworldbench"] #contact .contact-card, +body .twb-doc[data-page="triworldbench"] #contact .contact-card *:not(.contact-download-link) { + color: #000 !important; +} +body .twb-doc[data-page="triworldbench"] #contact .contact-card .contact-download-link { + color: #000 !important; +} +.twb-doc[data-page="triworldbench"] #contact .contact-grid { + grid-template-columns: repeat(2, minmax(0, 1fr)); + gap: 18px; + margin-top: 20px; +} +.twb-doc[data-page="triworldbench"] #contact .contact-card { + display: grid; + align-content: start; + gap: 10px; + min-height: 172px; + padding: 22px 24px; + border-color: #d7dde1; + border-radius: 6px; + background: #f6f7f8; +} +.twb-doc[data-page="triworldbench"] #contact .contact-card b { + font-size: 20px; + font-weight: 800; + line-height: 1.3; +} +.twb-doc[data-page="triworldbench"] #contact .contact-card a { + overflow-wrap: anywhere; + font-size: 17px; + font-weight: 800; + line-height: 1.45; +} +.twb-doc[data-page="triworldbench"] #contact .contact-card .contact-download-link { + overflow-wrap: normal; + word-break: normal; + font-size: 20px; + letter-spacing: 0; + text-transform: none; + text-decoration: underline; + text-decoration-thickness: 1px; + text-underline-offset: 3px; +} +.twb-doc[data-page="triworldbench"] #contact .contact-card .contact-download-link > .i18n-en, +.twb-doc[data-page="triworldbench"] #contact .contact-card .contact-download-link > .i18n-zh { + color: inherit !important; + font: inherit; + letter-spacing: 0; + text-transform: none; +} +.twb-doc[data-page="triworldbench"] #contact .contact-card .twb-markdown { + margin: 0; +} +.twb-doc[data-page="triworldbench"] #contact .contact-card .twb-markdown p { + margin: 0; + font-size: 15px; + line-height: 1.6; +} +@media (max-width: 720px) { + .twb-doc[data-page="triworldbench"] #contact .contact-grid { + grid-template-columns: minmax(0, 1fr); + } +} + +/* Final leaderboard column contract. */ +.twb-doc[data-page="triworldbench"] #leaderboard .twb-dense-table { + --twb-model-col-width: 260px; + --twb-rank-col-width: 68px; + --twb-score-col-width: 112px; + table-layout: fixed; + width: max-content; + min-width: max-content !important; +} +.twb-doc[data-page="triworldbench"] #leaderboard .twb-dense-table .twb-col-score, +.twb-doc[data-page="triworldbench"] #leaderboard .twb-dense-table .twb-col-category, +.twb-doc[data-page="triworldbench"] #leaderboard .twb-dense-table .twb-col-submetric, +.twb-doc[data-page="triworldbench"] #leaderboard .twb-dense-table .twb-metric-header { + width: var(--twb-score-col-width) !important; + min-width: var(--twb-score-col-width) !important; + max-width: var(--twb-score-col-width) !important; +} +.twb-doc[data-page="triworldbench"] #leaderboard .twb-dense-table thead .twb-col-score, +.twb-doc[data-page="triworldbench"] #leaderboard .twb-dense-table thead .twb-col-category, +.twb-doc[data-page="triworldbench"] #leaderboard .twb-dense-table thead .twb-col-submetric, +.twb-doc[data-page="triworldbench"] #leaderboard .twb-dense-table thead .twb-metric-header { + min-height: 76px; + padding: 12px 8px; + white-space: normal !important; +} +.twb-doc[data-page="triworldbench"] #leaderboard .twb-metric-header-text, +.twb-doc[data-page="triworldbench"] #leaderboard .twb-metric-header-line { + display: block; + white-space: normal; + overflow-wrap: anywhere; +} +.twb-doc[data-page="triworldbench"] #leaderboard .twb-dense-table .twb-sticky-col { + left: 0 !important; + width: var(--twb-model-col-width) !important; + min-width: var(--twb-model-col-width) !important; + max-width: var(--twb-model-col-width) !important; +} +.twb-doc[data-page="triworldbench"] #leaderboard .twb-dense-table .twb-sticky-rank { + left: var(--twb-model-col-width) !important; + width: var(--twb-rank-col-width) !important; + min-width: var(--twb-rank-col-width) !important; + max-width: var(--twb-rank-col-width) !important; +} +.twb-doc[data-page="triworldbench"] #leaderboard .twb-col-status { + display: none !important; +} +@media (max-width: 760px) { + .twb-doc[data-page="triworldbench"] #leaderboard .twb-dense-table { + --twb-model-col-width: 210px; + --twb-rank-col-width: 58px; + --twb-score-col-width: 106px; + } +} + +/* Database-managed research content. */ +.twb-doc[data-page="triworldbench"] .twb-research-section > p { + width: min(100%, 1040px); + margin-inline: auto; +} +.twb-doc[data-page="triworldbench"] .twb-content-figure, +.twb-doc[data-page="triworldbench"] .twb-protocol-figure { + width: min(100%, 1040px); + margin: 28px auto; +} +.twb-doc[data-page="triworldbench"] .twb-content-figure-frame { + display: block; + padding: clamp(12px, 1.8vw, 22px); + border: 1px solid #d9dde1; + background: #fff; + transition: transform 180ms ease, box-shadow 180ms ease; +} +.twb-doc[data-page="triworldbench"] .twb-content-figure img { + display: block; + width: 100%; + height: auto; + background: #fff; +} +.twb-doc[data-page="triworldbench"] .twb-content-figure-frame:hover, +.twb-doc[data-page="triworldbench"] .twb-institutions a:hover img { + transform: translateY(-2px); + box-shadow: 0 14px 28px rgba(20, 28, 34, .18); +} +.twb-doc[data-page="triworldbench"] .twb-content-figure figcaption, +.twb-doc[data-page="triworldbench"] .twb-protocol-figure figcaption { + margin-top: 10px; + color: #353a3e; + font-size: 14px; + line-height: 1.55; +} +.twb-doc[data-page="triworldbench"] .twb-section-subtitle, +.twb-doc[data-page="triworldbench"] .twb-metric-definitions > h3 { + margin: 0 0 10px; + color: #171a1d; + font-size: 20px; + line-height: 1.4; +} +.twb-doc[data-page="triworldbench"] .twb-protocol-flow { + display: grid; + justify-items: stretch; + gap: 10px; +} +.twb-doc[data-page="triworldbench"] .twb-protocol-single { + display: grid; + justify-items: center; +} +.twb-doc[data-page="triworldbench"] .twb-protocol-single .twb-protocol-node { + width: min(100%, 780px); +} +.twb-doc[data-page="triworldbench"] .twb-protocol-grid { + display: grid; + gap: 12px; +} +.twb-doc[data-page="triworldbench"] .twb-protocol-grid.is-checks { + grid-template-columns: repeat(3, minmax(0, 1fr)); +} +.twb-doc[data-page="triworldbench"] .twb-protocol-grid.is-protocols { + grid-template-columns: repeat(4, minmax(0, 1fr)); +} +.twb-doc[data-page="triworldbench"] .twb-protocol-node { + min-width: 0; + padding: 16px 18px; + border: 1px solid #d6dade; + border-radius: 6px; + background: #f2f3f5; + transition: transform 180ms ease, box-shadow 180ms ease, background-color 180ms ease; +} +.twb-doc[data-page="triworldbench"] .twb-protocol-node:hover { + transform: translateY(-2px); + background: #fff; + box-shadow: 0 12px 24px rgba(20, 28, 34, .14); +} +.twb-doc[data-page="triworldbench"] .twb-protocol-node h3, +.twb-doc[data-page="triworldbench"] .twb-protocol-node h3 > span { + margin: 0 0 7px; + color: #171a1d !important; + font-size: 16px !important; + font-weight: 700; + line-height: 1.4; +} +.twb-doc[data-page="triworldbench"] .twb-protocol-node p, +.twb-doc[data-page="triworldbench"] .twb-protocol-node p > span { + margin: 0; + color: #303438 !important; + font-size: 14px; + line-height: 1.55; +} +.twb-doc[data-page="triworldbench"] .twb-protocol-node.is-input { + background: #edf2f8; + border-color: #b9c9db; +} +.twb-doc[data-page="triworldbench"] .twb-protocol-node.is-output { + background: #eff4ef; + border-color: #c3d2c5; +} +.twb-doc[data-page="triworldbench"] .twb-flow-arrow { + display: grid; + place-items: center; + min-height: 24px; + color: #4d555d; + font-size: 22px; + line-height: 1; +} +.twb-doc[data-page="triworldbench"] .twb-routing-table-wrap { + width: 100%; + margin: 18px 0 36px; + overflow-x: auto; + border-top: 1px solid #d8dce0; + border-bottom: 1px solid #d8dce0; +} +.twb-doc[data-page="triworldbench"] .twb-routing-table { + width: 100%; + min-width: 860px; + border-collapse: collapse; + color: #252a2e; +} +.twb-doc[data-page="triworldbench"] .twb-routing-table th, +.twb-doc[data-page="triworldbench"] .twb-routing-table td { + padding: 13px 14px; + border-bottom: 1px solid #e0e3e6; + vertical-align: top; + text-align: left; + font-size: 14px; + line-height: 1.5; +} +.twb-doc[data-page="triworldbench"] .twb-routing-table thead th { + color: #171a1d; + background: #eef0f2; + font-size: 13px; + font-weight: 750; +} +.twb-doc[data-page="triworldbench"] .twb-routing-table tbody th { + width: 19%; + color: #171a1d; + background: #f7f8f9; + font-weight: 700; +} +.twb-doc[data-page="triworldbench"] .twb-metric-definitions { + padding-top: 4px; +} +.twb-doc[data-page="triworldbench"] .twb-metric-definitions .twb-glossary-grid { + margin-top: 12px; +} +.twb-doc[data-page="triworldbench"] .twb-institutions img { + transition: transform 180ms ease, box-shadow 180ms ease; +} + +@media (max-width: 920px) { + .twb-doc[data-page="triworldbench"] .twb-protocol-grid.is-protocols { + grid-template-columns: repeat(2, minmax(0, 1fr)); + } +} +@media (max-width: 720px) { + .twb-doc[data-page="triworldbench"] .site-nav nav { + width: 100%; + flex-wrap: nowrap; + overflow-x: auto; + padding-bottom: 3px; + scrollbar-width: thin; + } + .twb-doc[data-page="triworldbench"] .twb-protocol-grid.is-checks, + .twb-doc[data-page="triworldbench"] .twb-protocol-grid.is-protocols { + grid-template-columns: 1fr; + } + .twb-doc[data-page="triworldbench"] .twb-content-figure, + .twb-doc[data-page="triworldbench"] .twb-protocol-figure { + margin-block: 22px; + } + .twb-doc[data-page="triworldbench"] .twb-protocol-node { + padding: 14px; + } +} + +/* Canonical transparent institution seals, sourced from public/institution-logos. */ +.twb-doc[data-page="triworldbench"] .twb-institutions { + align-items: center; + gap: 18px 28px; +} +.twb-doc[data-page="triworldbench"] .twb-institutions > a, +.twb-doc[data-page="triworldbench"] .twb-institutions > div { + flex: 0 0 112px; + width: 112px; + min-height: 96px; + padding: 6px; + place-items: center; +} +.twb-doc[data-page="triworldbench"] .twb-institutions img { + display: block; + width: 84px; + height: 84px; + max-width: 84px; + object-fit: contain; + background: transparent; +} +@media (max-width: 720px) { + .twb-doc[data-page="triworldbench"] .twb-institutions { + gap: 12px 16px; + } + .twb-doc[data-page="triworldbench"] .twb-institutions > a, + .twb-doc[data-page="triworldbench"] .twb-institutions > div { + flex-basis: 88px; + width: 88px; + min-height: 76px; + padding: 4px; + } + .twb-doc[data-page="triworldbench"] .twb-institutions img { + width: 64px; + height: 64px; + max-width: 64px; + } +} + +/* Keep imported figures and the metric table at the document reading scale. */ +.twb-doc[data-page="triworldbench"] .twb-content-figure { + width: min(100%, 900px); +} +.twb-doc[data-page="triworldbench"] #abstract .twb-content-figure { + width: min(100%, 900px); +} +.twb-doc[data-page="triworldbench"] #overview .twb-content-figure { + width: min(100%, 1040px); +} +.twb-doc[data-page="triworldbench"] .twb-routing-table { + table-layout: fixed; +} +.twb-doc[data-page="triworldbench"] .twb-routing-table col.twb-routing-block { width: 19%; } +.twb-doc[data-page="triworldbench"] .twb-routing-table col.twb-routing-metrics { width: 27%; } +.twb-doc[data-page="triworldbench"] .twb-routing-table col.twb-routing-inputs { width: 34%; } +.twb-doc[data-page="triworldbench"] .twb-routing-table col.twb-routing-output { width: 20%; } +.twb-doc[data-page="triworldbench"] .twb-routing-table th, +.twb-doc[data-page="triworldbench"] .twb-routing-table td { + border-color: #dfe3e6 !important; + overflow-wrap: anywhere; +} +.twb-doc[data-page="triworldbench"] .twb-metric-definitions .twb-glossary-grid { + grid-template-columns: repeat(auto-fit, minmax(270px, 1fr)); + column-gap: 28px; + row-gap: 18px; +} + +@media (max-width: 720px) { + .twb-doc[data-page="triworldbench"] .twb-content-figure, + .twb-doc[data-page="triworldbench"] #abstract .twb-content-figure, + .twb-doc[data-page="triworldbench"] #overview .twb-content-figure { + width: 100%; + } + .twb-doc[data-page="triworldbench"] .twb-content-figure-frame { + padding: 12px; + } +} + +/* Keep every navigation item reachable as the research page grows. */ +.twb-doc[data-page="triworldbench"] .site-nav { + grid-template-columns: max-content minmax(0, 1fr) max-content; + gap: clamp(12px, 1.6vw, 28px); + padding-inline: clamp(18px, 2.4vw, 48px); +} +.twb-doc[data-page="triworldbench"] .site-nav nav { + align-items: center; + justify-content: space-between; + max-height: none; + gap: clamp(4px, .65vw, 11px); + padding-inline: 2px; + scroll-padding-inline: 2px; + scroll-snap-type: x proximity; +} +.twb-doc[data-page="triworldbench"] .site-nav nav a { + scroll-snap-align: start; +} + +@media (max-width: 1280px) and (min-width: 761px) { + .twb-doc[data-page="triworldbench"] .site-nav { + grid-template-columns: max-content max-content; + } + .twb-doc[data-page="triworldbench"] .site-nav nav { + grid-column: 1 / -1; + grid-row: 2; + width: 100%; + justify-content: space-between; + } +} + +@media (max-width: 960px) and (min-width: 761px) { + .twb-doc[data-page="triworldbench"] .site-nav nav { + justify-content: flex-start; + } +} + +/* Figures keep their depth without requiring a hover interaction. */ +.twb-doc[data-page="triworldbench"] .twb-content-figure-frame { + box-shadow: 0 14px 28px rgba(20, 28, 34, .14); + transition: none; +} +.twb-doc[data-page="triworldbench"] .twb-content-figure-frame:hover { + transform: none; + box-shadow: 0 14px 28px rgba(20, 28, 34, .14); +} +.twb-doc[data-page="triworldbench"] .twb-hero .actions a { + display: inline-flex; + align-items: center; + justify-content: center; + gap: 8px; +} +.twb-doc[data-page="triworldbench"] .twb-hero .actions a svg { + flex: none; +} + +/* Figure 2: reference-grounded, state-aware VLM consistency protocol. */ +.twb-doc[data-page="triworldbench"] .twb-protocol-flow-v2 { + display: grid; + gap: 0; + padding: clamp(14px, 2vw, 22px); + border: 1px solid #d8dde1; + background: #fff; + box-shadow: 0 14px 28px rgba(20, 28, 34, .12); +} +.twb-doc[data-page="triworldbench"] .twb-protocol-flow-v2 .twb-protocol-row { + display: grid; + gap: 12px; + min-width: 0; +} +.twb-doc[data-page="triworldbench"] .twb-protocol-flow-v2 .twb-protocol-row.is-reference, +.twb-doc[data-page="triworldbench"] .twb-protocol-flow-v2 .twb-protocol-row.is-rubric { + justify-items: center; +} +.twb-doc[data-page="triworldbench"] .twb-protocol-flow-v2 .twb-protocol-row.is-reference .twb-protocol-node { + width: min(100%, 500px); +} +.twb-doc[data-page="triworldbench"] .twb-protocol-flow-v2 .twb-protocol-row.is-rubric .twb-protocol-node { + width: min(100%, 420px); +} +.twb-doc[data-page="triworldbench"] .twb-protocol-flow-v2 .twb-protocol-row.is-taxonomy { + grid-template-columns: repeat(3, minmax(0, 1fr)); +} +.twb-doc[data-page="triworldbench"] .twb-protocol-flow-v2 .twb-protocol-row.is-protocols { + grid-template-columns: repeat(4, minmax(0, 1fr)); +} +.twb-doc[data-page="triworldbench"] .twb-protocol-flow-v2 .twb-protocol-node { + min-height: 104px; + padding: 13px 14px; + border: 1px solid #8f989e; + border-radius: 4px; + color: #171a1d; + box-shadow: none; + transition: none; +} +.twb-doc[data-page="triworldbench"] .twb-protocol-flow-v2 .twb-protocol-node:hover { + transform: none; + box-shadow: none; +} +.twb-doc[data-page="triworldbench"] .twb-protocol-flow-v2 .twb-protocol-node h3, +.twb-doc[data-page="triworldbench"] .twb-protocol-flow-v2 .twb-protocol-node h3 > span { + margin-bottom: 5px; + color: #111 !important; + font-family: "Source Serif 4", Georgia, serif; + font-size: 14px !important; + line-height: 1.22; +} +.twb-doc[data-page="triworldbench"] .twb-protocol-flow-v2 .twb-protocol-node p, +.twb-doc[data-page="triworldbench"] .twb-protocol-flow-v2 .twb-protocol-node p > span { + color: #25292d !important; + font-size: 12px; + line-height: 1.36; +} +.twb-doc[data-page="triworldbench"] .twb-protocol-flow-v2 .twb-protocol-node.is-reference { + min-height: 70px; + background: #f1f2ff; +} +.twb-doc[data-page="triworldbench"] .twb-protocol-flow-v2 .twb-protocol-node.is-taxonomy:nth-child(1) { + background: #f3f2ff; +} +.twb-doc[data-page="triworldbench"] .twb-protocol-flow-v2 .twb-protocol-node.is-taxonomy:nth-child(2) { + background: #effaf1; +} +.twb-doc[data-page="triworldbench"] .twb-protocol-flow-v2 .twb-protocol-node.is-taxonomy:nth-child(3) { + background: #fff7ef; +} +.twb-doc[data-page="triworldbench"] .twb-protocol-flow-v2 .twb-protocol-node.is-rubric { + min-height: 70px; + background: #fbf2fb; +} +.twb-doc[data-page="triworldbench"] .twb-protocol-flow-v2 .twb-protocol-node.is-protocol { + background: #f3f3ff; +} +.twb-doc[data-page="triworldbench"] .twb-protocol-flow-v2 .twb-protocol-node.is-expert { + min-height: 70px; + background: #fff2e5; +} +.twb-doc[data-page="triworldbench"] .twb-protocol-flow-v2 .twb-protocol-node.is-frozen { + min-height: 70px; + background: #effae9; +} +.twb-doc[data-page="triworldbench"] .twb-flow-connector { + display: grid; + min-height: 52px; + color: #596167; +} +.twb-doc[data-page="triworldbench"] .twb-flow-connector svg { + display: block; + width: 100%; + height: 52px; + overflow: visible; +} +.twb-doc[data-page="triworldbench"] .twb-flow-connector .twb-flow-line { + fill: none; + stroke: currentColor; + stroke-width: 1.5; + vector-effect: non-scaling-stroke; +} +.twb-doc[data-page="triworldbench"] .twb-flow-connector .twb-flow-arrowhead { + fill: currentColor; +} +.twb-doc[data-page="triworldbench"] .twb-flow-connector > span { + display: none; +} +.twb-doc[data-page="triworldbench"] .twb-protocol-outcomes { + display: grid; + grid-template-columns: minmax(0, 1.25fr) 38px minmax(0, .85fr); + align-items: center; + gap: 10px; +} +.twb-doc[data-page="triworldbench"] .twb-outcome-arrow { + display: grid; + min-height: 36px; + place-items: center; + color: #596167; + font-size: 26px; + line-height: 1; +} + +@media (max-width: 920px) { + .twb-doc[data-page="triworldbench"] .twb-protocol-flow-v2 .twb-protocol-row.is-protocols { + grid-template-columns: repeat(2, minmax(0, 1fr)); + } + .twb-doc[data-page="triworldbench"] .twb-flow-connector { + min-height: 26px; + } + .twb-doc[data-page="triworldbench"] .twb-flow-connector svg { + display: none; + } + .twb-doc[data-page="triworldbench"] .twb-flow-connector > span { + display: grid; + min-height: 26px; + place-items: center; + color: #596167; + font-size: 20px; + } +} +@media (max-width: 720px) { + .twb-doc[data-page="triworldbench"] .twb-protocol-flow-v2 { + padding: 12px; + } + .twb-doc[data-page="triworldbench"] .twb-protocol-flow-v2 .twb-protocol-row.is-taxonomy, + .twb-doc[data-page="triworldbench"] .twb-protocol-flow-v2 .twb-protocol-row.is-protocols, + .twb-doc[data-page="triworldbench"] .twb-protocol-outcomes { + grid-template-columns: 1fr; + } + .twb-doc[data-page="triworldbench"] .twb-protocol-flow-v2 .twb-protocol-node, + .twb-doc[data-page="triworldbench"] .twb-protocol-flow-v2 .twb-protocol-node.is-reference, + .twb-doc[data-page="triworldbench"] .twb-protocol-flow-v2 .twb-protocol-node.is-rubric, + .twb-doc[data-page="triworldbench"] .twb-protocol-flow-v2 .twb-protocol-node.is-expert, + .twb-doc[data-page="triworldbench"] .twb-protocol-flow-v2 .twb-protocol-node.is-frozen { + width: 100%; + min-height: 0; + } + .twb-doc[data-page="triworldbench"] .twb-flow-connector { + min-height: 26px; + } + .twb-doc[data-page="triworldbench"] .twb-flow-connector svg { + display: none; + } + .twb-doc[data-page="triworldbench"] .twb-flow-connector > span { + display: grid; + min-height: 26px; + place-items: center; + color: #596167; + font-size: 20px; + } + .twb-doc[data-page="triworldbench"] .twb-outcome-arrow { + min-height: 22px; + font-size: 22px; + transform: rotate(90deg); + } +} + +/* V2 research copy: explanation text aligns with the document edge. */ +.twb-doc[data-page="triworldbench"] .twb-research-section > p, +.twb-doc[data-page="triworldbench"] .twb-metric-intro, +.twb-doc[data-page="triworldbench"] .twb-content-figure figcaption, +.twb-doc[data-page="triworldbench"] .twb-protocol-figure figcaption { + width: 100%; + margin-inline: 0; + text-align: left; +} +.twb-doc[data-page="triworldbench"] .twb-evaluation-metrics { + display: grid; + width: 100%; + margin-top: 26px; + gap: 24px; + text-align: left; +} +.twb-doc[data-page="triworldbench"] .twb-evaluation-group { + margin: 0; + padding: 2px 0 0 18px; + border-left: 3px solid #aab1b8; + background: transparent; +} +.twb-doc[data-page="triworldbench"] .twb-evaluation-group > h3, +.twb-doc[data-page="triworldbench"] .twb-evaluation-item > h4 { + margin: 0; + color: #15181b; + font-weight: 760; + text-align: left; +} +.twb-doc[data-page="triworldbench"] .twb-evaluation-group > h3 { + font-size: 19px; + line-height: 1.35; +} +.twb-doc[data-page="triworldbench"] .twb-evaluation-group > p { + margin: 6px 0 0; + color: #444b51; + font-size: 15px; + line-height: 1.6; + text-align: left; +} +.twb-doc[data-page="triworldbench"] .twb-evaluation-items { + display: grid; + grid-template-columns: repeat(2, minmax(0, 1fr)); + gap: 14px 34px; + margin-top: 16px; +} +.twb-doc[data-page="triworldbench"] .twb-evaluation-item { + min-width: 0; + padding-top: 12px; + border-top: 1px solid #dde1e4; + background: transparent; +} +.twb-doc[data-page="triworldbench"] .twb-evaluation-item > h4 { + font-size: 15px; + line-height: 1.4; +} +.twb-doc[data-page="triworldbench"] .twb-evaluation-item > p { + margin: 5px 0 0; + color: #3d4348; + font-size: 14px; + line-height: 1.58; + text-align: left; +} +@media (max-width: 720px) { + .twb-doc[data-page="triworldbench"] .twb-evaluation-group { + padding-left: 14px; + } + .twb-doc[data-page="triworldbench"] .twb-evaluation-items { + grid-template-columns: 1fr; + gap: 13px; + } +} + +/* Current leaderboard metric hierarchy and navigation. */ +.twb-doc[data-page="triworldbench"] .twb-evaluation-group.submetric-border-left { + border-left-color: var(--submetric-border-left) !important; +} +.twb-doc[data-page="triworldbench"] #leaderboard .twb-leaderboard-card { + padding: 18px; + overflow: visible; +} +.twb-doc[data-page="triworldbench"] #leaderboard .twb-leaderboard-controls { + display: flex; + flex-wrap: wrap; + align-items: center; + gap: 10px 14px; + margin: 14px 0 10px; +} +.twb-doc[data-page="triworldbench"] #leaderboard .twb-rank-range-menu { + position: relative; + z-index: 30; +} +.twb-doc[data-page="triworldbench"] #leaderboard .twb-rank-range-menu > summary, +.twb-doc[data-page="triworldbench"] #leaderboard .twb-model-locator button { + display: inline-flex; + min-height: 38px; + align-items: center; + justify-content: center; + padding: 8px 13px; + border: 1px solid #18222c; + border-radius: 6px; + background: #18222c; + color: #fff; + cursor: pointer; + font-size: 13px; + font-weight: 750; + line-height: 1.2; + list-style: none; +} +.twb-doc[data-page="triworldbench"] #leaderboard .twb-rank-range-menu > summary::-webkit-details-marker { + display: none; +} +.twb-doc[data-page="triworldbench"] #leaderboard .twb-rank-range-menu > summary::after { + margin-left: 8px; + content: "+"; +} +.twb-doc[data-page="triworldbench"] #leaderboard .twb-rank-range-menu[open] > summary::after { + content: "-"; +} +.twb-doc[data-page="triworldbench"] #leaderboard .twb-rank-range-options { + position: absolute; + top: calc(100% + 6px); + left: 0; + display: grid; + min-width: 170px; + max-height: 260px; + overflow-y: auto; + padding: 5px; + border: 1px solid #c9d0d5; + border-radius: 6px; + background: #fff; + box-shadow: 0 10px 24px rgba(18, 26, 34, .16); +} +.twb-doc[data-page="triworldbench"] #leaderboard .twb-rank-range-options button { + border: 0; + border-radius: 4px; + background: transparent; + color: #1b252d; + cursor: pointer; + padding: 8px 10px; + text-align: left; + font-size: 13px; + font-weight: 650; +} +.twb-doc[data-page="triworldbench"] #leaderboard .twb-rank-range-options button:hover { + background: #edf0f2; +} +.twb-doc[data-page="triworldbench"] #leaderboard .twb-model-locator { + display: flex; + flex: 1 1 360px; + align-items: center; + gap: 8px; +} +.twb-doc[data-page="triworldbench"] #leaderboard .twb-model-locator label { + color: #28323a; + font-size: 13px; + font-weight: 750; + white-space: nowrap; +} +.twb-doc[data-page="triworldbench"] #leaderboard .twb-model-locator input { + min-width: 0; + flex: 1 1 180px; + min-height: 38px; + padding: 8px 10px; + border: 1px solid #b8c0c6; + border-radius: 5px; + background: #fff; + color: #15191d; + font: inherit; +} +.twb-doc[data-page="triworldbench"] #leaderboard .twb-locator-message { + margin: 0 0 10px; + color: #465058; + font-size: 13px; +} +.twb-doc[data-page="triworldbench"] #leaderboard .twb-table-wrap { + max-height: min(calc(72vh + 224px), 984px); + overflow: auto; + overscroll-behavior: contain; + border: 1px solid #d7dde1; + border-radius: 6px; + background: #fff; +} +.twb-doc[data-page="triworldbench"] #leaderboard .twb-dense-table { + --twb-score-col-width: 112px; + --twb-model-col-width: 260px; + --twb-rank-col-width: 68px; + width: max-content; + min-width: max-content; + table-layout: fixed; + border-collapse: separate; + border-spacing: 0; + color: #1a2025; +} +.twb-doc[data-page="triworldbench"] #leaderboard .twb-dense-table th, +.twb-doc[data-page="triworldbench"] #leaderboard .twb-dense-table td { + min-width: 104px; + padding: 10px 12px; + border-right: 1px solid #e1e5e8; + border-bottom: 1px solid #e1e5e8; + background: #fff; + color: #20262b; + font-size: 12px; + font-variant-numeric: tabular-nums; + text-align: right; + white-space: nowrap; +} +.twb-doc[data-page="triworldbench"] #leaderboard .twb-dense-table .twb-col-score, +.twb-doc[data-page="triworldbench"] #leaderboard .twb-dense-table .twb-col-category, +.twb-doc[data-page="triworldbench"] #leaderboard .twb-dense-table .twb-col-submetric, +.twb-doc[data-page="triworldbench"] #leaderboard .twb-dense-table .twb-metric-header { + width: var(--twb-score-col-width); + min-width: var(--twb-score-col-width) !important; + max-width: var(--twb-score-col-width); +} +.twb-doc[data-page="triworldbench"] #leaderboard .twb-dense-table thead th { + position: sticky; + top: 0; + z-index: 12; + background: #f1f3f5; + color: #303840; + font-size: 11px; + font-weight: 800; + text-align: center; +} +.twb-doc[data-page="triworldbench"] #leaderboard .twb-dense-table thead .twb-col-score, +.twb-doc[data-page="triworldbench"] #leaderboard .twb-dense-table thead .twb-col-category, +.twb-doc[data-page="triworldbench"] #leaderboard .twb-dense-table thead .twb-col-submetric, +.twb-doc[data-page="triworldbench"] #leaderboard .twb-dense-table thead .twb-metric-header { + padding: 12px 10px; + line-height: 1.18; + white-space: normal; + vertical-align: bottom; +} +.twb-doc[data-page="triworldbench"] #leaderboard .twb-metric-header-text, +.twb-doc[data-page="triworldbench"] #leaderboard .twb-metric-header-line { + display: block; +} +.twb-doc[data-page="triworldbench"] #leaderboard .twb-metric-header-text { + min-height: 2.4em; + text-wrap: balance; +} +.twb-doc[data-page="triworldbench"] #leaderboard .twb-metric-header-line { + white-space: normal; + overflow-wrap: anywhere; +} +.twb-doc[data-page="triworldbench"] #leaderboard .twb-dense-table thead .twb-metric-header { + border-bottom: 3px solid var(--metric-accent) !important; +} +.twb-doc[data-page="triworldbench"] #leaderboard .twb-dense-table thead .twb-metric-header.is-overall { + --metric-accent: #a16207 !important; +} +.twb-doc[data-page="triworldbench"] #leaderboard .twb-dense-table thead .twb-metric-header.is-category { + color: #172027; + font-weight: 800; +} +.twb-doc[data-page="triworldbench"] #leaderboard .twb-dense-table tbody .twb-category-score { + font-weight: 800; +} +.twb-doc[data-page="triworldbench"] #leaderboard .twb-dense-table tbody .twb-overall-score .twb-score-value { + color: #6b4500; +} +.twb-doc[data-page="triworldbench"] #leaderboard .twb-dense-table thead > tr > .twb-metric-header { + background: #f1f3f5 !important; + background-image: linear-gradient(#f1f3f5, #f1f3f5) !important; + opacity: 1; +} +.twb-doc[data-page="triworldbench"] #leaderboard .twb-score-cell { + display: flex; + min-height: 30px; + align-items: center; + justify-content: flex-end; + gap: 5px; +} +.twb-doc[data-page="triworldbench"] #leaderboard .twb-score-value { + display: block; + color: #1c242a; + font-size: 14px; + font-weight: 750; + line-height: 1.15; +} +.twb-doc[data-page="triworldbench"] #leaderboard .twb-cell-rank { + display: inline-flex; + align-items: center; + justify-content: flex-start; + gap: 3px; + margin: 0; + color: #69737b; + font-family: Inter, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; + font-size: 10px; + font-weight: 700; + line-height: 1; + white-space: nowrap; +} +.twb-doc[data-page="triworldbench"] #leaderboard .twb-cell-medal { + width: 12px; + height: 12px; + flex: 0 0 auto; +} +.twb-doc[data-page="triworldbench"] #leaderboard .twb-cell-medal.medal-1 { color: #b8860b; } +.twb-doc[data-page="triworldbench"] #leaderboard .twb-cell-medal.medal-2 { color: #7b8790; } +.twb-doc[data-page="triworldbench"] #leaderboard .twb-cell-medal.medal-3 { color: #9a5b35; } +.twb-doc[data-page="triworldbench"] #leaderboard .twb-cell-rank.rank-1 { color: #8a6200; } +.twb-doc[data-page="triworldbench"] #leaderboard .twb-cell-rank.rank-2 { color: #5d6973; } +.twb-doc[data-page="triworldbench"] #leaderboard .twb-cell-rank.rank-3 { color: #875335; } +.twb-doc[data-page="triworldbench"] #leaderboard .twb-dense-table .twb-model-col, +.twb-doc[data-page="triworldbench"] #leaderboard .twb-dense-table .twb-sticky-col { + position: sticky !important; + left: 0 !important; + z-index: 10; + width: var(--twb-model-col-width); + min-width: var(--twb-model-col-width) !important; + max-width: var(--twb-model-col-width); + padding: 10px 14px; + background: #fff !important; + color: #1a2025; + text-align: left; +} +.twb-doc[data-page="triworldbench"] #leaderboard .twb-dense-table .twb-sticky-rank { + position: sticky !important; + left: var(--twb-model-col-width) !important; + z-index: 10; + width: var(--twb-rank-col-width); + min-width: var(--twb-rank-col-width) !important; + max-width: var(--twb-rank-col-width); + background: #fff !important; + color: #1a2025; + text-align: center; + box-shadow: 8px 0 14px -15px rgba(20, 28, 34, .9); +} +.twb-doc[data-page="triworldbench"] #leaderboard .twb-dense-table thead .twb-sticky-col, +.twb-doc[data-page="triworldbench"] #leaderboard .twb-dense-table thead .twb-sticky-rank { + z-index: 20; + background: #f1f3f5 !important; +} +.twb-doc[data-page="triworldbench"] #leaderboard .twb-sticky-col b, +.twb-doc[data-page="triworldbench"] #leaderboard .twb-sticky-col small { + display: block; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} +.twb-doc[data-page="triworldbench"] #leaderboard .twb-sticky-col b { + color: #161b20; + font-size: 14px; + font-weight: 700; +} +.twb-doc[data-page="triworldbench"] #leaderboard .twb-sticky-col small { + margin-top: 2px; + color: #5e6870; + font-size: 11px; +} +.twb-doc[data-page="triworldbench"] #leaderboard .twb-rank-badge { + display: inline-grid; + min-width: 28px; + min-height: 28px; + place-items: center; + padding: 0 5px; + border: 1px solid #c8d0d6; + border-radius: 5px; + background: #fff; + color: #42505a; + font-size: 12px; + font-weight: 750; +} +.twb-doc[data-page="triworldbench"] #leaderboard .twb-subchart-row td { + padding: 7px 14px; + border-top: 2px solid #b9c2c9; + background: #e9edf0 !important; + color: #36414a; + font-size: 12px; + font-weight: 800; + letter-spacing: 0; + text-align: left; +} +.twb-doc[data-page="triworldbench"] #leaderboard .twb-subchart-row .twb-range-rank-cell { + padding: 0 !important; +} +.twb-doc[data-page="triworldbench"] #leaderboard .twb-subchart-row .twb-range-metric-cell { + width: auto !important; + min-width: 0 !important; + max-width: none !important; + background: #fff !important; +} +.twb-doc[data-page="triworldbench"] #leaderboard .twb-dense-table tbody tr[data-highlighted="true"] > td { + background: color-mix(in srgb, var(--model-highlight) 16%, #fff) !important; + box-shadow: inset 0 2px 0 var(--model-highlight), inset 0 -2px 0 var(--model-highlight); +} +.twb-doc[data-page="triworldbench"] #leaderboard .twb-dense-table tbody tr[data-highlighted="true"] > .twb-sticky-col, +.twb-doc[data-page="triworldbench"] #leaderboard .twb-dense-table tbody tr[data-highlighted="true"] > .twb-sticky-rank { + background: color-mix(in srgb, var(--model-highlight) 16%, #fff) !important; +} + +/* Six-axis visualization uses the same model color assignments as leaderboard highlights. */ +.twb-doc[data-page="triworldbench"] .twb-vis-top { + grid-template-columns: minmax(0, 1fr) minmax(285px, 315px); + gap: 32px; +} +.twb-doc[data-page="triworldbench"] .twb-vis-top .twb-vis-radar { + min-height: 680px; +} +.twb-doc[data-page="triworldbench"] .twb-vis-top .twb-vis-radar svg { + width: min(820px, 100%); +} +.twb-doc[data-page="triworldbench"] .visualization .twb-radar-label { + font-size: 9px !important; + font-weight: 750; +} +.twb-doc[data-page="triworldbench"] .visualization .twb-radar-label.is-start { + text-anchor: start !important; +} +.twb-doc[data-page="triworldbench"] .visualization .twb-radar-label.is-middle { + text-anchor: middle !important; +} +.twb-doc[data-page="triworldbench"] .visualization .twb-radar-label.is-end { + text-anchor: end !important; +} +.twb-doc[data-page="triworldbench"] .visualization .twb-radar-scale { + font-size: 7.5px !important; + font-weight: 650; + text-anchor: middle; + dominant-baseline: middle; + opacity: .68; +} +.twb-doc[data-page="triworldbench"] .twb-vis-top .twb-vis-models { + background: #f1f3f5; + border-color: #d5dadd; + border-radius: 6px; +} +.twb-doc[data-page="triworldbench"] .twb-model-search { + display: grid; + gap: 5px; + margin: 0 0 10px; + color: #3b454d; + font-size: 12px; + font-weight: 700; +} +.twb-doc[data-page="triworldbench"] .twb-model-search input { + width: 100%; + min-height: 34px; + padding: 7px 9px; + border: 1px solid #c3cbd0; + border-radius: 5px; + background: #fff; + color: #161b20; + font: inherit; +} +.twb-doc[data-page="triworldbench"] .twb-model-chips { + max-height: 420px; +} +.twb-doc[data-page="triworldbench"] .twb-model-chip { + min-height: 38px; + align-items: flex-start; + border-radius: 5px; + color: #303840; +} +.twb-doc[data-page="triworldbench"] .twb-model-chip > span { + min-width: 0; + overflow: visible; + text-overflow: clip; + white-space: normal; + overflow-wrap: anywhere; + line-height: 1.35; +} +.twb-doc[data-page="triworldbench"] .twb-bar-list { + max-height: 620px; + overflow-y: auto; + padding-right: 6px; +} +.twb-doc[data-page="triworldbench"] .twb-no-models { + margin: 12px 0 0; + color: #525d66; + font-size: 13px; +} + +@media (max-width: 1120px) { + .twb-doc[data-page="triworldbench"] .twb-vis-top { + grid-template-columns: minmax(0, 1fr); + } +} + +/* Clickable visualization ranks locate the matching row in the main leaderboard. */ +.twb-doc[data-page="triworldbench"] .twb-bar-list .twb-bar-row { + width: 100%; + appearance: none; + cursor: pointer; + font: inherit; + text-align: left; + position: relative; + isolation: isolate; + display: grid; + grid-template-columns: 24px minmax(0, 1fr) auto; + align-items: center; + gap: 10px; + min-height: 40px; + padding: 8px 12px; + overflow: hidden; + border: 1px solid #d6dade; + border-radius: 5px; + background: #f7f8f9; + color: #24282c; +} +.twb-doc[data-page="triworldbench"] .twb-bar-list .twb-bar-row::before { + content: ""; + position: absolute; + z-index: -1; + inset: 0 auto 0 0; + width: var(--v); + background: color-mix(in srgb, var(--c) 26%, #f1f3f5); +} +.twb-doc[data-page="triworldbench"] .twb-bar-list .twb-bar-row.is-hl::before { + background: color-mix(in srgb, var(--c) 72%, #fff); +} +.twb-doc[data-page="triworldbench"] .twb-bar-list .twb-bar-row.is-dim { + opacity: .35; +} +.twb-doc[data-page="triworldbench"] .twb-bar-list .twb-bar-row.is-hl { + outline: 2px solid #333; + outline-offset: -2px; +} +.twb-doc[data-page="triworldbench"] .twb-bar-list .twb-bar-row:hover { + border-color: #7a858d; +} +.twb-doc[data-page="triworldbench"] .twb-bar-list .twb-bar-row:focus-visible { + outline: 2px solid #1e5db8; + outline-offset: 2px; +} +.twb-doc[data-page="triworldbench"] .twb-bar-row > b { + min-width: 0; + overflow: hidden; + color: #20262b; + font-size: 12px; + font-weight: 700; + text-overflow: ellipsis; + white-space: nowrap; +} +.twb-doc[data-page="triworldbench"] .twb-bar-row > i { + color: #20262b; + font-size: 12px; + font-style: normal; + font-weight: 850; +} +.twb-doc[data-page="triworldbench"] .twb-ranking-medal { + width: 20px; + height: 20px; + color: var(--medal-color); + filter: drop-shadow(0 1px 0 rgba(255,255,255,.8)); +} +.twb-doc[data-page="triworldbench"] .twb-ranking-number { + display: grid; + width: 20px; + min-height: 20px; + place-items: center; + color: #59636b; + font-size: 11px; + font-style: normal; + font-weight: 800; + font-site-numeric: tabular-nums; +} + +@media (max-width: 960px) { + .twb-doc[data-page="triworldbench"] .twb-vis-top { + grid-template-columns: 1fr; + } +} +@media (max-width: 720px) { + .twb-doc[data-page="triworldbench"] #leaderboard .twb-model-locator { + flex-basis: 100%; + flex-wrap: wrap; + } + .twb-doc[data-page="triworldbench"] #leaderboard .twb-model-locator input { + min-width: 160px; + } + .twb-doc[data-page="triworldbench"] #leaderboard .twb-table-wrap { + max-height: min(calc(68vh + 192px), 860px); + } + .twb-doc[data-page="triworldbench"] #leaderboard .twb-dense-table .twb-sticky-col { + width: 184px; + min-width: 184px !important; + max-width: 184px; + padding-inline: 10px; + } + .twb-doc[data-page="triworldbench"] #leaderboard .twb-dense-table .twb-sticky-rank { + left: 184px !important; + width: 58px; + min-width: 58px !important; + max-width: 58px; + } + .twb-doc[data-page="triworldbench"] .twb-vis-top .twb-vis-radar { + min-height: 390px; + } +} + +/* Safe Markdown from database-managed page content. */ +html[data-twb-lang="zh"] .twb-doc[data-page="triworldbench"] .twb-markdown.i18n-zh { + display: block !important; +} +.twb-doc[data-page="triworldbench"] .twb-markdown { + color: #353b40; + font-size: 16px; + line-height: 1.68; +} +.twb-doc[data-page="triworldbench"] .twb-markdown > :first-child { + margin-top: 0; +} +.twb-doc[data-page="triworldbench"] .twb-markdown > :last-child { + margin-bottom: 0; +} +.twb-doc[data-page="triworldbench"] .twb-markdown p { + margin: 0 0 14px; +} +.twb-doc[data-page="triworldbench"] .twb-markdown h3, +.twb-doc[data-page="triworldbench"] .twb-markdown h4, +.twb-doc[data-page="triworldbench"] .twb-markdown h5 { + margin: 20px 0 8px; + color: #171b1f; + font-weight: 760; + line-height: 1.35; +} +.twb-doc[data-page="triworldbench"] .twb-markdown h3 { font-size: 20px; } +.twb-doc[data-page="triworldbench"] .twb-markdown h4 { font-size: 17px; } +.twb-doc[data-page="triworldbench"] .twb-markdown h5 { font-size: 15px; } +.twb-doc[data-page="triworldbench"] .twb-markdown ul, +.twb-doc[data-page="triworldbench"] .twb-markdown ol { + display: grid; + gap: 7px; + margin: 0 0 14px; + padding-left: 22px; +} +.twb-doc[data-page="triworldbench"] .twb-markdown code { + padding: 1px 5px; + border: 1px solid #d9dfe3; + border-radius: 3px; + background: #f2f4f5; + color: #20262b; + font-family: "Cascadia Mono", Consolas, monospace; + font-size: .88em; +} +.twb-doc[data-page="triworldbench"] .twb-markdown-code { + overflow-x: auto; + margin: 14px 0; + padding: 13px 15px; + border: 1px solid #d7dde1; + border-radius: 5px; + background: #f4f6f7; +} +.twb-doc[data-page="triworldbench"] .twb-markdown-code code { + display: block; + padding: 0; + border: 0; + background: transparent; + white-space: pre; +} +.twb-doc[data-page="triworldbench"] .twb-markdown a { + color: #123d68; + font-weight: 700; + text-decoration: underline; + text-underline-offset: 2px; +} +.twb-doc[data-page="triworldbench"] .twb-research-section > .twb-markdown, +.twb-doc[data-page="triworldbench"] .twb-metric-intro > .twb-markdown { + width: 100%; +} +.twb-doc[data-page="triworldbench"] .twb-evaluation-group > .twb-markdown { + margin-top: 6px; + color: #444b51; + font-size: 15px; +} +.twb-doc[data-page="triworldbench"] .twb-evaluation-item > .twb-markdown { + margin-top: 5px; + color: #3d4348; + font-size: 14px; + line-height: 1.58; +} +.twb-doc[data-page="triworldbench"] .twb-policy-list { + display: grid; + gap: 0; + max-width: 980px; +} +.twb-doc[data-page="triworldbench"] .twb-policy-item { + padding: 0 0 22px; + border-bottom: 1px solid #dce1e4; +} +.twb-doc[data-page="triworldbench"] .twb-policy-item + .twb-policy-item { + padding-top: 22px; +} +.twb-doc[data-page="triworldbench"] .twb-policy-item:last-child { + padding-bottom: 0; + border-bottom: 0; +} +.twb-doc[data-page="triworldbench"] .twb-policy-item h3 { + margin: 0 0 8px; + color: #161b20; + font-size: 18px; + font-weight: 800; +} +.twb-doc[data-page="triworldbench"] .twb-policy-item > .twb-markdown { + color: #353b40; +} +.twb-doc[data-page="triworldbench"] .twb-policy-item > .twb-markdown p { + max-width: 920px; +} + +/* Submission Guide v0.3 */ +.twb-doc[data-page="triworldbench"].submission-guide .subtitle { + max-width: 820px; + margin-inline: auto; +} +.twb-doc[data-page="triworldbench"].submission-guide .site-nav nav a { + font-weight: 700; +} +.twb-doc[data-page="triworldbench"] .submission-guide-section { + scroll-margin-top: 92px; +} +.twb-doc[data-page="triworldbench"] .submission-guide-section > .twb-markdown { + max-width: none; +} +.twb-doc[data-page="triworldbench"] .submission-guide-section .twb-markdown-code { + margin: 18px 0; + border: 1px solid #d5d9de; + background: #f6f7f8; +} +.twb-doc[data-page="triworldbench"] .case-item video { + -webkit-touch-callout: none; + user-select: none; +} +@media (max-width: 1280px) { + .twb-doc[data-page="triworldbench"] .submission-guide-section { + scroll-margin-top: 126px; + } +} diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000000000000000000000000000000000000..2b82485f9abc4fb7049f1593ccbc49afa1a9e8f5 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,44 @@ +{ + "compilerOptions": { + "target": "ES2017", + "lib": [ + "dom", + "dom.iterable", + "esnext" + ], + "allowJs": true, + "skipLibCheck": true, + "strict": true, + "noEmit": true, + "esModuleInterop": true, + "module": "esnext", + "moduleResolution": "bundler", + "resolveJsonModule": true, + "isolatedModules": true, + "jsx": "preserve", + "incremental": true, + "plugins": [ + { + "name": "next" + } + ], + "paths": { + "@/*": [ + "./src/*" + ] + } + }, + "include": [ + ".next/types/**/*.ts", + "next-env.d.ts", + "src/**/*.ts", + "src/**/*.tsx", + ".next-manager-build/types/**/*.ts" + ], + "exclude": [ + "node_modules", + "server", + ".next", + ".next-*" + ] +}