From 09c3e5740ea7eec508338e2aab35105046a03e80 Mon Sep 17 00:00:00 2001 From: FORIFOR Date: Mon, 19 Oct 2026 02:56:13 +0900 Subject: [PATCH 1/3] =?UTF-8?q?feat:=20a=20quieter=20homepage=20=E2=80=94?= =?UTF-8?q?=20fewer=20words,=20the=20same=20facts?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Hero keeps the claim, one line about the lab and the two actions; the "(01—07) Products · Tokyo" meta and the SCROLL note are gone. - Products: one-line lead; the access table, FAQ and per-product record links now sit in one native disclosure "利用条件・よくある質問・検証記録" under the list (opens without script; deep links open it). - Shorter leads for services, principles and contact; the principles lead no longer says every project publishes its code (Noa does not). - FAQ and access intros trimmed to one line each. - The reel caption keeps its facts (recreated screens and staging, sound, six products) in a shorter form; the English one adds that the on-screen text is Japanese. - verify_home_v4 opens the disclosure before checking the access summary without script; ui-capture opens nested disclosures outermost first. Co-Authored-By: Claude Opus 5.5 --- scripts/ui-capture.mjs | 17 +++++++++-------- scripts/verify_home_v4.py | 5 +++++ src/home-flagship.mjs | 4 ++-- src/home-v4-copy.mjs | 16 ++++++++-------- src/redesign-copy.mjs | 8 ++++---- src/redesign.mjs | 8 ++++---- src/redesign/redesign.css | 5 ++++- 7 files changed, 36 insertions(+), 27 deletions(-) diff --git a/scripts/ui-capture.mjs b/scripts/ui-capture.mjs index a204183..6eef18c 100644 --- a/scripts/ui-capture.mjs +++ b/scripts/ui-capture.mjs @@ -48,21 +48,21 @@ export const SHOTS = Object.freeze([ { file: 'home-mobile-tall.png', route: '/', width: 390, height: 844, state: 'whole page after scrolling through, reduced motion, real time', reducedMotion: true, realtime: true, fullPage: true }, { file: 'home-band-reel.png', route: '/', width: 1440, height: 1000, scrollTo: '[data-rd-reel]', assertVisible: '[data-rd-reel] .rd-reel-cap', state: 'reel with its native player and staged-film caption, reduced motion, real time', reducedMotion: true, realtime: true }, { file: 'home-band-chapter-genie.png', route: '/', width: 1440, height: 1000, scrollTo: '#products', assertVisible: 'a.rd-row[href="/products/genie/"]', state: 'product list (redesign; replaces the v4 Genie card), real time', realtime: true }, - { file: 'home-band-chapter-oathra.png', route: '/', width: 1440, height: 1000, scrollTo: '.rd-records', assertVisible: '.rd-records a[href="/products/oathra/#film15-oathra-title"]', state: 'records and films row under the product list (redesign; replaces the v4 Oathra card), real time', realtime: true }, + { file: 'home-band-chapter-oathra.png', route: '/', width: 1440, height: 1000, openDetails: '.rd-kept--fold', scrollTo: '.rd-records', assertVisible: '.rd-records a[href="/products/oathra/#film15-oathra-title"]', state: 'records and films row under the product list (redesign; replaces the v4 Oathra card), real time', realtime: true }, { file: 'home-band-chapter-launchloom.png', route: '/', width: 1440, height: 1000, scrollTo: 'a.rd-row[href="/products/launchloom/"]', assertVisible: 'a.rd-row[href="/products/launchloom/"]', state: 'Launchloom row in the product list (redesign), real time', realtime: true }, { file: 'home-band-principles.png', route: '/', width: 1440, height: 1000, scrollTo: '#principles', state: 'principles, reduced motion, real time', reducedMotion: true, realtime: true }, { file: 'home-band-services.png', route: '/', width: 1440, height: 1000, scrollTo: '#services', state: 'services band, reduced motion, real time', reducedMotion: true, realtime: true }, - { file: 'home-band-access.png', route: '/', width: 1440, height: 1000, openDetails: '#access > details', scrollTo: '#access', assertVisible: '#access details[open] .rm-access-table', state: 'open access table, reduced motion, real time', reducedMotion: true, realtime: true }, - { file: 'home-band-close.png', route: '/', width: 1440, height: 1000, scrollTo: '#faq', state: 'FAQ and contact, reduced motion, real time', reducedMotion: true, realtime: true }, + { file: 'home-band-access.png', route: '/', width: 1440, height: 1000, openDetails: ['.rd-kept--fold', '#access > details'], scrollTo: '#access', assertVisible: '#access details[open] .rm-access-table', state: 'open access table, reduced motion, real time', reducedMotion: true, realtime: true }, + { file: 'home-band-close.png', route: '/', width: 1440, height: 1000, openDetails: '.rd-kept--fold', scrollTo: '#faq', state: 'FAQ and contact, reduced motion, real time', reducedMotion: true, realtime: true }, { file: 'home-m-reel.png', route: '/', width: 390, height: 844, scrollTo: '[data-rd-reel]', assertVisible: '[data-rd-reel] .rd-reel-cap', state: 'phone, reel with native player and caption, reduced motion, real time', reducedMotion: true, realtime: true }, { file: 'home-m-chapter.png', route: '/', width: 390, height: 844, scrollTo: '#products', assertVisible: 'a.rd-row[href="/products/ai-meeting/"]', state: 'phone, product list (redesign), real time', realtime: true }, // The two home clips cut from illustrative films (2026-09-30): their label and the caption under the video. - { file: 'home-m-chapter-oathra.png', route: '/', width: 390, height: 1100, scrollTo: '.rd-records', assertVisible: '.rd-records a[href="/work/#oathra"]', state: 'phone, records and films row (redesign), reduced motion, real time', reducedMotion: true, realtime: true }, + { file: 'home-m-chapter-oathra.png', route: '/', width: 390, height: 1100, openDetails: '.rd-kept--fold', scrollTo: '.rd-records', assertVisible: '.rd-records a[href="/work/#oathra"]', state: 'phone, records and films row (redesign), reduced motion, real time', reducedMotion: true, realtime: true }, { file: 'home-m-chapter-agent-team.png', route: '/', width: 390, height: 1100, scrollTo: 'a.rd-row[data-rd-film]', assertVisible: 'a.rd-row[data-rd-film]', state: 'phone, Agent Team row carrying the labelled design film (redesign), reduced motion, real time', reducedMotion: true, realtime: true }, { file: 'home-m-services.png', route: '/', width: 390, height: 844, scrollTo: '#services', state: 'phone, services band, reduced motion, real time', reducedMotion: true, realtime: true }, - { file: 'home-m-access.png', route: '/', width: 390, height: 844, openDetails: '#access > details', scrollTo: '#access', assertVisible: '#access details[open] .rm-access-table', state: 'phone, open access table, reduced motion, real time', reducedMotion: true, realtime: true }, - { file: 'home-en-m-access.png', route: '/en/', width: 390, height: 844, openDetails: '#access > details', scrollTo: '#access', assertVisible: '#access details[open] .rm-access-table', state: 'phone, English open access table, reduced motion, real time', reducedMotion: true, realtime: true }, - { file: 'home-narrow-access.png', route: '/', width: 320, height: 900, openDetails: '#access > details', scrollTo: '#access', assertVisible: '#access details[open] .rm-access-table', state: 'narrow phone, open access table, reduced motion, real time', reducedMotion: true, realtime: true }, + { file: 'home-m-access.png', route: '/', width: 390, height: 844, openDetails: ['.rd-kept--fold', '#access > details'], scrollTo: '#access', assertVisible: '#access details[open] .rm-access-table', state: 'phone, open access table, reduced motion, real time', reducedMotion: true, realtime: true }, + { file: 'home-en-m-access.png', route: '/en/', width: 390, height: 844, openDetails: ['.rd-kept--fold', '#access > details'], scrollTo: '#access', assertVisible: '#access details[open] .rm-access-table', state: 'phone, English open access table, reduced motion, real time', reducedMotion: true, realtime: true }, + { file: 'home-narrow-access.png', route: '/', width: 320, height: 900, openDetails: ['.rd-kept--fold', '#access > details'], scrollTo: '#access', assertVisible: '#access details[open] .rm-access-table', state: 'narrow phone, open access table, reduced motion, real time', reducedMotion: true, realtime: true }, { file: 'noa-hero-ja-desktop.png', route: '/products/noa/', width: 1440, height: 1200, scrollTo: '.rd-phero', assertVisible: '.rd-phero', state: 'Noa ja public viewing hero, desktop, reduced motion, real time', reducedMotion: true, realtime: true }, { file: 'noa-hero-ja-mobile.png', route: '/products/noa/', width: 390, height: 1400, scrollTo: '.rd-phero', assertVisible: '.rd-phero', state: 'Noa ja public viewing hero, mobile, reduced motion, real time', reducedMotion: true, realtime: true }, { file: 'noa-viewing-ja-desktop.png', route: '/products/noa/', width: 1440, height: 1200, scrollTo: '#noa-viewing', assertVisible: '#noa-viewing', state: 'Noa ja public viewing viewing, desktop, reduced motion, real time', reducedMotion: true, realtime: true }, @@ -317,7 +317,8 @@ async function captureRealtime(binary, shots, results = []) { for (let i = 0; i < 150 && !loaded; i++) await sleep(100); if (!loaded) throw new Error(`Real-time capture: ${shot.file} did not finish loading`); await sleep(1200); - if (shot.openDetails) await openDetails(shot.openDetails); + // A disclosure nested in a folded one is opened after its parent: pass the selectors outermost first. + for (const selector of [].concat(shot.openDetails || [])) await openDetails(selector); if (shot.fullPage) { await evaluate(`(async () => { const h = document.documentElement.scrollHeight; for (let y = 0; y < h; y += innerHeight / 2) { scrollTo({ top: y, behavior: 'instant' }); await new Promise(r => setTimeout(r, 120)); } scrollTo({ top: 0, behavior: 'instant' }); })()`); await sleep(800); diff --git a/scripts/verify_home_v4.py b/scripts/verify_home_v4.py index ce5a427..c4516d1 100644 --- a/scripts/verify_home_v4.py +++ b/scripts/verify_home_v4.py @@ -296,7 +296,12 @@ def assert_home_v4(page, *, interactive=True): expect(page.locator('[data-rd-clock]')).to_be_hidden() expect(page.locator('#main-nav')).to_be_visible() expect(reel).to_be_visible() + # Access, FAQ and records sit in one native disclosure (2026-10-19): it opens without script. + fold = page.locator('details.rd-kept--fold > summary') + expect(fold).to_be_visible() + fold.click() expect(page.locator('#access details summary')).to_be_visible() + expect(page.locator('#faq')).to_be_visible() return {'products': checked, 'javascript': False, 'native_reel': True, 'network': _home_requests(page), 'geometry': no_overflow(page)} diff --git a/src/home-flagship.mjs b/src/home-flagship.mjs index e923569..99d614b 100644 --- a/src/home-flagship.mjs +++ b/src/home-flagship.mjs @@ -87,7 +87,7 @@ export function renderAccess(products, lang) { const c = p[lang]; return `${esc(p.index)}${esc(p.name)}${esc(c.outcome)}${esc(c.status)}${esc(c.license)}${t('詳しく見る', 'Open')} ${arrow}`; }).join(''); - return `

ACCESS AT A GLANCE

${t('「試せるのか」に、
先に答える。', 'Can you actually
try it? Yes — here.')}

${t('7つとも自主開発です。今の状態、成果物、ライセンス、入口を、ひとつの表に。
言えないことは、ここにも書きません。', 'All seven are built here. Stage, result, license and entry point in one table.
What has not been verified is not claimed here either.')}

${heads.map(h => ``).join('')}${rows}
${t('プロダクトごとの状態・ライセンス・入口の一覧', 'Stage, license and entry point for each product')}
${esc(h)}

${t('各製品の動作条件・未検証の範囲は、製品ページと検証資料に記載しています。実運用の性能や安全性を保証するものではありません。', 'Setup requirements and unverified scope are stated on each product page and in its evidence. This is not a guarantee of production performance or safety.')}

`; + return `

ACCESS AT A GLANCE

${t('「試せるのか」に、
先に答える。', 'Can you actually
try it? Yes — here.')}

${t('状態・成果物・ライセンス・入口を、ひとつの表に。', 'Stage, result, license and entry point in one table.')}

${heads.map(h => ``).join('')}${rows}
${t('プロダクトごとの状態・ライセンス・入口の一覧', 'Stage, license and entry point for each product')}
${esc(h)}

${t('各製品の動作条件・未検証の範囲は、製品ページと検証資料に記載しています。実運用の性能や安全性を保証するものではありません。', 'Setup requirements and unverified scope are stated on each product page and in its evidence. This is not a guarantee of production performance or safety.')}

`; } const QUESTIONS = { @@ -114,7 +114,7 @@ export function renderFaq(lang) { check(lang); const ja = lang === 'ja', t = (a, b) => (ja ? a : b); const items = QUESTIONS[lang].map(([q, a], i) => `
${String(i + 1).padStart(2, '0')}${esc(q)}

${esc(a)}

`).join(''); - return `

BEFORE YOU ASK

${t('よくある質問に、
そのまま答えます。', 'The questions,
answered plainly.')}

${t('答えにくいものほど、先に書いておきます。
もっと具体的な話は、相談から。', 'The awkward ones first.
Anything more specific: start a conversation.')}

${t('開発を相談する', 'Start a conversation')} ${arrow}
${items}
`; + return `

BEFORE YOU ASK

${t('よくある質問に、
そのまま答えます。', 'The questions,
answered plainly.')}

${t('もっと具体的な話は、相談から。', 'Anything more specific: start a conversation.')}

${t('開発を相談する', 'Start a conversation')} ${arrow}
${items}
`; } /** A footer that can actually navigate the site, not two rows of leftovers. */ diff --git a/src/home-v4-copy.mjs b/src/home-v4-copy.mjs index 2d50dd9..9cf2214 100644 --- a/src/home-v4-copy.mjs +++ b/src/home-v4-copy.mjs @@ -28,22 +28,22 @@ export const homeV4Copy = { nextUi: '次のTaskDockの設計プレビューを見る', nextUiNote: '設計プレビューは未リリースで、実アプリの録画ではありません。', accessOriginalLink: '詳しく見る', access: '利用条件を一覧で比べる', accessHint: '状態・ライセンス・入口', servicesKicker: '企業向け開発支援', servicesTitle: '変えたい仕事から、
はじめましょう。', - servicesLead: '設計・試作・評価から、必要な連携の実装まで。最初に何を確かめるかを決め、一緒に進めます。', servicesLink: '支援内容と進め方を見る', + servicesLead: '最初に確かめることを決め、設計から実装まで一緒に進めます。', servicesLink: '支援内容と進め方を見る', services: [ ['業務AI・エージェント実装','調査、下書き、レビュー、承認。人とAIの分担を設計し、結果を追える業務フローを試作します。','関連 — Genie · Agent Team'], ['音声・電話AIの開発','対話型の練習、音声入力、電話業務。自然さだけでなく、誤認識・同意・人への引き継ぎまで設計します。','関連 — AI Meeting · Oathra'], ['新しいAIプロダクトの試作','まだ言葉だけのアイデアを、操作できる試作へ。使い勝手と成立条件を確かめ、次に作る範囲を整理します。','関連 — 複数プロダクトの自主開発経験'] ], - productsKicker: '自主開発プロダクト', productsTitle: 'あなたの仕事に、
つながるものを。', productsLead: 'できることから選んで、実物を確かめる。
試せる範囲と、必要な準備も一緒に。', + productsKicker: '自主開発プロダクト', productsTitle: 'あなたの仕事に、
つながるものを。', productsLead: '選んで、すぐ確かめる。', sourceNote: () => '各製品は独立しており、自動連携しません。', principlesKicker: 'REACHMADEのつくり方', principlesTitle: 'つくるだけでなく、
確かめるところまで。', - principlesLead: '自主開発で得た知見を、次の開発へ。
コード、実物、検証記録を公開しています。', about: 'ラボ・開発者について', work: '開発・検証記録を見る', + principlesLead: '自主開発で得た知見を、次の開発へ。', about: 'ラボ・開発者について', work: '開発・検証記録を見る', principles: [ ['実物で話す。','自主開発のプロダクト、コード、実行記録。言葉だけでなく、確認できるものを見せます。'], ['結果を確かめる。','AIの「できました」を、成功の証拠にしない。実行と確認を分け、未完了も残します。'], ['使う人に決定権を。','外部への送信、費用、権限、人の承認。使う人が判断できるよう、設計に組み込みます。'] ], - contactTitle: 'その「できたら」を、
一緒につくりませんか', contactLead: '構想が固まる前の段階から。
対象の業務と、試してみたいことを聞かせてください。' + contactTitle: 'その「できたら」を、
一緒につくりませんか', contactLead: '構想が固まる前から。
試したいことを聞かせてください。' }, en: { eyebrow: 'Independent AI products and development for companies', @@ -73,22 +73,22 @@ export const homeV4Copy = { nextUi: 'See the next TaskDock design preview', nextUiNote: 'This design is not released. It is not a recording of the real app.', accessOriginalLink: 'Open', access: 'Compare access and requirements', accessHint: 'Stage · license · entry point', servicesKicker: 'DEVELOPMENT FOR COMPANIES', servicesTitle: 'Start with the work
you want to change.', - servicesLead: 'From design, prototypes and evaluation to the integrations you need. We decide what to test first, then build it together.', servicesLink: 'See the support and process', + servicesLead: 'We decide what to test first, then design and build it with you.', servicesLink: 'See the support and process', services: [ ['AI workflows and agents','Research, drafts, review and approval. We design how people and AI share the work, then prototype a workflow with results you can trace.','Related — Genie · Agent Team'], ['Voice and phone AI','Conversation practice, voice input and phone workflows. We plan for misheard words, consent and human handover, as well as natural conversation.','Related — AI Meeting · Oathra'], ['New AI product prototypes','Turn a spoken idea into something you can operate. Test how it works and what it requires, then decide what to build next.','Related — experience building independent products'] ], - productsKicker: 'INDEPENDENT PRODUCTS', productsTitle: 'Find a tool
for your work.', productsLead: 'Choose by what it does, then inspect the real work.
See what you can try and what you need to prepare.', + productsKicker: 'INDEPENDENT PRODUCTS', productsTitle: 'Find a tool
for your work.', productsLead: 'Pick one. See it work.', sourceNote: () => 'Each product is independent; they do not connect automatically.', principlesKicker: 'HOW REACHMADE BUILDS', principlesTitle: 'Build it.
Then check it.', - principlesLead: 'What we learn from our own products informs the next project.
We share code, working examples and verification records.', about: 'About the lab and developer', work: 'Read the development records', + principlesLead: 'What we learn from our own products goes into the next one.', about: 'About the lab and developer', work: 'Read the development records', principles: [ ['Show the work.','Independent products, code and run records. We show things you can inspect alongside the description.'], ['Check the result.','The AI saying “done” is not evidence of success. We separate execution from verification and retain unfinished results.'], ['Keep people in control.','External data transfers, costs, permissions and approval are part of the design, so the person using it can decide.'] ], - contactTitle: 'Let’s make your
next idea useful', contactLead: 'You can start before the brief is settled.
Tell us about the work and what you would like to try.' + contactTitle: 'Let’s make your
next idea useful', contactLead: 'Start before the brief is settled.
Tell us what you would like to try.' } }; diff --git a/src/redesign-copy.mjs b/src/redesign-copy.mjs index 4a84e01..2742388 100644 --- a/src/redesign-copy.mjs +++ b/src/redesign-copy.mjs @@ -12,13 +12,13 @@ export const redesignCopy = { scroll: ['SCROLL', '構想が固まる前から。'], reelKicker: '(02) 実際につくったもの', // reachmade-15s.mp4: motion graphics rendered from film.html, with a soundtrack (films/manifest.json). Made when there were six products. - reelCaption: '15秒の紹介映像(画面は再現・演出を含む)· 音声あり · 制作時点の6製品を紹介', + reelCaption: '紹介映像(画面は再現・演出を含む)· 15秒 · 音声あり · 6製品', reelLabel: 'Reachmadeの15秒紹介映像', productsKicker: '(03) 自主開発プロダクト', servicesKicker: '(04) 企業向け開発支援', principlesKicker: '(05) Reachmadeのつくり方', contactKicker: '(06) 相談する', - keptKicker: '(+) 利用条件とよくある質問', + keptKicker: '(+) 利用条件とよくある質問', keptSummary: '利用条件・よくある質問・検証記録', records: '検証記録と映像', recordLink: '検証記録', footCols: [['SITE', [['/products/', 'プロダクト'], ['/services/', '企業向け支援'], ['/work/', '開発記録'], ['/about/', 'ラボについて']]], ['CODE', [['https://github.com/FORIFOR', 'GitHub ↗'], ['/privacy/', 'プライバシー']]]], lang: ['LANG', '日本語', 'English'], @@ -56,13 +56,13 @@ export const redesignCopy = { meta: ['Reachmade / Independent AI Studio', n => `(01—${String(n).padStart(2, '0')}) Products · Tokyo`], scroll: ['SCROLL', 'Before the brief is settled.'], reelKicker: '(02) Things we have built', - reelCaption: '15-second introduction film (recreated screens and staging) · with sound · shows the six products at the time it was made', + reelCaption: 'Introduction film (recreated screens and staging) · 15 s · with sound · six products · Japanese on-screen text', reelLabel: 'Reachmade 15-second introduction film', productsKicker: '(03) Independent products', servicesKicker: '(04) Development for companies', principlesKicker: '(05) How Reachmade builds', contactKicker: '(06) Contact', - keptKicker: '(+) Access and questions', + keptKicker: '(+) Access and questions', keptSummary: 'Access, questions and records', records: 'Records and films', recordLink: 'Work notes', footCols: [['SITE', [['/en/products/', 'Products'], ['/en/services/', 'For companies'], ['/en/work/', 'Work notes'], ['/en/about/', 'About']]], ['CODE', [['https://github.com/FORIFOR', 'GitHub ↗'], ['/en/privacy/', 'Privacy']]]], lang: ['LANG', '日本語', 'English'], diff --git a/src/redesign.mjs b/src/redesign.mjs index 798bdd3..77265a4 100644 --- a/src/redesign.mjs +++ b/src/redesign.mjs @@ -184,14 +184,14 @@ function homeMain(products, lang, kept) { const services = c.services.map(([title, body, related], i) => `
0${i + 1}${esc(related)}

${esc(title)}

${esc(body)}

`).join(''); const principles = c.principles.map(([title, body], i) => `
/0${i + 1}

${esc(title)}

${esc(body)}

`).join(''); return `
-
${esc(r.meta[0])}${esc(r.meta[1](n))}${esc(c.eyebrow)}
+
${esc(r.meta[0])}${esc(c.eyebrow)}

${esc(c.title[0])}${esc(c.title[1])}${esc(c.dot)}

-

${c.lead}

${esc(r.scroll[0])}
${esc(r.scroll[1])}

+
${video({...REEL, label: `${r.reelLabel} — ${r.reelCaption}`}, lang)}
${esc(r.reelKicker)}${esc(r.reelCaption)}
-

${esc(r.productsKicker)}

${c.productsTitle}

${c.productsLead}

    ${rows}
${records}

${esc(c.sourceNote(sourcesCheckedAt))}

-

${esc(r.keptKicker)}

${kept.join('')}
+

${esc(r.productsKicker)}

${c.productsTitle}

${c.productsLead}

    ${rows}

${esc(c.sourceNote(sourcesCheckedAt))}

+
${esc(r.keptSummary)}${records}${kept.join('')}

${esc(r.servicesKicker)}

${svcFirst}
${svcSecond}

${esc(c.servicesLead)}

${services}

${esc(r.principlesKicker)}

${c.principlesTitle}

${c.principlesLead}

${principles}

${esc(r.contactKicker)}

${c.contactTitle}

${c.contactLead}

`; diff --git a/src/redesign/redesign.css b/src/redesign/redesign.css index fec730d..063a6e3 100644 --- a/src/redesign/redesign.css +++ b/src/redesign/redesign.css @@ -214,13 +214,16 @@ body[data-rd] #main .rd-kept .owned-primary,body[data-rd] #main .rd-kept .owned- body[data-rd] .rd-kept-kicker{padding:0 var(--rd-gutter);margin-bottom:clamp(24px,3vw,40px)} /* Product pages: the long-form sections start folded behind one summary row. */ body[data-rd] .rd-kept--fold{padding-top:0;padding-bottom:0;border-top:0} -body[data-rd] .rd-kept--fold>summary{list-style:none;cursor:pointer;display:flex;align-items:center;justify-content:space-between;min-height:72px;margin:0;border-bottom:1px solid var(--rd-rule);color:var(--rd-ink)} +body[data-rd] .rd-kept--fold>summary{list-style:none;cursor:pointer;display:flex;align-items:center;justify-content:flex-start;gap:14px;min-height:72px;margin:0;border-bottom:1px solid var(--rd-rule);color:var(--rd-ink);font-family:var(--rd-jp);font-size:clamp(15px,1.2vw,18px);font-weight:600;letter-spacing:.02em;text-transform:none} body[data-rd] .rd-kept--fold>summary::-webkit-details-marker{display:none} body[data-rd] .rd-kept--fold>summary::after{content:"+";font-size:22px;line-height:1;transition:transform .3s cubic-bezier(.16,1,.3,1)} body[data-rd] .rd-kept--fold[open]>summary{margin-bottom:clamp(24px,3vw,40px)} body[data-rd] .rd-kept--fold[open]>summary::after{transform:rotate(45deg)} body[data-rd] .rd-kept--fold>summary:hover{color:var(--rd-signal)} body[data-rd] .rd-kept--fold[open]{padding-bottom:clamp(64px,8vw,120px)} +/* Inside the home fold the record links stack under their label, on the same left edge as the sections below. */ +body[data-rd] .rd-kept--fold>.rd-records{display:block;margin:0 var(--rd-gutter) clamp(40px,5vw,72px)} +body[data-rd] .rd-kept--fold>.rd-records .rd-kicker{margin-bottom:12px} @media (prefers-reduced-motion:reduce){body[data-rd] .rd-kept--fold>summary::after{transition:none}} body[data-rd] .rd-kept h2,body[data-rd] .rd-kept h3{font-family:var(--rd-jp);font-weight:700;letter-spacing:-.04em;color:var(--rd-ink)} body[data-rd] .rd-kept h2{font-size:clamp(28px,3.6vw,56px);line-height:1.15} From 0a6612da3d7f6678de068824e90e0ebb5178d645 Mon Sep 17 00:00:00 2001 From: FORIFOR Date: Mon, 19 Oct 2026 20:30:33 +0900 Subject: [PATCH 2/3] feat: lead the homepage with the products, and let the fold sit in the list The first view's filled button now takes visitors to the products, with consultation as the outlined second action, as the design brief orders them. The access/FAQ/records fold reads as the last row of the product list instead of a grey band against the services section, and its access table now sits on the page gutter instead of being indented twice. Co-Authored-By: Claude Opus 5.5 --- src/redesign.mjs | 2 +- src/redesign/redesign.css | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/redesign.mjs b/src/redesign.mjs index 77265a4..595682a 100644 --- a/src/redesign.mjs +++ b/src/redesign.mjs @@ -186,7 +186,7 @@ function homeMain(products, lang, kept) { return `
${esc(r.meta[0])}${esc(c.eyebrow)}

${esc(c.title[0])}${esc(c.title[1])}${esc(c.dot)}

- +
${video({...REEL, label: `${r.reelLabel} — ${r.reelCaption}`}, lang)}
${esc(r.reelKicker)}${esc(r.reelCaption)}
diff --git a/src/redesign/redesign.css b/src/redesign/redesign.css index 063a6e3..3924a31 100644 --- a/src/redesign/redesign.css +++ b/src/redesign/redesign.css @@ -225,6 +225,13 @@ body[data-rd] .rd-kept--fold[open]{padding-bottom:clamp(64px,8vw,120px)} body[data-rd] .rd-kept--fold>.rd-records{display:block;margin:0 var(--rd-gutter) clamp(40px,5vw,72px)} body[data-rd] .rd-kept--fold>.rd-records .rd-kicker{margin-bottom:12px} @media (prefers-reduced-motion:reduce){body[data-rd] .rd-kept--fold>summary::after{transition:none}} +/* On the home page the fold reads as the last row of the product list, not as a band of its own. */ +body[data-rd] .rd-products:has(+ .rd-kept--home){padding-bottom:clamp(40px,5vw,72px)} +body[data-rd] .rd-kept--home{background:transparent;padding-bottom:clamp(72px,9vw,128px)} +body[data-rd] .rd-kept--home>summary{margin:0 var(--rd-gutter);padding:0;border-top:1px solid var(--rd-ink);border-bottom:1px solid var(--rd-rule)} +body[data-rd] .rd-kept--home[open]>summary{margin-bottom:clamp(24px,3vw,40px)} +body[data-rd] .rd-kept--home>.v4-wrap{width:auto;max-width:none;margin-left:var(--rd-gutter);margin-right:var(--rd-gutter);padding-left:0;padding-right:0} +body[data-rd] .rd-kept--home>.v4-wrap .container{margin-left:0;margin-right:0} body[data-rd] .rd-kept h2,body[data-rd] .rd-kept h3{font-family:var(--rd-jp);font-weight:700;letter-spacing:-.04em;color:var(--rd-ink)} body[data-rd] .rd-kept h2{font-size:clamp(28px,3.6vw,56px);line-height:1.15} body[data-rd] .rd-kept p,body[data-rd] .rd-kept li,body[data-rd] .rd-kept dd,body[data-rd] .rd-kept td{font-family:var(--rd-jp);line-height:1.85} From aa838b2ca0b0e9985d439cd7b50f46e3b64e9511 Mon Sep 17 00:00:00 2001 From: FORIFOR Date: Mon, 19 Oct 2026 20:36:58 +0900 Subject: [PATCH 3/3] test: the conversion path opens the home fold before following a record The records moved into the home fold, so the journey now opens it the way a visitor would; the path and its assertions are otherwise unchanged. Co-Authored-By: Claude Opus 5.5 --- scripts/verify-conversion-path.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/scripts/verify-conversion-path.py b/scripts/verify-conversion-path.py index 7579b17..21045fe 100644 --- a/scripts/verify-conversion-path.py +++ b/scripts/verify-conversion-path.py @@ -47,9 +47,11 @@ def handle(route): page=context.new_page();page.on('pageerror',lambda error:errors.append(str(error))) page.set_default_timeout(7000) try: - # Actual home -> record -> scoped offer -> contextual inquiry. + # Actual home -> record -> scoped offer -> contextual inquiry. The records sit in the home fold, + # so the visitor opens it first, as they would. page.goto(BASE+prefix+'/',wait_until='networkidle') - page.locator(f'a[href="{prefix}/work/#noa"]').click() + page.locator('details.rd-kept--home > summary').click() + page.locator(f'.rd-records a[href="{prefix}/work/#noa"]').click() expect(page.locator('#noa .work-consult')).to_be_visible() page.screenshot(path=str(OUT/f'work-{language}-{width}.png'),full_page=False) page.locator(f'#noa a[href="{prefix}/services/#ai-character"]').click()