diff --git a/website/assets/WeiBeiStele.ttf b/website/assets/WeiBeiStele.ttf new file mode 100644 index 00000000..9d7d9973 Binary files /dev/null and b/website/assets/WeiBeiStele.ttf differ diff --git a/website/assets/WeiBeiSteleMono.ttf b/website/assets/WeiBeiSteleMono.ttf new file mode 100644 index 00000000..9b7a5887 Binary files /dev/null and b/website/assets/WeiBeiSteleMono.ttf differ diff --git a/website/assets/app-icon.png b/website/assets/app-icon.png new file mode 100644 index 00000000..620ca536 Binary files /dev/null and b/website/assets/app-icon.png differ diff --git a/website/assets/course-relations-live.png b/website/assets/course-relations-live.png new file mode 100644 index 00000000..c698b6dc Binary files /dev/null and b/website/assets/course-relations-live.png differ diff --git a/website/assets/mark-cutout.png b/website/assets/mark-cutout.png new file mode 100644 index 00000000..9427797d Binary files /dev/null and b/website/assets/mark-cutout.png differ diff --git a/website/assets/paper-texture.jpg b/website/assets/paper-texture.jpg new file mode 100644 index 00000000..b1a95496 Binary files /dev/null and b/website/assets/paper-texture.jpg differ diff --git a/website/assets/relations-live-scrub.mp4 b/website/assets/relations-live-scrub.mp4 new file mode 100644 index 00000000..3f0d062d Binary files /dev/null and b/website/assets/relations-live-scrub.mp4 differ diff --git a/website/assets/three-pane-live.png b/website/assets/three-pane-live.png new file mode 100644 index 00000000..60ead53a Binary files /dev/null and b/website/assets/three-pane-live.png differ diff --git a/website/assets/workflow-live-scrub.mp4 b/website/assets/workflow-live-scrub.mp4 new file mode 100644 index 00000000..3f01b03c Binary files /dev/null and b/website/assets/workflow-live-scrub.mp4 differ diff --git a/website/check.mjs b/website/check.mjs new file mode 100644 index 00000000..a706daf2 --- /dev/null +++ b/website/check.mjs @@ -0,0 +1,62 @@ +import assert from "node:assert/strict"; +import { readFile, stat } from "node:fs/promises"; + +const [html, script, styles, workflow, relations] = await Promise.all([ + readFile(new URL("./index.html", import.meta.url), "utf8"), + readFile(new URL("./main.js", import.meta.url), "utf8"), + readFile(new URL("./styles.css", import.meta.url), "utf8"), + stat(new URL("./assets/workflow-live-scrub.mp4", import.meta.url)), + stat(new URL("./assets/relations-live-scrub.mp4", import.meta.url)), +]); + +assert.match(html, /three-pane-live\.png/); +assert.match(html, /workflow-live-scrub\.mp4/); +assert.match(html, /relations-live-scrub\.mp4/); +assert.doesNotMatch(html, /preload="auto"/); +assert.match(html, /data-download-link/); +assert.match(html, /rel="canonical"/); +assert.match(html, /class="stage-mark"/); +assert.match(html, /class="snap-points"/); +assert.match(html, /styles\.css\?v=11-full-window/); +assert.match(html, /main\.js\?v=11-full-window/); +assert.match(html, /读<\/b>/); +assert.match(html, /问<\/b>/); +assert.match(html, /记<\/b>/); +assert.doesNotMatch(html, /chapter-rail|scroll-cue|workspace-lens|workspace-status|replay/); +assert.doesNotMatch(html, /三栏,刚好是一条路|问题不离开上下文|答案带着|最后一步,仍由你确认|关联会留下/); +assert.doesNotMatch(html, /three-pane-workspace\.png|src="\.\/assets\/workflow\.mp4"|src="\.\/assets\/relations\.mp4"/); +assert.match(script, /function createScrubber/); +assert.match(script, /\{ name: "panes", at: 1 \/ 6 \}/); +assert.match(script, /Number\(button\.dataset\.stop\)/); +assert.match(script, /video\.preload = "auto"/); +assert.match(script, /desktopStory \? workflowVideos\.map\(createScrubber\) : \[\]/); +assert.match(script, /URL\.createObjectURL/); +assert.match(script, /let requestedTime = Number\.NaN/); +assert.match(script, /--stage-mark-opacity/); +assert.match(script, /\{ x: 0, y: 225, scale: 0\.88 \}/); +assert.match(script, /\{ x: -36, y: 94, scale: 0\.96 \}/); +assert.match(script, /\{ x: 78, y: 104, scale: 0\.94 \}/); +assert.match(script, /function resolvePublishedDownload/); +assert.doesNotMatch(script, /gestureLocked|gestureTimer|document\.addEventListener\("wheel"/); +assert.match(script, /addEventListener\("scrollend"/); +assert.match(script, /const nearestIndex = stops\.indexOf\(nearestStop\(progressFromScroll\(\)\)\)/); +assert.doesNotMatch(script, /35\.4|11\.7/); +assert.doesNotMatch(script, /--stage-dark|--lens-opacity|--workspace-media-x/); +assert.doesNotMatch(script, /snapToNearest|scheduleSnap|scrollVelocity/); +assert.match(styles, /\.stage-mark/); +assert.match(styles, /\.persistent-canvas \* \{\s*pointer-events: none;/); +assert.match(styles, /--workspace-y: 275px/); +assert.match(styles, /aspect-ratio: 1315 \/ 768/); +assert.match(styles, /border-radius: 30px;/); +assert.match(styles, /object-fit: contain/); +assert.match(styles, /scroll-snap-type: y mandatory/); +assert.match(styles, /scroll-snap-stop: always/); +assert.match(script, /classList\.toggle\("is-dark", index === 3\)/); +assert.match(styles, /\.stage\.is-dark/); +assert.match(styles, /#1e1a17/); +assert.match(styles, /var\(--paper-deep\)/); +assert.doesNotMatch(styles, /opacity: var\(--stage-dark\)|box-shadow: 0 0 0 3000px/); +assert.ok(workflow.size > 1_000_000); +assert.ok(relations.size > 500_000); + +console.log("宣传页检查通过:固定应用窗口、逐页手势、干净媒体切换与精简文案均已接入。"); diff --git a/website/index.html b/website/index.html index 4e72b86c..6358aa3d 100644 --- a/website/index.html +++ b/website/index.html @@ -1,277 +1,217 @@ - + - - - + + + + 魏碑 WeiBei - - - - - - - 魏碑 WeiBei — 本地优先的 macOS 学习工作台 + + + - - - - -
-
-
-

READ · NOTE · ASK · RETURN TO SOURCE

-

读、记、问,
在同一张纸上。

-

把资料摊开,边读边记。有问题就问,答案直接回到出处。

-

HTML、PDF、Markdown 和纯文本,在同一个原生 macOS 工作台。

- -
-
系统
macOS 14+
-
格式
DMG
-
版本
最新
-
-
- - - -
- -
- 魏碑的原生学习工作台:课程材料、Agent 对话与 Markdown 笔记保留在同一个窗口 -
-
01 资料、问题与笔记共享同一份学习上下文。
-
-
- -
-
-

READ · ASK · NOTE

-

从原文开始,也回到原文。

-

魏碑不把阅读变成聊天的附件。提问发生在材料旁边,写下的内容仍由你决定。

-
- -
    -
  1. -
    01READ
    -

    材料始终在眼前

    -

    打开单个文件,或导入整门课程。PDF 页码、HTML 章节与当前选区都能成为可核对的上下文。

    -
  2. -
  3. -
    02ASK
    -

    围绕正在读的句子发问

    -

    问题线程与选区保持连接。之后再点回那道标记,仍能接着当时的问题继续读。

    -
  4. -
  5. -
    03NOTE
    -

    确认之后再落笔

    -

    Agent 可以提出笔记修改和学习状态更新;比较、保留或写入,最后一步始终交给学习者。

    -
  6. -
-
- -
-
-

RETURN TO SOURCE

-

每个重要判断,
都有回原文的路。

-

回答里的来源由魏碑核对。点击引用,可以打开对应文件、PDF 页面、HTML 章节或关联笔记。

-
    -
  • 准确的 PDF 页面
  • -
  • 对应的 HTML 章节
  • -
  • 与材料相连的笔记
  • -
-
- -
-
ANSWER · 03 SOURCES
-

政策传导存在时滞:利率变化先影响融资条件,再逐步进入投资与消费决策。

- - -
-
- -
-
-
-

MATERIALS × NOTES

-

资料和笔记,保留长期关联。

-
-

不是临时标签,也不只表示当前打开状态。关系台让一份笔记可以连接多份材料,也让一份材料进入不同的学习线索。

-
- -
-
- 魏碑资料关系台:课程材料与课程笔记之间保留可查看和管理的多对多关联 + + +
+
+
+ + +
+
+ + + 魏碑WEIBEI + + +
+ + +
+ + + + + + + + + + + + + + -
02 一门课程里的材料、笔记与学习线索,不必散落在不同应用里。
-
-
- -
-
-

LEARNER DECIDES

-
Agent 提出建议。
学习者决定写下什么。
-
- -
-
笔记建议第 12 页
-

政策效果会立刻出现。

-

政策传导通常存在时滞,效果会经过融资、投资与消费决策逐步显现。

- -
- -
-
LOCAL
资料、索引、学习记录与笔记默认保存在本机。
-
BOUNDED
每次提问只获得当前任务所需的有界上下文。
-
NATIVE
SwiftUI、AppKit、PDFKit 与 WebKit 组成一个原生窗口。
-
-
- -
-
-

PAPER / INKSTONE

-

白天是纸面,夜里是墨石。

-

两种外观都保留暖色文字、石青链接与克制的朱砂落点;正文不会被装饰抢走。

-
-
-
-
- 魏碑应用图标 -
-

WEIBEI FOR MACOS

-

读、记、问,
在同一张纸上。

-

macOS 14 及以上 · DMG

-
- - 下载最新版 DMG - - - WeiBei-latest.dmg -
- -
- -
+
+
+ +

魏碑 · WEIBEI

+

资料在左,问题在旁,笔记在手。

+
+
+ 魏碑三栏工作台 +
02 / 三栏

读、问、记。

+
+
+ 魏碑 Agent 与笔记界面 +
03 / 应用

同一个窗口,内容继续变化。

+
+
+ 魏碑资料关系台 +
04 / 资料

一切仍在魏碑里。

+
- + diff --git a/website/main.js b/website/main.js index e79173ff..626a574a 100644 --- a/website/main.js +++ b/website/main.js @@ -1,170 +1,285 @@ -const REPOSITORY = "weibei-app/weibei"; -const RELEASES_URL = `https://github.com/${REPOSITORY}/releases`; -const RELEASE_MANIFEST = "./release.json"; -const LOCAL_DMG = "./downloads/WeiBei-latest.dmg"; - -const root = document.documentElement; -const themeColor = document.querySelector('meta[name="theme-color"]'); -const themeLabel = document.querySelector("[data-theme-label]"); -const themeToggles = document.querySelectorAll("[data-theme-toggle], [data-theme-toggle-secondary]"); - -function preferredTheme() { - const saved = localStorage.getItem("weibei-theme"); - if (saved === "paper" || saved === "inkstone") return saved; - return window.matchMedia("(prefers-color-scheme: dark)").matches ? "inkstone" : "paper"; -} +const run = document.querySelector(".scroll-run"); +const stage = document.querySelector(".stage"); +const scenes = [...document.querySelectorAll(".scene")]; +const progressButtons = [...document.querySelectorAll("[data-progress], [data-stop]")]; +const workflowVideos = [...document.querySelectorAll(".workspace-flow")]; +const relationsVideo = document.querySelector(".workspace-relations"); +const reducedMotion = matchMedia("(prefers-reduced-motion: reduce)").matches; +const desktopStory = matchMedia("(min-width: 761px)").matches; +const captureMode = new URLSearchParams(location.search).has("capture"); +const releasesUrl = "https://github.com/weibei-app/weibei/releases"; + +const stops = [ + { name: "hero", at: 0 }, + { name: "panes", at: 1 / 6 }, + { name: "context", at: 2 / 6 }, + { name: "provenance", at: 3 / 6 }, + { name: "writeback", at: 4 / 6 }, + { name: "relations", at: 5 / 6 }, + { name: "finish", at: 1 }, +]; + +const workspaceStates = [ + { x: 0, y: 275, scale: 0.86 }, + { x: 0, y: 225, scale: 0.88 }, + { x: -36, y: 94, scale: 0.96 }, + { x: 78, y: 104, scale: 0.94 }, + { x: -28, y: 110, scale: 0.96 }, + { x: 0, y: 98, scale: 0.95 }, + { x: 84, y: 395, scale: 0.78 }, +]; + +let targetProgress = 0; +let renderedProgress = 0; +let currentStopIndex = 0; +let activeSceneIndex = -1; + +const clamp = (value, min = 0, max = 1) => Math.min(max, Math.max(min, value)); +const mix = (a, b, amount) => a + (b - a) * amount; +const smoothstep = value => { + const x = clamp(value); + return x * x * (3 - 2 * x); +}; -function setTheme(theme, persist = false) { - root.dataset.theme = theme; - if (themeLabel) themeLabel.textContent = theme === "paper" ? "墨石" : "纸面"; - if (themeColor) themeColor.content = theme === "paper" ? "#f2e2ca" : "#0f0f0f"; - if (persist) localStorage.setItem("weibei-theme", theme); +function updateCanvasScale() { + const scale = Math.min(innerWidth / 2880, innerHeight / 1620); + document.documentElement.style.setProperty("--canvas-scale", scale.toFixed(5)); } -setTheme(preferredTheme()); +function progressFromScroll() { + if (!run) return 0; + const distance = run.offsetHeight - innerHeight; + return distance <= 0 ? 0 : clamp((scrollY - run.offsetTop) / distance); +} -themeToggles.forEach((button) => { - button.addEventListener("click", () => { - setTheme(root.dataset.theme === "paper" ? "inkstone" : "paper", true); - }); -}); +function sceneBlend(progress) { + const upperIndex = stops.findIndex(stop => stop.at >= progress); + if (upperIndex <= 0) return { lower: 0, upper: 0, local: 0 }; + const upper = stops[upperIndex]; + const lower = stops[upperIndex - 1]; + const local = (progress - lower.at) / (upper.at - lower.at); + return { lower: upperIndex - 1, upper: upperIndex, local: clamp(local) }; +} -const header = document.querySelector("[data-header]"); -function updateHeader() { - header?.classList.toggle("is-scrolled", window.scrollY > 24); +function nearestStop(progress) { + return stops.reduce((nearest, stop) => + Math.abs(stop.at - progress) < Math.abs(nearest.at - progress) ? stop : nearest + ); } -updateHeader(); -window.addEventListener("scroll", updateHeader, { passive: true }); +function createScrubber(video) { + let targetTime = 0; + let requestedTime = Number.NaN; + let frameReady = false; + video.preload = "auto"; -const revealItems = [...document.querySelectorAll(".reveal")]; -revealItems.forEach((item) => item.classList.add("is-visible")); + const reveal = () => { + if (Math.abs(video.currentTime - targetTime) > 0.08) return; + if (frameReady) return; + frameReady = true; + video.dataset.frameReady = "true"; + }; -function fileSize(bytes) { - const value = Number(bytes); - if (!Number.isFinite(value) || value <= 0) return ""; - const megabytes = value / (1024 * 1024); - return `${megabytes >= 100 ? megabytes.toFixed(0) : megabytes.toFixed(1)} MB`; + const commit = () => { + if (reducedMotion || video.readyState < 1 || !Number.isFinite(video.duration) || video.seeking) { + return; + } + const next = clamp(targetTime, 0, Math.max(0, video.duration - 0.04)); + if (Number.isFinite(requestedTime) && Math.abs(requestedTime - next) <= 0.05) { + reveal(); + return; + } + requestedTime = next; + video.currentTime = next; + }; + + video.pause(); + video.addEventListener("loadedmetadata", commit); + video.addEventListener("seeked", reveal); + + fetch(video.currentSrc || video.src) + .then(response => { + if (!response.ok) throw new Error(`媒体加载失败:${response.status}`); + return response.blob(); + }) + .then(blob => { + requestedTime = Number.NaN; + video.src = URL.createObjectURL(blob); + video.load(); + }) + .catch(() => { + requestedTime = Number.NaN; + commit(); + }); + + return time => { + video.dataset.targetTime = time.toFixed(3); + targetTime = time; + commit(); + }; } -function cleanVersion(version) { - return String(version || "").trim().replace(/^v/i, ""); +const workflowScrubbers = desktopStory ? workflowVideos.map(createScrubber) : []; +const relationsScrubber = desktopStory && relationsVideo ? createScrubber(relationsVideo) : () => {}; + +function updateWorkflow(progress) { + const flowTime = progress <= 0.17 + ? 0.7 + : progress <= 0.34 + ? mix(0.7, 4.2, smoothstep((progress - 0.17) / 0.17)) + : progress <= 0.52 + ? mix(4.2, 7.35, smoothstep((progress - 0.34) / 0.18)) + : progress <= 0.68 + ? mix(7.35, 13.25, smoothstep((progress - 0.52) / 0.16)) + : mix(13.25, 16.4, smoothstep((progress - 0.68) / 0.16)); + workflowScrubbers.forEach(scrub => scrub(flowTime)); + + const relationFlow = clamp((progress - 0.77) / 0.07); + relationsScrubber(mix(0.4, 4.25, smoothstep(relationFlow))); } -function releaseDate(value) { - if (!value) return ""; - const date = new Date(value); - if (Number.isNaN(date.getTime())) return ""; - return new Intl.DateTimeFormat("zh-CN", { - year: "numeric", - month: "short", - day: "numeric", - }).format(date); +function updatePersistentWorkspace(progress, lower, upper, local) { + const eased = smoothstep(local); + const from = workspaceStates[lower]; + const to = workspaceStates[upper]; + const value = key => mix(from[key], to[key], eased); + const root = document.documentElement.style; + + root.setProperty("--workspace-x", `${value("x").toFixed(2)}px`); + root.setProperty("--workspace-y", `${value("y").toFixed(2)}px`); + root.setProperty("--workspace-scale", value("scale").toFixed(4)); + root.setProperty("--stage-mark-opacity", (0.92 * (1 - smoothstep(progress / 0.12))).toFixed(3)); + + const workflowIn = smoothstep((progress - 0.19) / 0.11); + const relationsIn = smoothstep((progress - 0.77) / 0.08); + const finishIn = smoothstep((progress - 0.94) / 0.06); + const workflowReady = workflowVideos.every(video => video.dataset.frameReady === "true"); + const relationsReady = relationsVideo?.dataset.frameReady === "true"; + const workflowOpacity = workflowIn * Number(workflowReady) * (1 - finishIn); + const relationsOpacity = relationsIn * Number(relationsReady) * (1 - finishIn); + root.setProperty("--workspace-static-opacity", "1"); + root.setProperty("--workspace-flow-opacity", workflowOpacity.toFixed(3)); + root.setProperty("--workspace-relations-opacity", relationsOpacity.toFixed(3)); } -function setFallbackRelease() { - document.querySelectorAll("[data-download-link]").forEach((link) => { - link.href = RELEASES_URL; - link.removeAttribute("download"); - }); - document.querySelectorAll("[data-download-label]").forEach((label) => { - label.textContent = "查看最新版本"; +function setActiveScene(index) { + if (activeSceneIndex === index) return; + activeSceneIndex = index; + stage?.classList.toggle("is-dark", index === 3); + scenes.forEach((scene, sceneIndex) => { + const active = sceneIndex === index; + if (!active && scene.contains(document.activeElement)) document.activeElement.blur(); + scene.classList.toggle("is-interactive", active); + scene.inert = !active; + scene.setAttribute("aria-hidden", String(!active)); }); } -function architectureLabel(name) { - if (/universal/i.test(name)) return "Universal"; - if (/arm64|aarch64|apple[-_ ]?silicon/i.test(name)) return "Apple Silicon"; - if (/x86_64|x64|intel/i.test(name)) return "Intel"; - return "macOS"; +function paint(progress) { + const { lower, upper, local } = sceneBlend(progress); + const activeIndex = local < 0.5 ? lower : upper; + + scenes.forEach((scene, index) => { + const opacity = Number(index === activeIndex); + scene.style.setProperty("--scene-opacity", opacity.toFixed(4)); + scene.style.setProperty("--scene-z", String(opacity > 0 ? 8 : 0)); + }); + + setActiveScene(activeIndex); + + updatePersistentWorkspace(progress, lower, upper, local); + updateWorkflow(progress); } -function normalizedAssets(release) { - if (Array.isArray(release?.assets)) { - return release.assets.filter((asset) => asset?.name && asset?.download_url); - } - if (release?.asset_name && release?.download_url) { - return [{ name: release.asset_name, size: release.size, download_url: release.download_url }]; - } - return []; +function frame() { + const response = reducedMotion || captureMode ? 1 : 0.18; + renderedProgress += (targetProgress - renderedProgress) * response; + if (Math.abs(targetProgress - renderedProgress) < 0.0001) renderedProgress = targetProgress; + paint(renderedProgress); + requestAnimationFrame(frame); } -function renderDownloadOptions(assets) { - const options = document.querySelector("[data-download-options]"); - if (!options) return; - options.replaceChildren(); - - assets.forEach((asset) => { - const link = document.createElement("a"); - const title = document.createElement("strong"); - const detail = document.createElement("span"); - link.href = new URL(asset.download_url, document.baseURI).href; - link.download = asset.name; - title.textContent = architectureLabel(asset.name); - detail.textContent = `${asset.name}${asset.size ? ` · ${fileSize(asset.size)}` : ""}`; - link.append(title, detail); - options.append(link); +function scrollToStop(index, behavior = reducedMotion ? "auto" : "smooth") { + if (!run) return; + currentStopIndex = clamp(index, 0, stops.length - 1); + const next = stops[currentStopIndex].at; + scrollTo({ + top: run.offsetTop + next * (run.offsetHeight - innerHeight), + behavior, }); - options.hidden = assets.length < 2; } -function applyRelease(release) { - if (!release?.available) { - setFallbackRelease(); - return; - } +function stepStory(direction) { + const nextIndex = clamp(currentStopIndex + direction, 0, stops.length - 1); + if (nextIndex !== currentStopIndex) scrollToStop(nextIndex); +} - const version = cleanVersion(release.version || release.tag_name); - const published = releaseDate(release.published_at); - const assets = normalizedAssets(release); - const primary = assets.find((asset) => /universal/i.test(asset.name)) || (assets.length === 1 ? assets[0] : null); +addEventListener("scroll", () => { + targetProgress = progressFromScroll(); +}, { passive: true }); - if (!assets.length) { - setFallbackRelease(); - return; +addEventListener("scrollend", () => { + const nearestIndex = stops.indexOf(nearestStop(progressFromScroll())); + const nearestProgress = stops[nearestIndex].at; + if (nearestIndex !== currentStopIndex || Math.abs(progressFromScroll() - nearestProgress) > 0.002) { + scrollToStop(nearestIndex); } +}, { passive: true }); - renderDownloadOptions(assets); +addEventListener("resize", () => { + updateCanvasScale(); + targetProgress = progressFromScroll(); +}, { passive: true }); - document.querySelectorAll("[data-download-link]").forEach((link) => { - link.href = primary ? new URL(primary.download_url || LOCAL_DMG, document.baseURI).href : "#download"; - if (primary) link.setAttribute("download", primary.name); - else link.removeAttribute("download"); - }); - document.querySelectorAll("[data-download-label]").forEach((label, index) => { - if (!primary) { - label.textContent = "选择 macOS 版本"; - } else { - label.textContent = index === 0 && version ? `下载 v${version}` : `下载${version ? ` v${version}` : "最新版"} DMG`; - } +progressButtons.forEach(button => { + button.addEventListener("click", event => { + event.preventDefault(); + const index = button.dataset.stop === undefined + ? stops.findIndex(stop => stop.at === Number(button.dataset.progress)) + : Number(button.dataset.stop); + if (index >= 0) scrollToStop(index); }); +}); - const versionLabel = document.querySelector("[data-release-version]"); - if (versionLabel && version) versionLabel.textContent = `v${version}`; +addEventListener("keydown", event => { + if (!["ArrowRight", "ArrowDown", "ArrowLeft", "ArrowUp"].includes(event.key)) return; + const direction = event.key === "ArrowRight" || event.key === "ArrowDown" ? 1 : -1; + event.preventDefault(); + stepStory(direction); +}); - const meta = document.querySelector("[data-release-meta]"); - if (meta) { - meta.textContent = ["macOS 14 及以上", version && `v${version}`, primary && fileSize(primary.size), published] - .filter(Boolean) - .join(" · "); - } +[...workflowVideos, relationsVideo].filter(Boolean).forEach(video => { + video.addEventListener("loadedmetadata", () => paint(renderedProgress), { once: true }); +}); - const assetLabel = document.querySelector("[data-asset-name]"); - if (assetLabel) { - assetLabel.textContent = primary - ? [primary.name, fileSize(primary.size)].filter(Boolean).join(" · ") - : `${assets.length} 个安装包可选`; - } -} +updateCanvasScale(); +targetProgress = progressFromScroll(); +renderedProgress = targetProgress; +currentStopIndex = stops.indexOf(nearestStop(targetProgress)); +paint(renderedProgress); +requestAnimationFrame(frame); -async function resolveLatestRelease() { +async function resolvePublishedDownload() { try { - const response = await fetch(RELEASE_MANIFEST, { cache: "no-store" }); - if (!response.ok) throw new Error(`release manifest unavailable: ${response.status}`); - applyRelease(await response.json()); + const response = await fetch("./release.json", { cache: "no-store" }); + if (!response.ok) return; + const release = await response.json(); + const assets = Array.isArray(release?.assets) + ? release.assets.filter(asset => asset?.name && asset?.download_url) + : []; + const asset = assets.find(item => /universal/i.test(item.name)) || (assets.length === 1 ? assets[0] : null); + if (!release?.available || !asset) return; + const downloadUrl = new URL(asset.download_url, document.baseURI); + document.querySelectorAll("[data-download-link]").forEach(link => { + link.href = downloadUrl.href; + link.download = asset.name; + }); } catch { - setFallbackRelease(); + document.querySelectorAll("[data-download-link]").forEach(link => { + link.href = releasesUrl; + link.removeAttribute("download"); + }); } } -resolveLatestRelease(); +resolvePublishedDownload(); diff --git a/website/styles.css b/website/styles.css index c576c8e7..a8ca3605 100644 --- a/website/styles.css +++ b/website/styles.css @@ -1,1702 +1,1284 @@ @font-face { - font-family: "WeiBei Stele"; - src: url("./assets/fonts/WeiBeiStele.ttf") format("truetype"); - font-display: swap; - font-style: normal; - font-weight: 400; -} - -@font-face { - font-family: "WeiBei Stele Mono"; - src: url("./assets/fonts/WeiBeiSteleMono.ttf") format("truetype"); - font-display: swap; - font-style: normal; - font-weight: 400; -} - -@font-face { - font-family: "Noto Serif SC Web"; - src: url("./assets/fonts/NotoSerifSC-Web-400.woff2") format("woff2"); - font-display: swap; - font-style: normal; - font-weight: 400; -} - -@font-face { - font-family: "Noto Serif SC Web"; - src: url("./assets/fonts/NotoSerifSC-Web-600.woff2") format("woff2"); - font-display: swap; - font-style: normal; - font-weight: 600 700; + font-family: "WeiBeiStele"; + src: url("./assets/WeiBeiStele.ttf") format("truetype"); } @font-face { - font-family: "Noto Sans SC Web"; - src: url("./assets/fonts/NotoSansSC-Web-400.woff2") format("woff2"); - font-display: swap; - font-style: normal; - font-weight: 400 700; + font-family: "WeiBeiSteleMono"; + src: url("./assets/WeiBeiSteleMono.ttf") format("truetype"); } :root { - --brand-paper: #f2e2ca; - --paper: #f4ead5; - --paper-raised: #f9f1de; - --paper-inset: #e8dbbf; - --ink: #1d1814; - --brand-ink: #231f1c; - --ink-secondary: #55493e; - --ink-tertiary: #7d6e5d; - --brand-cinnabar: #aa2a23; - --cinnabar: #91261b; - --stone: #4d667a; - --link: #305469; - --moss: #3b624c; - --hairline: rgba(83, 67, 50, 0.22); - --hairline-strong: rgba(83, 67, 50, 0.38); - --shadow: rgba(65, 42, 24, 0.16); - --page: 1320px; - --serif: ui-serif, "Songti SC", "STSong", "Noto Serif SC Web", "Noto Serif CJK SC", serif; - --sans: -apple-system, BlinkMacSystemFont, "SF Pro Text", "PingFang SC", "Noto Sans SC Web", "Noto Sans CJK SC", sans-serif; - --stele: "WeiBei Stele", serif; - --stele-mono: "WeiBei Stele Mono", monospace; -} - -html[data-theme="inkstone"] { - --brand-paper: #0f0f0f; - --paper: #0f0f0f; - --paper-raised: #151515; - --paper-inset: #1c1c1c; - --ink: #d7cbb0; - --brand-ink: #d7cbb0; - --ink-secondary: #9b9178; - --ink-tertiary: #6f6655; - --brand-cinnabar: #a6362b; - --cinnabar: #a6362b; - --stone: #c8b98a; - --link: #c8b98a; - --moss: #b88a42; - --hairline: rgba(155, 145, 120, 0.25); - --hairline-strong: rgba(155, 145, 120, 0.42); - --shadow: rgba(0, 0, 0, 0.5); + --paper: #f2e2ca; + --paper-light: #f8eedb; + --paper-deep: #e9d3b3; + --ink: #231f1b; + --ink-soft: #5c5147; + --stone: #496579; + --cinnabar: #aa2f23; + --rule: rgba(35, 31, 27, 0.22); + --stage-mark-opacity: 0.92; + --serif: "Songti SC", "STSong", "Noto Serif CJK SC", serif; + --sans: -apple-system, BlinkMacSystemFont, "PingFang SC", "Helvetica Neue", sans-serif; + --stele: "WeiBeiStele", var(--serif); + --mono: "WeiBeiSteleMono", ui-monospace, monospace; } * { box-sizing: border-box; } -html { - scroll-behavior: smooth; - scroll-padding-top: 76px; - color-scheme: light; - background: var(--paper); -} - -html[data-theme="inkstone"] { - color-scheme: dark; -} - +html, body { margin: 0; - color: var(--ink); background: var(--paper); + color: var(--ink); font-family: var(--sans); - -webkit-font-smoothing: antialiased; - text-rendering: optimizeLegibility; - transition: color 420ms ease, background-color 420ms ease; } -a { - color: inherit; - text-decoration: none; +body { + overflow-x: hidden; } -button, a { - -webkit-tap-highlight-color: transparent; -} - -button { color: inherit; - font: inherit; + text-decoration: none; } -img, -svg { - display: block; - max-width: 100%; +figure, +h1, +h2, +p { + margin: 0; } -::selection { - color: var(--ink); - background: color-mix(in srgb, var(--stone) 28%, transparent); +img { + display: block; } -.skip-link { - position: fixed; - top: 8px; - left: 8px; - z-index: 100; - padding: 10px 14px; - color: var(--paper-raised); - background: var(--ink); - transform: translateY(-160%); +.frame { + position: relative; + width: 100vw; + height: 100vh; + min-height: 760px; + overflow: hidden; + isolation: isolate; + background: + radial-gradient(circle at 12% 9%, rgba(255, 255, 255, 0.56), transparent 31%), + radial-gradient(circle at 83% 84%, rgba(141, 101, 56, 0.08), transparent 34%), + var(--paper); + border-bottom: 1px solid var(--rule); } -.skip-link:focus { - transform: translateY(0); +.frame::before { + position: absolute; + inset: 0; + z-index: -1; + content: ""; + background: url("./assets/paper-texture.jpg") center / 720px repeat; + opacity: 0.32; + mix-blend-mode: multiply; + pointer-events: none; } -:focus-visible { - outline: 2px solid var(--link); - outline-offset: 4px; +.frame h1, +.frame h2 { + font-family: var(--serif); + font-weight: 600; + letter-spacing: -0.055em; } -.site-header { - position: sticky; - top: 0; - z-index: 20; - display: grid; - grid-template-columns: 1fr auto 1fr; +.site-head, +.section-head { + position: absolute; + z-index: 12; + top: 34px; + right: 4.6vw; + left: 4.6vw; + display: flex; + height: 98px; align-items: center; - min-height: 72px; - padding: 0 max(24px, calc((100vw - var(--page)) / 2)); - border-bottom: 1px solid transparent; - background: color-mix(in srgb, var(--paper) 88%, transparent); - backdrop-filter: blur(18px) saturate(0.76); - transition: min-height 180ms ease, border-color 180ms ease, background-color 420ms ease; + justify-content: space-between; + border-bottom: 1px solid var(--rule); } -.site-header.is-scrolled { - min-height: 60px; - border-bottom-color: var(--hairline); +.brand, +.mini-brand { + display: inline-flex; + align-items: center; + color: var(--ink); } .brand { - display: inline-flex; - align-items: center; - justify-self: start; - gap: 10px; - width: fit-content; + gap: 18px; } -.brand-mark { - width: 34px; - height: 34px; - flex: 0 0 auto; +.brand img { + width: 76px; + height: 76px; } -.mark-ink { - fill: var(--brand-ink); +.brand span { + display: grid; + gap: 2px; } -.mark-seal { - fill: var(--brand-cinnabar); +.brand strong { + font-family: var(--serif); + font-size: 38px; + letter-spacing: 0.15em; } -.brand-word { +.brand small { font-family: var(--stele); - font-size: 17px; - line-height: 1; - letter-spacing: 0.11em; + font-size: 15px; + letter-spacing: 0.36em; } -.brand-name { - padding-left: 9px; - border-left: 1px solid var(--hairline-strong); - color: var(--ink-secondary); +.site-head nav { + display: flex; + gap: 88px; font-family: var(--serif); - font-size: 15px; - font-weight: 650; + font-size: 26px; } -.site-nav { - display: flex; - align-items: center; - gap: 34px; - color: var(--ink-secondary); - font-size: 13px; +.mini-brand { + gap: 13px; + font-family: var(--serif); + font-size: 28px; + letter-spacing: 0.12em; } -.site-nav a, -footer nav a { - position: relative; +.mini-brand img { + width: 54px; + height: 54px; +} + +.folio, +.eyebrow { + font-family: var(--mono); + letter-spacing: 0.18em; + text-transform: uppercase; +} + +.folio { + color: var(--ink-soft); + font-size: 20px; +} + +.eyebrow { + color: var(--cinnabar); + font-size: 22px; } -.site-nav a::after, -footer nav a::after { +.app-window { position: absolute; - right: 0; - bottom: -7px; - left: 0; - height: 1px; - content: ""; - background: var(--link); - transform: scaleX(0); - transform-origin: right; - transition: transform 180ms ease; + overflow: hidden; + background: #f4ead7; + border: 1px solid rgba(35, 31, 27, 0.2); + box-shadow: 0 36px 90px rgba(61, 43, 20, 0.18); +} + +.app-window > img { + width: 100%; + height: auto; + max-width: none; +} + +/* 01 / 品牌开场 */ +.hero-copy { + position: absolute; + z-index: 6; + top: 260px; + left: 5.3vw; + width: 63%; +} + +.hero-copy h1 { + margin-top: 24px; + font-size: clamp(92px, 5.4vw, 158px); + line-height: 0.92; } -.site-nav a:hover::after, -.site-nav a:focus-visible::after, -footer nav a:hover::after, -footer nav a:focus-visible::after { - transform: scaleX(1); - transform-origin: left; +.hero-copy .lead { + margin-top: 34px; + color: var(--ink-soft); + font-family: var(--serif); + font-size: clamp(25px, 1.45vw, 42px); + letter-spacing: 0.035em; } -.header-actions { +.actions { display: flex; align-items: center; - justify-self: end; - gap: 8px; + gap: 58px; + margin-top: 0; + font-family: var(--serif); + font-size: 27px; } -.theme-toggle, -.appearance-button { +.button-seal { display: inline-flex; + height: 76px; align-items: center; - gap: 8px; - border: 0; - color: var(--ink-secondary); - background: transparent; - cursor: pointer; + padding: 0 46px; + color: #fff8e9; + background: var(--cinnabar); + box-shadow: 0 18px 34px rgba(170, 47, 35, 0.17); } -.theme-toggle { - min-height: 38px; - padding: 0 10px; - font-size: 12px; +.button-line { + padding: 14px 0; + border-bottom: 1px solid var(--stone); + color: var(--stone); } -.theme-symbol { - position: relative; - width: 11px; - height: 11px; - border: 1px solid var(--ink-tertiary); - border-radius: 50%; +.button-line span { + margin-left: 18px; } -.theme-symbol::after { +.hero-mark { position: absolute; - inset: 2px 5px 2px 2px; - content: ""; - background: var(--ink); -} - -.header-download { - display: inline-flex; - align-items: center; - gap: 7px; - min-height: 38px; - padding: 0 14px; - border: 1px solid var(--hairline-strong); - color: var(--ink); - font-size: 12px; - transition: color 180ms ease, border-color 180ms ease, background 180ms ease; + z-index: 0; + top: 92px; + right: 50px; + width: 950px; + mix-blend-mode: multiply; } -.header-download:hover { - border-color: var(--cinnabar); - color: #f8ead4; - background: var(--cinnabar); +.hero-window { + z-index: 4; + top: 790px; + right: 6.6vw; + left: 11.8vw; + height: 970px; + border-radius: 28px 28px 0 0; } -.header-download svg, -.text-link svg, -.button svg { - fill: none; - stroke: currentColor; - stroke-linecap: square; - stroke-linejoin: miter; - stroke-width: 1.45; +.hero-window img { + object-position: center top; } -.header-download svg { - width: 15px; +.vertical-note { + position: absolute; + bottom: 110px; + left: 4.7vw; + color: rgba(35, 31, 27, 0.55); + font-family: var(--serif); + font-size: 18px; + letter-spacing: 0.18em; + writing-mode: vertical-rl; } -.section { - max-width: var(--page); - margin: 0 auto; - padding-right: 24px; - padding-left: 24px; +/* 02 / 三栏 */ +.panes h2 { + position: absolute; + z-index: 8; + top: 158px; + left: 4.8vw; + font-size: clamp(76px, 4.2vw, 122px); + line-height: 1; } -.kicker { - margin: 0; - color: var(--stone); - font-family: var(--stele-mono); - font-size: 11px; - line-height: 1.3; - letter-spacing: 0.13em; -} - -.hero h1, -.section-intro h2, -.source-copy h2, -.relations-heading h2, -.appearance h2, -.download-copy h2 { - margin: 0; +.panes-sub { + position: absolute; + z-index: 8; + top: 198px; + right: 5vw; + width: 820px; + color: var(--ink-soft); font-family: var(--serif); - font-weight: 650; - letter-spacing: -0.045em; + font-size: 30px; + line-height: 1.8; } -.hero { +.pane-names { + position: absolute; + z-index: 9; + top: 130px; + right: 4.5vw; + left: 4.5vw; display: grid; - grid-template-columns: minmax(410px, 0.86fr) minmax(420px, 0.74fr); - gap: 48px clamp(40px, 6vw, 96px); - max-width: var(--page); - margin: 0 auto; - padding: clamp(70px, 8vw, 112px) 24px 128px; -} - -.hero-copy { - align-self: center; - padding: 30px 0 22px; + grid-template-columns: repeat(3, 1fr); + pointer-events: none; } -.hero h1 { - max-width: 710px; - margin-top: 26px; - font-size: clamp(58px, 6.3vw, 92px); - line-height: 1.04; +.pane-names span { + display: flex; + align-items: baseline; + justify-content: center; + gap: 20px; } -.hero-claim { - margin: 30px 0 0; - color: var(--ink); +.pane-names b { font-family: var(--serif); - font-size: clamp(23px, 2.15vw, 31px); + font-size: 102px; font-weight: 600; - line-height: 1.45; + line-height: 1; } -.hero-detail { - max-width: 580px; - margin: 14px 0 0; - color: var(--ink-secondary); - font-size: 15px; - line-height: 1.8; +.pane-names small { + color: var(--cinnabar); + font-family: var(--mono); + font-size: 20px; + letter-spacing: 0.18em; } -.hero-actions { - display: flex; - flex-wrap: wrap; - align-items: center; - gap: 22px; - margin-top: 34px; +.panes-window { + z-index: 3; + top: 435px; + right: 2.8vw; + left: 2.8vw; + height: 1420px; + border-radius: 30px 30px 0 0; } -.button { - display: inline-flex; - align-items: center; - justify-content: center; - gap: 14px; - min-height: 48px; - padding: 0 20px; - border: 1px solid transparent; - font-size: 14px; - font-weight: 650; - transition: transform 180ms ease, color 180ms ease, background 180ms ease, box-shadow 180ms ease; +.learning-thread { + position: absolute; + z-index: 7; + right: 9.5%; + bottom: 116px; + left: 9.5%; + height: 2px; + background: rgba(170, 47, 35, 0.66); } -.button svg { +.learning-thread i { + position: absolute; + top: 50%; width: 18px; + height: 18px; + border: 4px solid var(--paper-light); + border-radius: 50%; + background: var(--cinnabar); + transform: translate(-50%, -50%); + box-shadow: 0 0 0 1px rgba(170, 47, 35, 0.35); } -.button:hover { - transform: translateY(-2px); +.learning-thread i:nth-child(1) { left: 16.66%; } +.learning-thread i:nth-child(2) { left: 50%; } +.learning-thread i:nth-child(3) { left: 83.33%; } + +.margin-caption { + position: absolute; + z-index: 10; + right: 36px; + bottom: 165px; + color: var(--ink-soft); + font-family: var(--serif); + font-size: 18px; + line-height: 1.7; + writing-mode: vertical-rl; } -.button-primary { - color: #f8ead4; - background: var(--cinnabar); - box-shadow: 0 10px 28px color-mix(in srgb, var(--cinnabar) 20%, transparent); +/* 03 / 上下文 */ +.context { + background: + linear-gradient(125deg, rgba(255, 255, 255, 0.48), transparent 46%), + var(--paper-deep); } -.button-primary:hover { - box-shadow: 0 14px 34px color-mix(in srgb, var(--cinnabar) 30%, transparent); +.context h2 { + position: absolute; + z-index: 10; + top: 166px; + left: 4.8vw; + font-size: clamp(84px, 4.8vw, 138px); + line-height: 1; } -.text-link { - display: inline-flex; - align-items: center; - gap: 7px; - padding: 10px 0; - border-bottom: 1px solid var(--hairline-strong); - color: var(--ink-secondary); - font-size: 13px; +.context-sub { + position: absolute; + z-index: 10; + top: 188px; + right: 5vw; + width: 930px; + color: var(--ink-soft); + font-family: var(--serif); + font-size: 29px; + line-height: 1.85; } -.text-link:hover { - border-color: var(--link); - color: var(--link); +.ask-glyph { + position: absolute; + z-index: 0; + top: 520px; + left: -150px; + color: rgba(73, 101, 121, 0.13); + font-family: var(--serif); + font-size: 820px; + font-weight: 700; + line-height: 0.8; } -.text-link svg { - width: 15px; +.context-window { + z-index: 3; + top: 370px; + left: -90px; + width: 3060px; + height: 1600px; + border-radius: 28px 28px 0 0; } -.hero-meta { +.context-thread { + position: absolute; + z-index: 7; + right: 210px; + bottom: 140px; + left: 210px; display: grid; - grid-template-columns: repeat(3, max-content); - gap: 0; - margin: 44px 0 0; + grid-template-columns: auto 1fr auto 1fr auto; + align-items: center; + gap: 26px; + color: var(--ink); + font-family: var(--serif); + font-size: 23px; } -.hero-meta div { - padding: 0 24px; - border-left: 1px solid var(--hairline); +.context-thread i { + height: 2px; + background: linear-gradient(90deg, var(--cinnabar), rgba(170, 47, 35, 0.34)); } -.hero-meta div:first-child { - padding-left: 0; - border-left: 0; +.context-thread span { + padding: 9px 16px 11px; + background: rgba(248, 238, 219, 0.92); + box-shadow: 0 0 0 1px rgba(35, 31, 27, 0.15); } -.hero-meta dt { - margin-bottom: 7px; - color: var(--ink-tertiary); - font-size: 10px; - letter-spacing: 0.14em; +.context-side { + position: absolute; + z-index: 8; + right: 30px; + bottom: 255px; + color: var(--ink-soft); + font-family: var(--serif); + font-size: 18px; + line-height: 1.8; + writing-mode: vertical-rl; } -.hero-meta dd { - margin: 0; - font-family: var(--stele-mono); - font-size: 12px; - letter-spacing: 0.06em; +/* 04 / 关系台 */ +.relations { + background: var(--paper-light); } -.hero-brand-surface { - position: relative; - min-height: 460px; - overflow: hidden; - border: 1px solid color-mix(in srgb, var(--brand-ink) 13%, transparent); - color: var(--brand-ink); - background: var(--brand-paper); - isolation: isolate; +.relations::before { + opacity: 0.2; } -.hero-brand-surface::before, -.download-panel::before { +.relations-screen { position: absolute; + z-index: 0; inset: 0; - z-index: -1; - content: ""; - background: url("./assets/brand/paper-texture.webp") center / cover; - opacity: 0.62; - mix-blend-mode: multiply; -} - -html[data-theme="inkstone"] .hero-brand-surface::before, -html[data-theme="inkstone"] .download-panel::before { - opacity: 0.055; - filter: grayscale(1) invert(1); - mix-blend-mode: screen; + width: 100%; + height: auto; } -.hero-mark { +.relations-wash { position: absolute; - top: 26px; - right: -118px; - width: min(540px, 112%); - color: var(--brand-ink); -} - -.hero-mark-paper { - mix-blend-mode: multiply; + z-index: 2; + inset: 0; + background: linear-gradient(180deg, rgba(242, 226, 202, 0.02) 0 54%, rgba(242, 226, 202, 0.72) 74%, var(--paper) 100%); } -.hero-mark-inkstone { +.relation-head { display: none; } -html[data-theme="inkstone"] .hero-mark-paper { - display: none; +.relations-small { + position: absolute; + z-index: 7; + top: 260px; + left: 5.3vw; + font-family: var(--serif); + font-size: 30px; + letter-spacing: 0.11em; } -html[data-theme="inkstone"] .hero-mark-inkstone { - display: block; +.relations h2 { + position: absolute; + z-index: 7; + right: 7.5vw; + bottom: 135px; + font-size: clamp(130px, 8.6vw, 248px); + line-height: 0.9; } -.hero-brand-surface p { +.relations-note { position: absolute; - bottom: 38px; - left: 36px; - z-index: 2; - margin: 0; - color: var(--ink-secondary); - font-family: var(--stele-mono); - font-size: 14px; + z-index: 7; + right: 7.7vw; + bottom: 410px; + width: 600px; + color: var(--ink-soft); + font-family: var(--serif); + font-size: 29px; line-height: 1.8; - letter-spacing: 0.16em; } -.brand-ruling { +.relation-seal { position: absolute; - z-index: 1; - width: 152px; - height: 1px; - background: var(--brand-ink); - opacity: 0.52; + z-index: 7; + right: 4.3vw; + bottom: 162px; + width: 31px; + height: 31px; + background: var(--cinnabar); } -.brand-ruling::after { - position: absolute; - top: 10px; - left: 0; - width: 76%; - height: 1px; - content: ""; - background: inherit; +/* 05 / 出处 */ +.provenance { + color: var(--paper-light); + background: + radial-gradient(circle at 12% 12%, rgba(255, 255, 255, 0.035), transparent 34%), + #1e1a17; } -.brand-ruling-a { - top: 44px; - left: 36px; +.provenance::before { + opacity: 0.08; + filter: invert(1); } -.brand-ruling-b { - top: 86px; - left: 36px; - width: 90px; +.section-head.dark { + border-color: rgba(242, 226, 202, 0.25); } -.source-anchor { +.dark .mini-brand, +.dark .folio { + color: var(--paper-light); +} + +.provenance-copy { position: absolute; - right: 34px; - bottom: 34px; - width: 13px; - height: 13px; - background: var(--brand-cinnabar); + z-index: 9; + top: 240px; + left: 5vw; + width: 780px; } -.workspace-figure, -.relations-figure { - margin: 0; +.evidence-glyph { + position: absolute; + z-index: -1; + top: -90px; + left: -140px; + color: rgba(242, 226, 202, 0.055); + font-family: var(--serif); + font-size: 650px; + font-weight: 700; + line-height: 1; } -.workspace-figure { - grid-column: 1 / -1; - margin-top: 12px; - border: 1px solid var(--hairline-strong); - background: var(--paper-raised); - box-shadow: 0 34px 80px var(--shadow); +.provenance h2 { + margin-top: 52px; + font-size: clamp(88px, 5vw, 144px); + line-height: 0.9; } -.window-bar { - position: relative; - display: flex; - align-items: center; - gap: 7px; - height: 42px; - padding: 0 16px; - border-bottom: 1px solid var(--hairline); - background: color-mix(in srgb, var(--paper-raised) 88%, transparent); +.provenance-copy > p:last-child { + width: 580px; + margin-top: 50px; + color: rgba(242, 226, 202, 0.68); + font-family: var(--serif); + font-size: 28px; + line-height: 1.85; } -.window-bar span { - width: 8px; - height: 8px; - border: 1px solid var(--hairline-strong); - border-radius: 50%; +.provenance-window { + z-index: 3; + top: 200px; + right: -140px; + width: 2180px; + height: 1360px; + border-color: rgba(242, 226, 202, 0.22); + border-radius: 30px 0 0 30px; + box-shadow: 0 40px 110px rgba(0, 0, 0, 0.4); } -.window-bar span:first-child { - border-color: var(--cinnabar); - background: var(--cinnabar); +.provenance-window img { + width: 2880px; + max-width: none; + transform: translateX(-950px); } -.window-bar b { +.source-rule { position: absolute; - left: 50%; - color: var(--ink-tertiary); - font-family: var(--stele-mono); - font-size: 9px; - font-weight: 400; - letter-spacing: 0.12em; - transform: translateX(-50%); + z-index: 8; + right: 150px; + bottom: 105px; + left: 890px; + display: flex; + align-items: center; + gap: 28px; + color: var(--paper-light); + font-family: var(--mono); + font-size: 20px; + letter-spacing: 0.14em; } -.workspace-viewport { - overflow: hidden; - background: var(--paper-inset); +.source-rule i { + height: 2px; + flex: 1; + background: var(--cinnabar); } -.workspace-viewport img { - width: 100%; - height: auto; +.source-rule span { + padding: 8px 12px; + color: var(--ink); + background: var(--paper); } -.workspace-figure figcaption, -.relations-figure figcaption { - display: flex; - gap: 16px; - align-items: center; - min-height: 54px; - padding: 12px 18px; - border-top: 1px solid var(--hairline); - color: var(--ink-secondary); - font-size: 12px; - line-height: 1.5; +/* 06 / 收束 */ +.finish-mark { + position: absolute; + z-index: 0; + top: 150px; + left: -230px; + width: 1580px; + mix-blend-mode: multiply; } -.workspace-figure figcaption span, -.relations-figure figcaption span { - color: var(--cinnabar); - font-family: var(--stele-mono); - font-size: 12px; - letter-spacing: 0.08em; +.finish-copy { + position: absolute; + z-index: 8; + top: 210px; + right: 5vw; + width: 1230px; } -.workflow { - padding-top: 132px; - padding-bottom: 138px; +.finish-copy > p { + margin-bottom: 28px; + color: var(--ink-soft); + font-family: var(--serif); + font-size: 30px; + letter-spacing: 0.06em; } -.section-intro { - display: grid; - grid-template-columns: 0.72fr 1fr; - gap: 20px 80px; - align-items: end; - max-width: 980px; +.finish h2 { + font-size: clamp(112px, 6.4vw, 184px); + line-height: 0.9; } -.section-intro .kicker { - grid-column: 1 / -1; +.download { + display: inline-grid; + grid-template-columns: 62px auto 56px; + min-width: 560px; + height: 94px; + margin-top: 55px; + align-items: center; + gap: 22px; + padding: 0 30px 0 18px; + color: #fff8e9; + background: var(--cinnabar); + font-family: var(--serif); + font-size: 27px; } -.section-intro h2, -.source-copy h2, -.relations-heading h2, -.appearance h2, -.download-copy h2 { - font-size: clamp(40px, 4.5vw, 66px); - line-height: 1.12; +.download img { + width: 62px; + height: 62px; } -.section-intro > p:last-child, -.source-copy > p, -.relations-heading > p, -.appearance-copy > p:not(.kicker) { - margin: 0; - color: var(--ink-secondary); - font-size: 15px; - line-height: 1.9; +.download b { + font-size: 34px; + font-weight: 400; + text-align: right; } -.workflow-line { - position: relative; - display: grid; - grid-template-columns: repeat(3, 1fr); - gap: 0; - margin: 78px 0 0; - padding: 0; - border-top: 1px solid var(--hairline-strong); - list-style: none; +.finish-window { + z-index: 4; + top: 870px; + right: -160px; + left: 650px; + height: 980px; + border-radius: 30px 0 0 0; } -.workflow-line::before { +.finish footer { position: absolute; - top: -4px; - left: 0; - width: 7px; - height: 7px; - content: ""; - background: var(--cinnabar); -} - -.workflow-line li { - min-height: 320px; - padding: 30px clamp(24px, 3vw, 44px) 30px; - border-left: 1px solid var(--hairline); -} - -.workflow-line li:first-child { - padding-left: 0; - border-left: 0; -} - -.step-heading { + z-index: 10; + right: 4.6vw; + bottom: 28px; + left: 4.6vw; display: flex; - align-items: baseline; justify-content: space-between; - color: var(--stone); + color: rgba(35, 31, 27, 0.6); + font-family: var(--mono); + font-size: 18px; + letter-spacing: 0.09em; } -.step-heading span, -.step-heading b { - font-family: var(--stele-mono); - font-size: 12px; - font-weight: 400; - letter-spacing: 0.12em; +/* 05 / 人确认写入 */ +.writeback { + background: + linear-gradient(125deg, rgba(255, 255, 255, 0.42), transparent 48%), + var(--paper-deep); } -.workflow-line h3 { - margin: 86px 0 16px; - font-family: var(--serif); - font-size: 24px; - font-weight: 650; - letter-spacing: -0.02em; +.writeback h2 { + position: absolute; + z-index: 10; + top: 166px; + left: 4.8vw; + font-size: clamp(84px, 4.8vw, 138px); + line-height: 1; } -.workflow-line p { - margin: 0; - color: var(--ink-secondary); - font-size: 14px; +.writeback-sub { + position: absolute; + z-index: 10; + top: 188px; + right: 5vw; + width: 900px; + color: var(--ink-soft); + font-family: var(--serif); + font-size: 29px; line-height: 1.85; } -.source-section { - display: grid; - grid-template-columns: minmax(330px, 0.72fr) minmax(520px, 1fr); - gap: clamp(54px, 8vw, 116px); - align-items: center; - padding-top: 122px; - padding-bottom: 122px; - border-top: 1px solid var(--hairline); -} - -.source-copy h2 { - margin-top: 24px; -} - -.source-copy > p { - max-width: 480px; - margin-top: 26px; -} - -.source-types { - display: grid; - gap: 0; - margin: 38px 0 0; - padding: 0; - border-top: 1px solid var(--hairline); - list-style: none; -} - -.source-types li { - display: flex; - align-items: center; - gap: 14px; - padding: 13px 0; - border-bottom: 1px solid var(--hairline); - color: var(--ink-secondary); - font-size: 13px; -} - -.source-types span { - display: grid; - place-items: center; - width: 26px; - height: 26px; - border: 1px solid var(--stone); - color: var(--link); +.note-glyph { + position: absolute; + z-index: 0; + top: 520px; + right: -170px; + color: rgba(73, 101, 121, 0.12); font-family: var(--serif); + font-size: 820px; font-weight: 700; + line-height: 0.8; } -.source-proof { - position: relative; - min-height: 520px; - padding: 38px 42px 48px; - border: 1px solid var(--hairline-strong); - background: var(--paper-raised); - box-shadow: 16px 18px 0 color-mix(in srgb, var(--paper-inset) 75%, transparent); -} - -.proof-label { - padding-bottom: 20px; - border-bottom: 1px solid var(--hairline); - color: var(--stone); - font-family: var(--stele-mono); - font-size: 11px; - letter-spacing: 0.13em; -} - -.proof-answer { - max-width: 610px; - margin: 38px 0 46px; - font-family: var(--serif); - font-size: clamp(22px, 2.2vw, 31px); - line-height: 1.65; -} - -.proof-citations { - display: grid; - gap: 0; - border-top: 1px solid var(--hairline); -} - -.proof-citations a { - display: grid; - grid-template-columns: 34px 1fr auto; - gap: 14px; - align-items: center; - min-height: 57px; - border-bottom: 1px solid var(--hairline); - transition: color 140ms ease, background 140ms ease; -} - -.proof-citations a:hover { - color: var(--link); - background: color-mix(in srgb, var(--stone) 7%, transparent); -} - -.proof-citations b { - color: var(--link); - font-family: var(--stele-mono); - font-size: 11px; - font-weight: 400; -} - -.proof-citations span { - font-family: var(--serif); - font-size: 14px; - font-weight: 650; +.writeback-window { + z-index: 3; + top: 370px; + right: auto; + left: 0; + width: 2880px; + height: 1600px; + border-radius: 28px 28px 0 0; } -.proof-citations em { - color: var(--ink-tertiary); - font-family: var(--stele-mono); - font-size: 10px; - font-style: normal; - letter-spacing: 0.05em; +.writeback-window video { + width: 2880px; + height: 1682px; + object-fit: cover; + object-position: center top; + transform: none; } -.proof-anchor { +.writeback-thread { position: absolute; - right: 22px; - bottom: 22px; - width: 11px; - height: 11px; - background: var(--cinnabar); -} - -.relations { - padding-top: 138px; - padding-bottom: 138px; -} - -.relations-heading { - display: grid; - grid-template-columns: 1fr minmax(280px, 420px); - gap: 60px; - align-items: end; -} - -.relations-heading h2 { - margin-top: 22px; -} - -.relations-figure { - margin-top: 66px; - border: 1px solid var(--hairline-strong); - background: var(--paper-raised); - box-shadow: 0 30px 64px var(--shadow); -} - -.control-section { + z-index: 7; + right: 210px; + bottom: 140px; + left: 210px; display: grid; - grid-template-columns: 0.72fr 1fr; - gap: 72px 96px; - padding-top: 124px; - padding-bottom: 136px; - border-top: 1px solid var(--hairline); -} - -.control-quote blockquote { - margin: 24px 0 0; + grid-template-columns: auto 1fr auto 1fr auto; + align-items: center; + gap: 26px; + color: var(--ink); font-family: var(--serif); - font-size: clamp(34px, 3.8vw, 55px); - font-weight: 650; - line-height: 1.3; - letter-spacing: -0.04em; -} - -.note-proposal { - padding: 28px 30px 26px; - border-top: 3px solid var(--cinnabar); - border-bottom: 1px solid var(--hairline-strong); - background: var(--paper-raised); -} - -.proposal-top { - display: flex; - justify-content: space-between; - padding-bottom: 17px; - border-bottom: 1px solid var(--hairline); - color: var(--ink-tertiary); - font-size: 11px; + font-size: 23px; } -.proposal-top span { - color: var(--cinnabar); - font-weight: 700; +.writeback-thread i { + height: 2px; + background: linear-gradient(90deg, var(--cinnabar), rgba(170, 47, 35, 0.34)); } -.proposal-top b { - font-family: var(--stele-mono); - font-weight: 400; +.writeback-thread span { + padding: 9px 16px 11px; + background: rgba(248, 238, 219, 0.92); + box-shadow: 0 0 0 1px rgba(35, 31, 27, 0.15); } -.note-proposal p { - margin: 25px 0 0; +.writeback-side { + position: absolute; + z-index: 8; + right: 30px; + bottom: 255px; + color: var(--ink-soft); font-family: var(--serif); - font-size: 16px; + font-size: 18px; line-height: 1.8; + writing-mode: vertical-rl; } -.note-proposal del { - color: var(--ink-tertiary); - text-decoration-color: var(--cinnabar); -} - -.note-proposal ins { - color: var(--ink); - text-decoration: none; - background: linear-gradient(transparent 72%, color-mix(in srgb, var(--moss) 18%, transparent) 72%); +/* 一镜到底运行层:同一台真实工作台持续在场,滚动只改变镜头与内容。 */ +:root { + --canvas-scale: 0.58; + --workspace-x: 0px; + --workspace-y: 275px; + --workspace-scale: 0.86; + --workspace-static-opacity: 1; + --workspace-flow-opacity: 0; + --workspace-relations-opacity: 0; } -.proposal-actions { - display: flex; - justify-content: flex-end; - gap: 10px; - margin-top: 28px; - font-size: 12px; +html { + scroll-behavior: auto; + scroll-snap-type: y mandatory; } -.proposal-actions span, -.proposal-actions strong { - padding: 10px 14px; - border: 1px solid var(--hairline-strong); +body { + min-width: 320px; + overflow-x: hidden; } -.proposal-actions strong { - border-color: var(--cinnabar); - color: #f8ead4; - background: var(--cinnabar); +button, +a { + -webkit-tap-highlight-color: transparent; } -.product-facts { - display: grid; - grid-column: 1 / -1; - grid-template-columns: repeat(3, 1fr); - gap: 0; - margin: 18px 0 0; - border-top: 1px solid var(--hairline-strong); +button { + color: inherit; + font: inherit; } -.product-facts div { - padding: 28px 32px 0; - border-left: 1px solid var(--hairline); +button:focus-visible, +a:focus-visible { + outline: 3px solid var(--stone); + outline-offset: 6px; } -.product-facts div:first-child { - padding-left: 0; - border-left: 0; +.skip-link { + position: fixed; + z-index: 200; + top: 12px; + left: 12px; + padding: 10px 14px; + color: var(--paper-light); + background: var(--ink); + transform: translateY(-180%); } -.product-facts dt { - margin-bottom: 16px; - color: var(--stone); - font-family: var(--stele-mono); - font-size: 11px; - letter-spacing: 0.13em; +.skip-link:focus { + transform: none; } -.product-facts dd { - margin: 0; - color: var(--ink-secondary); - font-size: 13px; - line-height: 1.8; +.scroll-run { + position: relative; + height: 700vh; } -.appearance { +.snap-points { display: grid; - grid-template-columns: 0.8fr 1.2fr; - gap: clamp(52px, 8vw, 112px); - align-items: center; - max-width: none; - padding-top: 118px; - padding-right: max(24px, calc((100vw - var(--page)) / 2)); - padding-bottom: 118px; - padding-left: max(24px, calc((100vw - var(--page)) / 2)); - color: #d7cbb0; - background: #0f0f0f; + height: 700vh; + margin-top: -100svh; + pointer-events: none; } -.appearance .kicker { - color: #c8b98a; +.snap-points i { + height: 100vh; + scroll-snap-align: start; + scroll-snap-stop: always; } -.appearance h2 { - margin-top: 22px; - color: #d7cbb0; +.stage { + position: sticky; + top: 0; + height: 100svh; + min-height: 100svh; + overflow: hidden; + isolation: isolate; + background-color: var(--paper); + background-image: + radial-gradient(circle at 12% 9%, rgba(255, 255, 255, 0.56), transparent 31%), + radial-gradient(circle at 83% 84%, rgba(141, 101, 56, 0.08), transparent 34%); } -.appearance-copy > p:not(.kicker) { - max-width: 500px; - margin-top: 24px; - color: #9b9178; +.stage.is-dark { + background-color: #1e1a17; + background-image: radial-gradient(circle at 12% 12%, rgba(255, 255, 255, 0.035), transparent 34%); } -.appearance-button { - margin-top: 34px; - padding: 10px 0; - border-bottom: 1px solid #6f6655; - color: #c8b98a; - font-size: 13px; +.stage::before { + position: absolute; + inset: 0; + content: ""; + pointer-events: none; } -.appearance-button i { - position: relative; - width: 38px; - height: 18px; - border: 1px solid #6f6655; - border-radius: 10px; +.stage::before { + z-index: 0; + background: url("./assets/paper-texture.jpg") center / 720px repeat; + opacity: 0.32; + mix-blend-mode: multiply; } -.appearance-button i::after { +.frame.scene { position: absolute; - top: 3px; - left: 3px; - width: 10px; - height: 10px; - border-radius: 50%; - content: ""; - background: #a6362b; - transition: transform 240ms ease; -} - -html[data-theme="inkstone"] .appearance-button i::after { - transform: translateX(20px); + z-index: var(--scene-z, 0); + top: 50%; + left: 50%; + width: 2880px; + height: 1620px; + min-height: 0; + border: 0; + background: transparent; + opacity: var(--scene-opacity, 0); + pointer-events: none; + transform: + translate(-50%, -50%) + scale(var(--canvas-scale)); + transform-origin: center; + will-change: opacity, transform; } -.appearance-study { - display: grid; - grid-template-columns: 84px 1fr 0.72fr; - min-height: 390px; - border: 1px solid #39362f; - background: #151515; - box-shadow: 0 28px 72px rgba(0, 0, 0, 0.42); +.frame.scene::before { + display: none; } -.study-rail { - padding: 34px 22px; - border-right: 1px solid #39362f; +.context .ask-glyph, +.writeback .note-glyph { + display: none; } -.study-rail span { - display: block; - height: 5px; - margin-bottom: 18px; - background: #6f6655; +.frame.scene[data-scene="hero"] { + --scene-opacity: 1; } -.study-rail span:first-child { - background: #a6362b; +.frame.scene.is-interactive { + pointer-events: auto; } -.study-page, -.study-note { - position: relative; - padding: 38px 34px; +.stage-mark { + position: absolute; + z-index: 2; + top: 50%; + right: -2%; + width: min(48vw, 860px); + max-width: none; + opacity: var(--stage-mark-opacity); + mix-blend-mode: multiply; + transform: translateY(-54%); + pointer-events: none; } -.study-page { - border-right: 1px solid #39362f; +.persistent-canvas { + position: absolute; + z-index: 4; + top: 50%; + left: 50%; + width: 2880px; + height: 1620px; + pointer-events: none; + transform: translate(-50%, -50%) scale(var(--canvas-scale)); + transform-origin: center; } -.study-page b, -.study-note b { - display: block; - margin-bottom: 48px; - color: #9b9178; - font-family: var(--stele-mono); - font-size: 10px; - font-weight: 400; - letter-spacing: 0.13em; +.persistent-canvas * { + pointer-events: none; } -.study-page i, -.study-note i { +.persistent-workspace { + position: absolute; + top: 30px; + left: 140px; + width: 2600px; + height: auto; + aspect-ratio: 1315 / 768; + margin: 0; + overflow: hidden; + background: #f4ead7; + border: 1px solid rgba(35, 31, 27, 0.24); + border-radius: 30px; + box-shadow: 0 42px 110px rgba(61, 43, 20, 0.22); + transform: + translate3d(var(--workspace-x), var(--workspace-y), 0) + scale(var(--workspace-scale)); + transform-origin: center top; + will-change: transform; +} + +.workspace-media { + position: absolute; + inset: 0; display: block; width: 100%; - height: 5px; - margin-bottom: 16px; - background: #403c33; + height: 100%; + max-width: none; + object-fit: contain; + object-position: center; + user-select: none; + -webkit-user-drag: none; } -.study-page i.short, -.study-note i.short { - width: 60%; +.workspace-static { + opacity: var(--workspace-static-opacity); } -.study-page i.medium { - width: 78%; +.workspace-flow { + opacity: var(--workspace-flow-opacity); } -.study-page mark { - display: block; - width: 86%; - height: 2px; - margin: -10px 0 28px; - background: #a6362b; +.workspace-relations { + z-index: 3; + opacity: var(--workspace-relations-opacity); } -.download-section { - padding: 124px max(24px, calc((100vw - var(--page)) / 2)) 104px; +.workspace-relations-still { + z-index: 2; + opacity: var(--workspace-relations-opacity); } -.download-panel { - position: relative; - display: grid; - grid-template-columns: 240px 1fr; - gap: clamp(42px, 7vw, 96px); - align-items: center; - min-height: 480px; - overflow: hidden; - padding: 62px clamp(36px, 7vw, 92px); - border: 1px solid color-mix(in srgb, var(--brand-ink) 14%, transparent); - background: var(--brand-paper); - isolation: isolate; +.workspace-static, +.workspace-flow, +.workspace-relations-still, +.workspace-relations { + will-change: opacity, transform; } -.download-panel > img { - position: relative; - z-index: 2; - width: 220px; - filter: drop-shadow(0 24px 30px color-mix(in srgb, var(--brand-ink) 17%, transparent)); +.site-head nav button, +.site-head nav a { + padding: 10px 0; + border: 0; + color: inherit; + background: transparent; + font-family: var(--serif); + font-size: 26px; + cursor: pointer; } -.download-copy { - position: relative; - z-index: 2; +.site-head nav button { + appearance: none; } -.download-copy h2 { - max-width: 680px; - margin-top: 20px; +.button-seal { + border: 0; + font-family: var(--serif); + font-size: 27px; + cursor: pointer; } -.download-meta { - margin: 24px 0 0; - color: var(--ink-secondary); - font-size: 13px; +.pane-names { + pointer-events: auto; } -.download-actions { +.pane-names button { display: flex; - flex-wrap: wrap; - align-items: center; - gap: 18px; - margin-top: 32px; -} - -.button-large { - min-height: 54px; - padding: 0 24px; + align-items: baseline; + justify-content: center; + gap: 20px; + padding: 0; + border: 0; + background: transparent; + cursor: pointer; } -.download-file { - color: var(--ink-tertiary); - font-family: var(--stele-mono); - font-size: 10px; - letter-spacing: 0.06em; +.pane-names button b { + font-family: var(--serif); + font-size: 102px; + font-weight: 600; + line-height: 1; + transition: color 180ms ease, transform 180ms ease; } -.download-options { - display: grid; - grid-template-columns: repeat(2, minmax(0, 1fr)); - gap: 0; - max-width: 660px; - margin-top: 26px; - border-top: 1px solid var(--hairline-strong); +.pane-names button small { + color: var(--cinnabar); + font-family: var(--mono); + font-size: 20px; + letter-spacing: 0.18em; } -.download-options[hidden] { - display: none; +.pane-names button:hover b, +.pane-names button:focus-visible b { + color: var(--cinnabar); + transform: translateY(-8px); } -.download-options a { - display: grid; - gap: 8px; - padding: 16px 18px 16px 0; - border-bottom: 1px solid var(--hairline); - color: var(--ink-secondary); +.app-window > video { + display: block; + max-width: none; + user-select: none; + -webkit-user-drag: none; } -.download-options a:nth-child(even) { - padding-right: 0; - padding-left: 18px; - border-left: 1px solid var(--hairline); +.context-window .workflow-video { + width: 100%; + height: 100%; + object-fit: cover; + object-position: center top; } -.download-options a:hover { - color: var(--link); +.context-window { + left: 0; + width: 2880px; + height: 1682px; } -.download-options strong { - color: var(--ink); - font-size: 13px; +.provenance-window .workflow-video { + width: 2880px; + height: 1682px; + object-fit: cover; + object-position: center top; + transform: translateX(-700px); } -.download-options span { - overflow: hidden; - font-family: var(--stele-mono); - font-size: 9px; - letter-spacing: 0.04em; - text-overflow: ellipsis; - white-space: nowrap; +.proof-steps { + display: grid; + width: 590px; + margin: 46px 0 0; + padding: 0; + border-top: 1px solid rgba(242, 226, 202, 0.26); + list-style: none; } -.download-word { - position: absolute; - right: -22px; - bottom: -28px; - z-index: 0; - color: color-mix(in srgb, var(--brand-ink) 7%, transparent); - font-family: var(--stele); - font-size: clamp(100px, 16vw, 230px); - letter-spacing: 0.03em; - white-space: nowrap; +.provenance-copy > p:nth-of-type(2) { + width: 580px; + margin-top: 50px; + color: rgba(242, 226, 202, 0.68); + font-family: var(--serif); + font-size: 28px; + line-height: 1.85; } -footer { +.proof-steps li { display: grid; - grid-template-columns: 1fr auto 1fr; + grid-template-columns: 58px 1fr; align-items: center; - max-width: var(--page); - min-height: 100px; - margin: 0 auto; - padding: 22px 24px; - border-top: 1px solid var(--hairline); + min-height: 68px; + border-bottom: 1px solid rgba(242, 226, 202, 0.16); + color: rgba(242, 226, 202, 0.5); + font-family: var(--serif); + font-size: 22px; + transition: color 220ms ease, padding 220ms ease; } -.brand-footer .brand-mark { - width: 28px; - height: 28px; +.proof-steps li b { + color: var(--cinnabar); + font-family: var(--mono); + font-size: 17px; + font-weight: 400; } -.brand-footer .brand-word { - font-size: 14px; +.proof-steps li.is-active { + padding-left: 14px; + color: var(--paper-light); } -footer p { - margin: 0; - color: var(--ink-tertiary); - font-family: var(--stele-mono); - font-size: 9px; - letter-spacing: 0.06em; +.relations-screen { + width: 100%; + height: 100%; + object-fit: cover; + object-position: center top; } -footer nav { +.relation-head { display: flex; - justify-self: end; - gap: 26px; - color: var(--ink-secondary); - font-size: 12px; -} - -.reveal { - opacity: 1; - transform: none; -} - -.reveal.reveal-ready { - opacity: 0; - transform: translateY(8px); - transition: opacity 240ms ease, transform 240ms cubic-bezier(0.22, 0.75, 0.2, 1); } -.reveal.reveal-ready[data-reveal-delay="1"] { - transition-delay: 50ms; -} - -.reveal.reveal-ready[data-reveal-delay="2"] { - transition-delay: 100ms; -} - -.reveal.reveal-ready.is-visible { - opacity: 1; - transform: translateY(0); -} - -@media (max-width: 1040px) { - .hero { - grid-template-columns: 1fr 0.76fr; - gap: 44px; - } - - .hero h1 { - font-size: clamp(54px, 7.4vw, 76px); - } - - .hero-brand-surface { - min-height: 410px; - } - - .source-section { - grid-template-columns: 0.7fr 1fr; - gap: 54px; - } - - .source-proof { - padding: 32px; - } - - .control-section { - gap: 56px; - } - - .appearance { - gap: 54px; - } - - .appearance-study { - grid-template-columns: 68px 1fr; - } - - .study-note { - display: none; - } - - .study-page { - border-right: 0; - } +.mobile-story { + display: none; } -@media (max-width: 820px) { - .site-header { - grid-template-columns: 1fr auto; - } - - .site-nav { - display: none; - } - - .brand-name, - .theme-toggle span:last-child { - display: none; - } - - .hero { - grid-template-columns: 1fr; - padding-top: 62px; - } - - .hero-copy { - padding: 0; - } - - .hero-brand-surface { - min-height: 360px; - } - - .hero-mark { - top: -12px; - right: -76px; - width: 470px; - } - - .workspace-figure { - margin-top: 0; - } - - .section-intro, - .source-section, - .relations-heading, - .control-section, - .appearance { - grid-template-columns: 1fr; - } - - .section-intro { - gap: 18px; - } - - .workflow-line { - grid-template-columns: 1fr; - } - - .workflow-line li, - .workflow-line li:first-child { - min-height: 0; - padding: 28px 0 34px; - border-bottom: 1px solid var(--hairline); - border-left: 0; - } - - .workflow-line h3 { - margin-top: 54px; - } - - .source-section { - gap: 58px; - } - - .relations-heading { - gap: 26px; - } - - .product-facts { - grid-template-columns: 1fr; - } - - .product-facts div, - .product-facts div:first-child { - padding: 24px 0; - border-bottom: 1px solid var(--hairline); - border-left: 0; - } - - .appearance { - gap: 56px; - } - - .download-panel { - grid-template-columns: 160px 1fr; - padding: 48px 36px; - } - - .download-options { - grid-template-columns: 1fr; - } - - .download-options a:nth-child(even) { - padding-left: 0; - border-left: 0; - } - - .download-panel > img { - width: 150px; - } - - footer { - grid-template-columns: 1fr auto; +@media (max-width: 760px) { + html { + scroll-snap-type: y mandatory; } - footer p { + .scroll-run { display: none; } -} - -@media (max-width: 560px) { - .site-header { - min-height: 62px; - padding: 0 16px; - } - - .brand-mark { - width: 29px; - height: 29px; - } - - .brand-word { - font-size: 14px; - } - - .theme-toggle { - padding: 0 5px; - } - - .header-download { - min-height: 34px; - padding: 0 11px; - } - - .section, - .hero { - padding-right: 18px; - padding-left: 18px; - } - - .hero { - gap: 38px; - padding-top: 52px; - padding-bottom: 96px; - } - - .hero h1 { - margin-top: 20px; - font-size: clamp(44px, 12vw, 50px); - line-height: 1.1; - } - - .hero-claim { - margin-top: 24px; - font-size: 22px; - } - - .hero-meta { - grid-template-columns: repeat(3, 1fr); - } - .hero-meta div { - padding: 0 13px; + .mobile-story { + display: block; + background: + url("./assets/paper-texture.jpg") center / 720px repeat, + var(--paper); } - .hero-meta dd { - font-size: 10px; + .mobile-card { + position: relative; + height: 100svh; + min-height: 620px; + overflow: hidden; + border-bottom: 1px solid var(--rule); + scroll-snap-align: start; + background: rgba(242, 226, 202, 0.84); } - .hero-brand-surface { - min-height: 320px; - } - - .hero-mark { - top: 10px; - right: -74px; - width: 390px; + .mobile-card > img:not(.mobile-mark) { + position: absolute; + top: 16%; + left: 50%; + width: 170%; + max-width: none; + border: 1px solid var(--rule); + box-shadow: 0 24px 58px rgba(61, 43, 20, 0.17); + transform: translateX(-50%); } - .hero-brand-surface p { + .mobile-card > div { + position: absolute; + z-index: 3; + right: 18px; bottom: 24px; - left: 24px; - font-size: 11px; + left: 18px; + padding: 20px 18px 22px; + border-top: 1px solid var(--cinnabar); + background: rgba(248, 238, 219, 0.94); + backdrop-filter: blur(12px); } - .brand-ruling-a, - .brand-ruling-b { - left: 24px; + .mobile-card small, + .mobile-hero p { + color: var(--cinnabar); + font-family: var(--mono); + font-size: 11px; + letter-spacing: 0.13em; } - .window-bar { - height: 34px; + .mobile-card h2 { + margin-top: 10px; + font-family: var(--serif); + font-size: clamp(34px, 10vw, 46px); + font-weight: 600; + line-height: 1.08; } - .window-bar b { - display: none; + .mobile-hero { + display: grid; + align-content: center; + padding: 22px; } - .workspace-viewport img { - width: 165%; + .mobile-hero .mobile-mark { + position: absolute; + right: -30vw; + bottom: -4vh; + width: 112vw; max-width: none; - transform: translateX(-20%); - } - - .workspace-figure figcaption, - .relations-figure figcaption { - align-items: flex-start; - min-height: 0; - padding: 12px; - } - - .workflow, - .relations { - padding-top: 96px; - padding-bottom: 100px; - } - - .source-section, - .control-section { - padding-top: 92px; - padding-bottom: 98px; - } - - .section-intro h2, - .source-copy h2, - .relations-heading h2, - .appearance h2, - .download-copy h2 { - font-size: 40px; - } - - .source-proof { - min-height: 0; - padding: 26px 22px 38px; - box-shadow: 8px 10px 0 color-mix(in srgb, var(--paper-inset) 75%, transparent); - } - - .proof-answer { - margin: 28px 0 34px; - font-size: 22px; - } - - .proof-citations a { - grid-template-columns: 28px 1fr; - padding: 10px 0; - } - - .proof-citations em { - grid-column: 2; - } - - .control-section { - gap: 42px; + opacity: 0.78; + mix-blend-mode: multiply; } - .note-proposal { - padding: 24px 20px; + .mobile-hero p, + .mobile-hero h2 { + position: relative; + z-index: 2; } - .appearance { - padding: 92px 18px; + .mobile-hero h2 { + margin: 14px 0 0; + font-size: clamp(48px, 12.2vw, 62px); + letter-spacing: -0.06em; + line-height: 0.98; + white-space: nowrap; } - .appearance-study { - grid-template-columns: 50px 1fr; - min-height: 310px; - } - - .study-rail { - padding: 26px 14px; - } - - .study-page { - padding: 28px 22px; - } - - .download-section { - padding: 72px 18px 76px; - } - - .download-panel { - grid-template-columns: 1fr; - gap: 28px; - min-height: 0; - padding: 32px 24px 48px; - } - - .download-panel > img { - width: 112px; - } - - .download-word { - font-size: 94px; - } - - footer { - min-height: 86px; - padding: 18px; - } - - footer nav { - gap: 16px; + .mobile-crop-agent > img:not(.mobile-mark) { + left: 21%; + width: 260%; } } @media (prefers-reduced-motion: reduce) { - html { - scroll-behavior: auto; - } - *, *::before, *::after { - scroll-behavior: auto !important; - transition-duration: 0.01ms !important; animation-duration: 0.01ms !important; animation-iteration-count: 1 !important; - } - - .reveal { - opacity: 1; - transform: none; + transition-duration: 0.01ms !important; } }