diff --git a/design-qa.md b/design-qa.md new file mode 100644 index 0000000..b23b278 --- /dev/null +++ b/design-qa.md @@ -0,0 +1,236 @@ +# Design QA — 贵州体验三主题合并 + +## Comparison target + +- source visual truth path: `/var/folders/zy/v2mtllmj38j5wnn5vqmsnwfr0000gn/T/codex-clipboard-88de526f-12fb-4cce-9b9e-477b59045f0c.png` +- implementation route: `http://127.0.0.1:5175/` +- implementation screenshot path: `/tmp/wanqu-home-three-experiences-reference-state.png` +- focused side-by-side comparison: `/tmp/wanqu-three-experience-comparison.png` +- supporting screenshots: + - `/tmp/wanqu-home-desktop-top.png` + - `/tmp/wanqu-experiences-page-desktop-final.png` + - `/tmp/wanqu-home-mobile-top.png` + - `/tmp/wanqu-home-mobile-cards.png` +- viewport: desktop `1512 × 900` CSS px; mobile `390 × 844` CSS px +- source pixels: `1512 × 900` +- implementation comparison pixels: `1512 × 900` +- density normalization: both comparison images were inspected at equal pixel dimensions and scaled equally in the side-by-side composite; no device frame was included +- state: default English locale, three-theme homepage section; desktop and mobile default states; mobile full-menu open state also tested + +## Findings + +No actionable P0, P1, or P2 issues remain. + +- Fonts and typography: the implementation keeps WanderQ's established Assistant/Georgia hierarchy instead of copying the reference's generic Chinese sans face. Category hierarchy, optical weight, wrapping, and small-label tracking remain clear at desktop and mobile sizes. +- Spacing and layout rhythm: the reference's centered heading and equal three-column card rhythm are retained. Desktop cards use the same near-full-width composition and equal heights; mobile collapses to one card per row without horizontal overflow. +- Colors and visual tokens: the dark forest, medium green, and light moss card sequence follows the source while using the site's existing cream background and acid-green brand accent. Text contrast is readable across all three tones. +- Image quality and asset fidelity: all three cards use existing high-resolution project photography with matched subjects—cave, living craft, and waterfall landscape. Crops remain sharp and intentional; no placeholder or synthetic icon treatment is present. +- Copy and content: the three categories are explicit and non-overlapping. English copy is longer than the Chinese source, but the hierarchy and card proportions remain stable. +- Interaction and accessibility: card hover/focus treatment, anchor navigation, mobile menu, legacy route fallback, and bilingual navigation were tested. No broken images, horizontal overflow, browser errors, or warnings were observed. + +## Full-view comparison evidence + +The homepage desktop capture confirms the simplified five-section funnel: hero, three Guizhou experiences, WanderQ method, local team, and final inquiry CTA. The merged experience-page capture confirms exactly three top-level categories and no separate Routes catalogue in the public navigation. + +## Focused region comparison evidence + +`/tmp/wanqu-three-experience-comparison.png` places the supplied three-card source and the implementation in the same comparison image. The implementation matches the source's principal composition, category order, photography-led cards, three green tones, and direct action affordance. The retained WanderQ header and English copy are intentional product-context differences. + +## Comparison history + +1. Earlier finding — P1 mobile layout overflow: the V1 desktop-specific three-column rule overrode the mobile breakpoint and compressed all three cards into narrow columns. + - fix: added V1-specific `820px` and `640px` responsive rules, one-column stacking, mobile image ratio, and compact content spacing. + - post-fix evidence: `/tmp/wanqu-home-mobile-cards.png`; measured viewport and document width are both `390px`, and every card measures `350px`. +2. Earlier finding — P2 experience-navigation contrast: category headings inherited a dark global heading color over dark photography. + - fix: explicitly set the category heading and arrow to white. + - post-fix evidence: `/tmp/wanqu-experiences-page-desktop-final.png`. +3. Earlier finding — P2 desktop proportion drift: the shared container kept the cards too narrow and let intrinsic content expand their height. + - fix: expanded the section to the intended wide frame and fixed the desktop card grid to a `660px` source-aligned height. + - post-fix evidence: `/tmp/wanqu-home-three-experiences-reference-state.png` and the focused side-by-side comparison. + +## Primary interactions tested + +- header “Guizhou Experiences” navigation +- all three theme anchor links +- four culture cards and four landscape cards render in their merged sections +- old `/safaris/classic-guizhou/` URL resolves to the merged Guizhou Experiences page +- mobile full menu opens and contains Guizhou Experiences, Hotels, Food, and About Us without a Routes section +- all rendered images complete with non-zero natural width +- console errors and warnings checked: none + +## Follow-up polish + +- P3: if the client later wants the English version to track the Chinese reference even more tightly, shorten the three English card titles by one line each. + +## Implementation checklist + +- [x] Merge navigation and content architecture +- [x] Reduce homepage to five primary sections +- [x] Match the selected three-card direction +- [x] Verify desktop and mobile layouts +- [x] Test navigation, anchors, legacy links, menu, images, and console + +## Method-section refinement + +- source state: `/tmp/wanqu-method-before.png` +- implementation state: `/tmp/wanqu-method-after.png` +- same-state comparison: `/tmp/wanqu-method-comparison.png` +- desktop viewport: `1512 × 1000` CSS px +- mobile evidence: `/tmp/wanqu-method-mobile-copy.png` at `390 × 844` CSS px +- refinement: replaced the abstract “See less. Feel more.” line with a Guizhou-specific promise, clarified the three planning steps, increased step readability, and reduced excess section spacing while preserving the approved editorial layout and real project photography. +- responsive result: document and viewport widths both measure `390px`; no horizontal overflow or broken imagery. +- interaction result: “How we plan” now resolves to the verified `/our-story/` page instead of falling back to the homepage. +- console errors and warnings: none. +- findings after refinement: no actionable P0/P1/P2 issues; the longer English step labels wrap intentionally on mobile. + +final result: passed + +## 2026-08-22 Atlas homepage redesign + +### Comparison target + +- source visual truth path: `/Users/a1/.codex/generated_images/019febea-95df-7f22-bd6f-c6895dab41b8/exec-53fa5a7a-5ed3-4865-8a82-23030f01a87b.png` +- implementation route: `http://127.0.0.1:5175/` +- implementation screenshot paths: + - desktop hero: `/tmp/wanqu-atlas-qa-2026-08-22/final-top-1440-r3.png` + - desktop experiences: `/tmp/wanqu-atlas-qa-2026-08-22/final-experiences-1440.png` + - desktop planning: `/tmp/wanqu-atlas-qa-2026-08-22/final-plan-1440.png` + - desktop team/final contact: `/tmp/wanqu-atlas-qa-2026-08-22/final-contact-1440.png` + - mobile hero: `/tmp/wanqu-atlas-qa-2026-08-22/final-mobile-top-r5.png` +- full-view same-board comparison: `/tmp/wanqu-atlas-qa-2026-08-22/compare-overview.jpg` +- focused comparisons: + - hero: `/tmp/wanqu-atlas-qa-2026-08-22/compare-hero-final.jpg` + - experiences: `/tmp/wanqu-atlas-qa-2026-08-22/compare-experiences.jpg` + - planning: `/tmp/wanqu-atlas-qa-2026-08-22/compare-planning.jpg` + - team/final contact: `/tmp/wanqu-atlas-qa-2026-08-22/compare-team.jpg` +- viewport: desktop `1440 × 1000` CSS px; mobile `390 × 844` CSS px +- source pixels: `864 × 1821` +- implementation pixels: desktop viewport captures `1440 × 1000`; mobile capture `390 × 844`; assembled implementation overview `1440 × 3724` +- density normalization: device scale factor `1`. The generated source is a tall design board rather than a live browser viewport, so the full source and assembled implementation were proportionally contained in equal `780 × 1750` comparison slots. Focused source crops and implementation captures were normalized into equal `780 × 540` slots before judgment. +- state: homepage, default English locale, first hero slide selected and paused; desktop and mobile responsive states + +### Findings + +No actionable P0, P1, or P2 issues remain. + +- Fonts and typography: the implementation reproduces the condensed editorial hierarchy with a system-safe Arial/Aptos Narrow stack, while Chinese uses PingFang SC/Microsoft YaHei to avoid missing glyphs. Display weight, wrapping, labels, coordinates, body line-height, and mobile scaling remain legible. The implementation intentionally uses slightly larger real-browser body text than the generated overview board. +- Spacing and layout rhythm: the source's slim header, split hero, atlas rail, overlapping three-image narrative, framed itinerary map, dark local-team proof, and compact contact plate are all present. Desktop section spacing is controlled and compact; the document width equals the viewport at both tested breakpoints with no horizontal overflow. +- Colors and visual tokens: warm mineral paper, ink black, deep forest, clay annotation, and restrained acid-lime actions match the selected direction. The accent is reserved for CTAs, route markers, small labels, and service facts. +- Image quality and asset fidelity: the dedicated hero photograph, route-map plate, existing cave/craft/waterfall photographs, and real WanderQ team image match the source art direction and render sharply. No placeholder images, handcrafted SVGs, CSS drawings, or visible watermarks remain. +- Copy and content: the approved three Guizhou experience categories, private-journey proposition, planning method, local-team proof, and contact destination are preserved in bilingual form. English is the default and the Chinese switch renders complete text without clipped glyphs. +- Interaction and accessibility: menu open/close, language switching in both directions, hero slide selection and pause/resume, primary CTA destinations, focus return, and responsive navigation were tested. Menu/search controls now expose explicit accessible labels. Browser console errors checked after interaction testing: none. + +### Full-view comparison evidence + +`/tmp/wanqu-atlas-qa-2026-08-22/compare-overview.jpg` places the complete selected design and the assembled browser implementation on the same board. The implementation retains the same story order, split-image proportions, atlas typography, overlapping experience plates, illustrated journey map, dark team proof, and final inquiry colophon. The implementation is taller because it uses production-readable body sizes and real responsive spacing rather than the compressed type in the ImageGen presentation board; this is an intentional browser-quality constraint rather than design drift. + +### Focused region comparison evidence + +- Hero comparison confirms the selected image mood, split composition, navigation density, headline scale, coordinate metadata, vertical Guizhou stamp, acid CTA, and forest atlas rail. +- Experience comparison confirms the asymmetric overlap, numbered photographic plates, black caption fields, theme order, and visible action affordances without returning to an equal rounded-card grid. +- Planning comparison confirms the framed two-column composition and purpose-built paper route-map asset with cave, culture, landscape, and Guiyang nodes. +- Team/contact comparison confirms the dark image-and-proof split, restrained statistics, compact inquiry plate, and book-colophon footer. + +### Comparison history + +1. Earlier finding — P1 experience cards stacked into three implicit grid rows, creating a `2131px` experience section and large empty areas. + - fix: assigned all three desktop cards to the same grid row, then restored automatic rows at tablet/mobile breakpoints. + - post-fix evidence: `/tmp/wanqu-atlas-qa-2026-08-22/final-experiences-1440.png`; the section is `895px` high and all three plates are visible together. +2. Earlier finding — P2 third experience caption was partially hidden by excessive overlap. + - fix: narrowed the middle plate from grid columns `5 / 10` to `5 / 9`, preserving the layered composition while exposing the third title and action. + - post-fix evidence: `/tmp/wanqu-atlas-qa-2026-08-22/final-experiences-1440.png`. +3. Earlier finding — P2 existing wide waterfall photo felt like a conventional attraction image and did not match the selected quiet, narrow-gorge hero. + - fix: generated and optimized `/public/client-assets/atlas-hero-waterfall.webp` for the exact hero slot, then verified the desktop and mobile crops. + - post-fix evidence: `/tmp/wanqu-atlas-qa-2026-08-22/compare-hero-final.jpg` and `/tmp/wanqu-atlas-qa-2026-08-22/final-mobile-top-r5.png`. +4. Earlier finding — P2 the icon-only Atlas menu control lost its accessible name when its visible label was hidden. + - fix: added localized `aria-label` values to menu and search buttons and retested open/close focus state. + - post-fix evidence: menu dialog opens, close returns focus, and `aria-expanded` returns to `false`. + +### Primary interactions tested + +- full menu opens and closes; dialog count `1` while open and `aria-expanded="false"` after close +- English → Chinese → English switch; both hero headings render correctly +- hero slide 1/2 selection and pause/resume controls +- both primary Atlas CTAs resolve to `/contact/` +- desktop layout width `1440px` equals document width `1440px` +- mobile layout width `390px` equals document width `390px` +- mobile hero, experience stack, and sticky header render without horizontal overflow +- browser console error log: empty +- production build: passed + +### Follow-up polish + +- P3: after the client reviews the complete homepage, inner-page headers and editorial modules can inherit the Atlas tokens in a separate controlled pass without changing their business content. + +### Implementation checklist + +- [x] Rebuild the homepage around the selected Atlas visual direction +- [x] Generate and optimize the missing hero and itinerary-map assets +- [x] Preserve bilingual copy, carousel, navigation, and CTA behavior +- [x] Verify desktop and mobile layouts in the in-app browser +- [x] Compare source and implementation together at full-view and focused-region levels +- [x] Fix all P0/P1/P2 design issues +- [x] Check production build and browser console + +final result: passed + +## Final inquiry-section refinement + +- source visual truth: `/tmp/wanqu-final-cta-before.png` +- implementation screenshot: `/tmp/wanqu-final-cta-after.png` +- same-state comparison: `/tmp/wanqu-final-cta-comparison.png` +- desktop viewport and pixels: `1512 × 1000` CSS px and `1512 × 1000` image pixels +- mobile evidence: `/tmp/wanqu-final-cta-mobile-top.png` and `/tmp/wanqu-final-cta-mobile-bottom.png` at `390 × 844` CSS px +- Chinese mobile evidence: `/tmp/wanqu-final-cta-mobile-zh.png` at `390 × 844` CSS px +- density normalization: source and implementation desktop captures use the same CSS viewport and equal pixel dimensions; the side-by-side composite scales both equally to `756 × 500`. +- state: homepage final inquiry section, default English; Chinese locale and mobile continuation state also verified. + +### Findings + +No actionable P0, P1, or P2 issues remain. + +- Fonts and typography: the Georgia display face and Assistant supporting face preserve the established editorial hierarchy. The shorter two-line promise has stronger optical balance, and the acid-green emphasis remains readable in both languages. +- Spacing and layout rhythm: the dark two-column section creates a clear final destination in the page funnel. Desktop copy, CTA, reassurance note, and three prompts align to a shared baseline; mobile collapses to one column with an `18px` content inset and no horizontal overflow. +- Colors and visual tokens: forest, warm white, and acid green now reuse the approved WanderQ palette with stronger contrast than the previous acid-green full background. Prompt body copy remains secondary without dropping below useful visual hierarchy. +- Image quality and asset fidelity: this section intentionally uses no raster imagery; removing the previous decorative pseudo-element keeps the ending quieter and consistent with the minimal direction. +- Copy and content: the generic request was replaced with a clearer promise, a lower-friction CTA, a no-fixed-itinerary reassurance, and three concrete starting details. English and Chinese versions communicate the same scope. +- Interaction and accessibility: the primary CTA resolves to `/contact/`; the contact heading appears in the active language. Focusable control boundaries remain visible, all images on the page load, and the browser console contains no errors or warnings. + +### Comparison history + +1. Earlier finding — P2 contrast and conversion hierarchy: the acid-green full section made the supporting prompts too pale and visually competed with the CTA. + - fix: moved the section to the dark forest token, reserved acid green for the key phrase, prompt label, and primary action, and rewrote the supporting copy around three simple inputs. + - post-fix evidence: `/tmp/wanqu-final-cta-after.png` and `/tmp/wanqu-final-cta-comparison.png`. +2. Earlier finding — P1 animated CTA overlap: the generic stagger animation left the button translated `64px` downward, visually colliding with the reassurance note. + - fix: removed the primary CTA from the stagger target and neutralized inherited transforms for that button. + - post-fix evidence: button and note bounds no longer intersect; desktop comparison and both mobile captures show the corrected spacing. + +### Primary interactions tested + +- final CTA navigation to `/contact/` +- English and Chinese language states +- desktop and mobile layouts +- mobile CTA boundaries (`x=18px`, `right=372px`) and document width (`390px`) +- broken images and console errors/warnings: none + +### Follow-up polish + +- P3: after client review, the reassurance note can be shortened further if the Chinese line is preferred on one row at very narrow widths. + +final result: passed + +## Team-section refinement + +- previous state: `/tmp/wanqu-team-before.png` +- implementation state: `/tmp/wanqu-team-after.png` +- same-viewport side-by-side comparison: `/tmp/wanqu-team-comparison.png` +- desktop viewport: `1512 × 1000` CSS px +- mobile evidence: `/tmp/wanqu-team-mobile-top.png` and `/tmp/wanqu-team-mobile-services.png` at `390 × 844` CSS px +- refinement: promoted the real Guizhou field-day image to the primary visual, reduced the oversized editorial headline to a two-line local-support promise, and condensed the content into three concrete capabilities: route judgment, bilingual cultural context, and on-trip coordination. +- visual result: the section now uses the approved sage/forest palette, a balanced image-and-copy split, and a clearer trust hierarchy while preserving the established WanderQ typography and square-corner system. +- responsive result: viewport and document widths both measure `390px`; the full-width mobile CTA now resolves inside the content frame at `x=20px`, `right=370px`, with no horizontal overflow. +- interaction result: “Talk with our local team” resolves to the verified `/contact/` page. +- image and runtime result: no broken images and no browser console errors or warnings. +- findings after refinement: no actionable P0, P1, or P2 issues remain. The mobile CTA entrance transform was found extending past the content frame during verification and was neutralized at the mobile breakpoint. + +final result: passed diff --git a/docs/WanderQ官网客户验收与资料确认清单.docx b/docs/WanderQ官网客户验收与资料确认清单.docx new file mode 100644 index 0000000..78080ed Binary files /dev/null and b/docs/WanderQ官网客户验收与资料确认清单.docx differ diff --git a/docs/final-audit/01-home.png b/docs/final-audit/01-home.png new file mode 100644 index 0000000..dedc94c Binary files /dev/null and b/docs/final-audit/01-home.png differ diff --git a/docs/final-audit/02-routes.png b/docs/final-audit/02-routes.png new file mode 100644 index 0000000..453c108 Binary files /dev/null and b/docs/final-audit/02-routes.png differ diff --git a/docs/final-audit/03-experiences.png b/docs/final-audit/03-experiences.png new file mode 100644 index 0000000..d917cbc Binary files /dev/null and b/docs/final-audit/03-experiences.png differ diff --git a/docs/final-audit/04-transport.png b/docs/final-audit/04-transport.png new file mode 100644 index 0000000..4408729 Binary files /dev/null and b/docs/final-audit/04-transport.png differ diff --git a/docs/final-audit/05-hotels.png b/docs/final-audit/05-hotels.png new file mode 100644 index 0000000..7390f91 Binary files /dev/null and b/docs/final-audit/05-hotels.png differ diff --git a/docs/final-audit/06-contact.png b/docs/final-audit/06-contact.png new file mode 100644 index 0000000..566b112 Binary files /dev/null and b/docs/final-audit/06-contact.png differ diff --git a/docs/final-audit/07-route-detail.png b/docs/final-audit/07-route-detail.png new file mode 100644 index 0000000..d39784d Binary files /dev/null and b/docs/final-audit/07-route-detail.png differ diff --git a/docs/final-audit/08-experience-detail.png b/docs/final-audit/08-experience-detail.png new file mode 100644 index 0000000..2b14876 Binary files /dev/null and b/docs/final-audit/08-experience-detail.png differ diff --git a/docs/final-audit/09-contact-validation.png b/docs/final-audit/09-contact-validation.png new file mode 100644 index 0000000..a27ba37 Binary files /dev/null and b/docs/final-audit/09-contact-validation.png differ diff --git a/docs/final-audit/10-mobile-home.png b/docs/final-audit/10-mobile-home.png new file mode 100644 index 0000000..bc468fe Binary files /dev/null and b/docs/final-audit/10-mobile-home.png differ diff --git a/docs/final-audit/11-mobile-routes.png b/docs/final-audit/11-mobile-routes.png new file mode 100644 index 0000000..3cc75e8 Binary files /dev/null and b/docs/final-audit/11-mobile-routes.png differ diff --git a/docs/final-audit/12-mobile-experience.png b/docs/final-audit/12-mobile-experience.png new file mode 100644 index 0000000..a22eca4 Binary files /dev/null and b/docs/final-audit/12-mobile-experience.png differ diff --git a/docs/final-audit/13-mobile-contact.png b/docs/final-audit/13-mobile-contact.png new file mode 100644 index 0000000..5d2ffc6 Binary files /dev/null and b/docs/final-audit/13-mobile-contact.png differ diff --git a/docs/final-audit/14-menu.png b/docs/final-audit/14-menu.png new file mode 100644 index 0000000..cc86ece Binary files /dev/null and b/docs/final-audit/14-menu.png differ diff --git a/docs/final-audit/15-search.png b/docs/final-audit/15-search.png new file mode 100644 index 0000000..baa76d8 Binary files /dev/null and b/docs/final-audit/15-search.png differ diff --git a/docs/final-audit/验收报告.md b/docs/final-audit/验收报告.md new file mode 100644 index 0000000..5412916 --- /dev/null +++ b/docs/final-audit/验收报告.md @@ -0,0 +1,60 @@ +# WanderQ 官网全站最终验收报告 + +日期:2026-08-12 +环境:`http://127.0.0.1:5173/` +范围:首页、6 个主要栏目、线路/体验/美食/交通/酒店详情、咨询页、全屏菜单、站内搜索、中英文切换及移动端。 + +## 验收结论 + +当前版本已达到提交客户进行整站内容与视觉验收的条件。页面默认英文,中文切换正常;核心导航、详情页、咨询入口、图片加载与移动端布局均可用。生产构建、ESLint 与空白差异检查通过。 + +仍不建议直接对外正式发布:客户尚需补齐酒店实景与授权、供应商和人员资质、正式合作背书、真实评价、实时价格与取消条款。这些属于业务真实性和交易条件,不应由开发侧推测或代填。 + +## 验收步骤与健康度 + +1. 页面覆盖与路由:通过。遍历 40 个内部路径,均存在主内容、页脚与英文页面状态。 +2. 视觉一致性:通过。首页、线路、体验、交通、酒店、咨询及代表详情页保持统一的低饱和绿色、编辑式排版和图片语言。 +3. 响应式布局:通过。桌面端与 390px 手机端无页面水平溢出;修复了移动端线路标题与主视觉层叠问题。 +4. 导航与链接:通过。主导航、全屏菜单和详情锚点可用;酒店菜单已由旧版酒店更新为客户确认的 8 家候选。 +5. 搜索与语言:通过。站内搜索可按中英文标题筛选线路、体验、酒店、美食等内容;中英文切换后页面语言属性同步,验收结束已恢复英文。 +6. 咨询表单:通过。姓名、联系方式与体验类型等必填项使用浏览器原生校验;本次未发送真实咨询数据。 +7. 图片与媒体:通过。可见图片均正常加载;批量检查中未发现完成加载后 `naturalWidth = 0` 的实际裂图。离屏懒加载图片不计为错误。 +8. 可访问性基础项:通过。页面使用主内容区、标题层级、对话框语义和可聚焦控件;全屏菜单打开后焦点进入关闭按钮,菜单与搜索可关闭并恢复触发点焦点。 +9. 工程检查:通过。TypeScript/Vite 生产构建、ESLint、`git diff --check` 均成功。当前仅有主 JavaScript 包超过 500 kB 的非阻断构建警告,后续可按页面拆包优化首屏性能。 + +## 本轮修复 + +- 修复线路详情标签在窄桌面宽度下越界。 +- 修复手机端线路页标题被主视觉遮罩覆盖。 +- 修复交通页、酒店页重复一级标题。 +- 将全屏菜单酒店入口更新为客户新版 8 家候选,并连接到对应页面卡片。 +- 为全屏菜单补充打开焦点、关闭后焦点恢复和 Escape 键处理。 +- 将搜索框由静态输入升级为可筛选的站内内容搜索,并增加无结果提示。 +- 补充搜索对话框标题关联和搜索输入类型。 + +## 客户确认前必须补齐 + +1. 8 家特色酒店的真实原图、拍摄主体与商业使用授权,以及图片与酒店/房型的准确对应。 +2. 酒店正式中英文名、经营和预订主体、准确地址、现行营业状态、境外客人登记方式、消防与重点安全信息。 +3. 户外与文化体验的具名运营方、老师/向导/领队资质、装备、保险、应急与撤离方案、当前可约日期。 +4. 合作机构、媒体推荐、行业会员或政府合作的正式文件和 Logo 使用授权;未提供前不展示暗示性背书。 +5. 可公开的真实英文评价,以及照片、国籍、人数、线路、原始评价和授权之间的对应关系。 +6. 当前价格、房态或活动名额、报价包含/不含、税费、预付、支付、取消、退款和变更条款。 + +## 截图证据 + +- `01-home.png`:桌面首页 +- `02-routes.png`:线路栏目 +- `03-experiences.png`:体验栏目 +- `04-transport.png`:交通栏目 +- `05-hotels.png`:特色酒店 +- `06-contact.png`:咨询页 +- `07-route-detail.png`:线路详情 +- `08-experience-detail.png`:体验详情 +- `09-contact-validation.png`:咨询表单校验 +- `10-mobile-home.png`:手机端首页 +- `11-mobile-routes.png`:手机端线路 +- `12-mobile-experience.png`:手机端体验详情 +- `13-mobile-contact.png`:手机端咨询 +- `14-menu.png`:全屏菜单与新版酒店入口 +- `15-search.png`:站内搜索结果 diff --git a/docs/homepage-prototype-qa/implementation-hero.png b/docs/homepage-prototype-qa/implementation-hero.png new file mode 100644 index 0000000..8bb48ce Binary files /dev/null and b/docs/homepage-prototype-qa/implementation-hero.png differ diff --git a/docs/homepage-prototype-qa/implementation-mobile.png b/docs/homepage-prototype-qa/implementation-mobile.png new file mode 100644 index 0000000..5a73905 Binary files /dev/null and b/docs/homepage-prototype-qa/implementation-mobile.png differ diff --git a/docs/homepage-prototype-qa/implementation-story.png b/docs/homepage-prototype-qa/implementation-story.png new file mode 100644 index 0000000..bbaaad2 Binary files /dev/null and b/docs/homepage-prototype-qa/implementation-story.png differ diff --git a/docs/homepage-prototype-qa/implementation-themes.png b/docs/homepage-prototype-qa/implementation-themes.png new file mode 100644 index 0000000..280a705 Binary files /dev/null and b/docs/homepage-prototype-qa/implementation-themes.png differ diff --git a/docs/homepage-prototype-qa/source-direction.jpg b/docs/homepage-prototype-qa/source-direction.jpg new file mode 100644 index 0000000..9db136c Binary files /dev/null and b/docs/homepage-prototype-qa/source-direction.jpg differ diff --git a/docs/客户修改意见实施清单.md b/docs/客户修改意见实施清单.md new file mode 100644 index 0000000..76fdd83 --- /dev/null +++ b/docs/客户修改意见实施清单.md @@ -0,0 +1,201 @@ +# WanderQ 官网客户修改意见实施清单(V2) + +更新时间:2026-08-12 +需求来源:客户《飞书文档》32 页版本 +当前阶段:首页、三条线路、新奇体验栏目页、四项户外体验详情页、高桥专项核验页,以及洞穴餐叙、山野观景咖啡、原生村寨沉浸、节庆民俗盛典、喀斯特野奢星空露营、非遗与轻户外融合体验详情页、民族人文栏目页、“苗族蜡染・苗绣”“侗族草木染・木构建筑”“水族马尾绣”与“布依族古法技艺”详情页第一版已完成;下一步进入“民族美食文化”系列。底部第三方合作与资质标识仍等待正式文件和公开授权。 + +## 一、已经确认的执行原则 + +1. 客户文档中的中英文文案与原始图片是本轮开发的首要内容依据。 +2. 不一次性重做整站,按“顶部导航 → 首屏 → 首页下方模块 → 各栏目页 → 详情页”的顺序逐块确认、逐块开发。 +3. 企业团建与会务暂不加入官网。本轮相关文案、案例和服务范围全部排除,除非业务后续重新确认。 +4. 客户已明确的文案不擅自改写;仅修正明显的排版、标点、编号和中英文显示问题。 +5. “高级、欧美极简、低饱和、大量留白”等主观视觉要求,需要转换成统一的网页设计规范后再实施。 +6. 任何涉及资质、媒体推荐、协会会员、合作单位、保险、安全承诺和量化服务数据的内容,必须使用业务确认过的正式名称和可公开素材。 + +## 二、32 页文档内容归位 + +| 文档页码 | 主要内容 | 网站归属 | 本轮状态 | +|---|---|---|---| +| 1–2 | 三条代表线路的中英文独家亮点;户外、洞穴、峡谷、瀑布资源说明 | 首页线路卡片、线路列表、线路详情 | 纳入 | +| 3–4 上半 | 民族村寨、非遗、美食、峰林、瀑布、梯田、古镇基础内容 | 体验、风光、人文、目的地栏目 | 纳入,但后续优先使用更完整的第 9–25 页版本 | +| 4 下半 | 企业团建、会务、政企案例、团队拓展 | 企业业务栏目 | 本轮排除 | +| 5 | 首屏视觉、第三方背书、Logo、极简版式、实拍客片与评价 | 全站视觉与首页 | 纳入,优先级最高 | +| 6–7 | 24 小时在地服务、业务团队、品牌价值、团队照片、线路状态 | 首页品牌、团队与信任模块 | 纳入;部分信息待确认 | +| 8–9 上半 | 线路详情结构:地图、信息总览、亮点、日程、费用、酒店、安全、评价 | 线路详情页模板 | 纳入 | +| 9 下半–14 | Signature Guizhou Experiences;户外探险与在地新奇体验 | 新奇体验栏目及体验详情 | 纳入 | +| 15–17 | 民族人文、非遗工坊、村寨沉浸、节庆、美食文化 | 民族人文栏目及体验详情 | 纳入 | +| 18–19 | 世界级瀑布群与独特风光 | 风光地貌栏目及目的地详情 | 纳入 | +| 20–21 | 原生民族村寨、历史古镇古村 | 村寨与古镇栏目及目的地详情 | 纳入 | +| 22–24 | 青岩、娄山关实景沉浸历史体验 | 历史体验详情 | 纳入;团建适用标签不展示 | +| 25 | 在地市集与街头美食 | 探索美食栏目 | 纳入 | +| 26–30 上半 | 私家用车、接送、跨城接驳、特殊车型、服务标准与承诺 | 交通服务栏目 | 纳入;企业团用车表述需删减 | +| 30 下半–32 | 新增特色酒店及线路联动 | 精选酒店栏目 | 纳入;图片素材待补齐 | + +## 三、文档图片核对结论 + +文档内共嵌入 145 个图片文件,但其中同时包含官网截图、竞品参考截图、Logo 示例、旅行照片、活动照片、景点照片、餐饮照片和车辆照片。因此不能把 145 个文件全部直接作为网站正式图片。 + +### 可以作为正式素材候选 + +- 户外探洞、瀑降、溯溪、漂流、徒步与高桥体验照片。 +- 山野咖啡、洞穴晚宴、村寨与非遗体验照片。 +- 民族节庆、村寨、古镇、瀑布与风光照片。 +- 美食和车辆照片。 +- 两个 WanderQ Logo 文件,以箭头版新 Logo 为准。 +- 若业务确认人物授权,可评估文档中的团队合照和游客合照。 + +### 只能作为设计参考,不能直接当网站内容 + +- 当前 WanderQ 官网截图及红框标注图。 +- Visit Croatia、LPS Beijing 等第三方网站截图。 +- 客户用于说明版式、团队介绍、评价结构的示例页面。 + +### 文档中未找到完整正式素材 + +- 《国家地理》推荐的正式标识、报道链接或授权文件。 +- 贵州文旅官方合作地接标识。 +- 贵州户外探险协会会员单位标识或证书。 +- 本地非遗工坊合作证书。 +- 可直接发布的境外游客英文评价原文及评价人与照片对应关系。 +- 定制师个人照片、姓名/称呼、从业年限、语言能力和量化服务数据的完整对应表。 +- 第 30–32 页新增特色酒店对应的酒店原始照片。 + +## 四、首页从上到下的实施结构 + +| 序号 | 首页部分 | 客户要求 | 当前处理 | +|---|---|---|---| +| 01 | 顶部导航栏 | 文档未提出导航结构调整;只明确 Logo 错误 | 保留导航结构,使用新 Logo,检查移动端和链接 | +| 02 | 首屏主视觉 | 浅色、低饱和、高级质感、欧美极简、文字清晰 | 需要确定单图/轮播、最终主图、默认语言 | +| 03 | 顶部信任背书 | 增加媒体、官方合作与协会等第三方背书 | 正式素材与名称确认后实施,不使用假 Logo | +| 04 | 品牌主张与核心价值 | 打破旅游泡泡、真实在地生活、一人一行程、透明无套路 | 第一版已完成:客户原文核心意思、真实村寨人物图、五项编号价值说明 | +| 05 | 三大体验入口 | 户外探险、民族人文、独特风光 | 第一版已完成:洞穴桨板、非遗工坊、瀑布群实拍图与双语入口短文 | +| 06 | 三条代表线路 | 三条线路增加各 3 个独家亮点 | 第一版已完成:首页卡片已使用第 1–2 页的 9 个中英文亮点;详情页后续按第 8–9 页模板处理 | +| 07 | 团队与在地服务 | 团队照片、定制师信息、24 小时在地服务 | 第一版已完成:真实团队/旅行现场照片与三项服务说明;个人姓名、年限及量化数据待业务补充 | +| 08 | 定制流程 | 客户没有明确要求删除现有三步流程 | 已复核并保留三步流程,继续使用极简分栏呈现 | +| 09 | 真实客片与英文评价 | 国籍、人数、线路、英文短评和行程照片 | 真实现场影集第一版已完成;文档未提供照片与国籍、人数、线路、英文原评的一一对应关系,评价卡待补资料 | +| 10 | 出行方式对比 | 万趣私家定制 vs 大巴团 vs 国际 OTA | 第一版已完成:按 7 个相同维度进行克制对比,并标明不同运营商和产品存在差异 | +| 11 | 最终咨询行动区 | 引导用户开始定制 | 第一版已完成:单一主行动按钮,并提示日期人数、兴趣、节奏与住宿三类有效咨询信息 | +| 12 | 底部合作与资质 | 官方合作、协会会员、工坊证书 | 暂不上线;正式文件、Logo 原件与公开授权确认后实施 | +| 13 | 页脚 | 客户没有提出结构重做 | 已复核并保留精简结构,统一品牌名、服务定位、邮箱和法律链接 | + +## 五、栏目页与详情页实施矩阵 + +### 1. 线路栏目与线路详情 + +- 首页三条线路补充第 1–2 页提供的 9 个中英文独家亮点。 +- 线路栏目页已改为三条代表线路的大图编辑式结构:经典全景线、喀斯特户外探险线、均衡探索线;取消仅有三条主线时不必要的复杂筛选。 +- 列表卡片直接说明路线方向、节奏、适合人群和三项客户原文独家亮点,不展示缺少报价依据的宽泛价格区间。 +- 线路详情统一采用:动态地图、核心信息、Why This Trip、时间轴、每日行程、费用包含/不含、住宿参考、安全贴士、关联评价。 +- 经典全景线详情页第一版已完成:核心信息总览、3 项 Why This Trip、6 节点路线示意、8 天上午/下午/晚上拆分、车程参考、餐食住宿字段、费用包含/不含和 6 项安全实用贴士均已落地。 +- 经典全景线不展示未经核验的酒店涉外资质和不对应酒店的图片;真实酒店 2–3 档与关联客评继续等待正式资料。 +- 喀斯特户外探险线详情页第一版已完成:使用客户户外实拍素材,补齐 7 天逐日骨架、三级活动强度、四项 Go / No-go 安全门槛、恢复日、地面替代方案、费用边界和 6 项安全说明。 +- 户外线暂不发布未经核验的 370 米蹦极、260 米翼装、瀑降高度、CE 装备、向导证书、最低年龄等强承诺;具体运营方、人员、装备、通信、保险和撤离机制需进入正式方案。 +- 均衡探索线详情页第一版已完成:使用客户村寨、非遗、餐食和山野实拍素材,补齐 8 天逐日方案、慢住/跟随/轻探三层结构,以及“提前锁定/当天可调/可能替换”的弹性边界。 +- 均衡线对客户“每日完全灵活”做了可执行化处理:村寨住宿、主人、农民带路人、非遗老师与车辆需提前确认;开放时间和安全条件允许时再调整停留时长与轻量活动。 +- 当前文档同时出现“线路暂无”和“成熟定制线路合集”,需要确认“暂无”指暂无成品页、暂无价格,还是暂无可售线路。 + +### 2. 新奇体验与户外探险 + +- 使用 `Signature Guizhou Experiences` 作为栏目头部内容。 +- 分为 `Karst Outdoor Adventures` 和 `Unique Local Experiences` 两大系列。 +- 每项体验详情至少展示:英文名称、地理依托、核心体验、适合人群、难度/体力、安全保障、可加入的线路。 +- 370 米蹦极、260 米翼装飞行、CE 装备、持证向导等事实和安全表述需业务确认后上线。 +- 新奇体验栏目页第一版已完成:取消原有“类型 + 地点”的平铺筛选墙,改为两大系列的编辑式选择结构;户外系列公开 4 个方向,在地系列公开 5 个方向。 +- 栏目页已增加活动强度、执行条件、组合线路和公开边界;370 米蹦极、翼装体验及未核验的高度、世界纪录、证书、年龄承诺继续不进入公开可售清单。 +- “地下喀斯特探索”详情页第一版已完成:以客户第 10 页中清镇、安顺与绥阳洞穴区域为地理依托,建立轻量 / 活力 / 进阶候选三档分级、五步现场流程、四项 Go / No-go 门槛和三条可组合线路。 +- 洞穴详情页未将“全年 18°C”、“6 岁以上”、CE 装备、认证向导和进阶洞段写成全区域固定承诺;以公开边界模块明确标记为“按具体点位与运营方复核”。 +- “瀑降与峡谷绳索”详情页第一版已完成:提取并使用客户文档中 4 张瀑降实拍原图,建立初次体验候选 / 活力 / 进阶候选三档分级、五步执行流程、四项 Go / No-go 门槛和三条线路组合边界。 +- 瀑降详情页未将 20–86 米、36 米入门、86 米进阶、双绳保护、向导/教练资料、实时水量监测、救生装备和保险覆盖写成默认承诺;全部列为具体点位与运营方的复核项。 +- “峡谷溯溪与白水漂流”详情页第一版已完成:提取并使用客户文档中 5 张河流实拍原图,把平缓亲水 / 活力溯溪 / 白水候选拆分为三档独立决策,建立五步水上流程、四项 Go / No-go 门槛与三条线路组合。 +- 水上详情页未将“全年龄”、平缓段亲子、专业救生衣与护具、持证溯溪向导、全程水位/天气实时监测写成默认承诺;客户图片只证明平缓水域场景,不用于证明白水漂流已可售。 + +### 3. 民族人文、风光、村寨与古镇 + +- 以客户英文文案为主要内容,中文作为切换语言内容。 +- 非遗、村寨、节庆、瀑布、古镇采用统一卡片和详情结构,不把全部长文堆在列表页。 +- 节庆日期按文档保留“每年随农历变化”的提示。 +- 青岩和娄山关沉浸体验中的“企业团建”适配标签本轮删除。 + +### 4. 探索美食 + +- 使用客户提供的 `Local Market & Street Food Tour` 内容和 5 类代表小吃。 +- 首页/列表页使用短文案,详细英文介绍放美食详情页。 + +### 5. 交通服务 + +- 页面英文为主展示文案,中文随语言切换。 +- 服务结构调整为:全程私家用车、机场/高铁接送、跨城景观接驳、特殊场景车型、服务标准、服务承诺。 +- 企业团、研学团相关表述本轮删除或改为中性的小团/同业接待描述。 +- “车龄 5 年以内、司机 5 年以上经验、基础英文、免费安全座椅、足额营运保险、延误免费等候 60 分钟”等承诺需逐项确认。 + +### 6. 精选酒店 + +- 按野奢地貌、民族村寨、田园山野、城市/主题四类组织。 +- 使用文档中的中英文酒店介绍和线路联动建议。 +- 第 30–32 页没有嵌入对应酒店原始照片,不能用无关风景图替代。 +- “所有酒店均具备涉外资质”只能在每家酒店资质核验后展示。 + +## 六、第一批必须确认的问题(顶部部分) + +确认结果(2026-08-11): + +1. 首屏保留自动轮播,并提供分页选择与暂停/继续控制。 +2. 首屏图片由开发侧从客户文档素材中筛选和制作。 +3. 官网首次打开默认显示英文,用户仍可切换为中文。 +4. 不伪造《国家地理》推荐、政府合作或协会会员等第三方身份。正式文件补充前,顶部使用“贵州本地团队、纯玩私家小团、英文旅行支持、24/7 在地支持”四项真实服务信号;未来可替换或补充正式背书。 + +## 七、当前执行顺序 + +1. 顶部导航和新 Logo:已完成。 +2. 首屏主视觉与客户素材轮播:已完成第一版。 +3. 默认英文:已完成。 +4. 真实服务信任栏:已完成第一版。 +5. 桌面端、移动端、轮播暂停/继续和图片加载:已检查通过。 +6. 品牌主张与核心价值:已完成第一版;使用客户第 6–7 页内容与文档原图,桌面端、移动端及中英文排版已检查通过。 +7. 三大体验入口:已完成第一版;使用客户第 9–19 页中的实拍素材与核心表述,桌面端、移动端及中英文排版已检查通过。 +8. 三条代表线路:首页第一版已完成;使用客户第 1–2 页线路名称、9 个独家亮点和文档实拍图,移除过宽且误导性强的价格区间。 +9. 团队与在地服务:已完成不含虚构个人资料的第一版;使用客户文档团队照片,突出贵州本地规划、英文文化沟通和 24 小时在地协调。 +10. 定制流程:已复核,客户未要求删除,保留现有三步极简流程。 +11. 真实客片:已使用客户文档中的餐食、户外、洞穴、山野、非遗和瀑布照片完成第一版静态影集。 +12. 英文评价:文档仅提出结构要求,未提供可核验的“照片—国籍—人数—线路—英文原评”对应数据,暂不上线虚构评价。 +13. 出行方式对比:已完成第一版;覆盖行程设计、节奏、在地深度、语言、现场响应、价格方式和适合人群,不使用贬低同行的绝对化表述。 +14. 最终咨询行动区:已完成第一版;使用单一“开始规划”入口,并通过三项提示降低用户咨询门槛。 +15. 底部合作与资质:文档未提供可核验的正式标识与授权,继续保留为待补项,不使用文字或占位 Logo 暗示合作关系。 +16. 页脚:已完成复核;统一 WanderQ 品牌名、贵州私家定制旅行定位、联系邮箱与法律链接。 +17. 线路栏目页:已完成第一版;三条代表线路使用大图模块、决策信息和客户第 1–2 页的 9 项中英文亮点,复杂筛选与宽泛价格区间已移除。 +18. 经典全景线详情页:已完成第一版;使用客户实拍素材与 3 项独家亮点,补齐 8 天行程、路线示意、费用边界和实用贴士。 +19. 待补资料:经典线 2–3 档真实酒店原图、当前涉外接待状态、对应线路的真实英文评价。 +20. 喀斯特户外探险线详情页:已完成第一版;按客户第 10–14 页内容建立三级强度、四项出发门槛、7 天日程、费用边界和天气/水位替代方案。 +21. 户外线待补资料:具体合作运营方、领队/向导资料、装备清单、通信与撤离方案、专项保险说明,以及“8 年以上本地经验”证明。 +22. 均衡探索线详情页:已完成第一版;按客户第 1–2 页和第 14–18 页内容建立 8 天日程、三层体验结构、弹性边界、费用说明和 6 项实用提示。 +23. 均衡线待补资料:可接待境外客人的村寨住宿清单及真实图片、主人/农民带路人/非遗老师资料、体验价格和可预约档期。 +24. 新奇体验栏目页:已完成第一版;按客户第 9–15 页拆分为 `Karst Outdoor Adventures` 与 `Unique Local Experiences`,使用 4 + 5 个策展式体验方向、风险边界和三条组合线路入口。 +25. “地下喀斯特探索”详情页:已完成第一版;使用客户洞穴实拍图,补齐地理依托、三档强度、适合人群、五步流程、装备/天气/水位/退出门槛和可加入线路,并通过英文默认、移动端、裂图与控制台检查。 +26. “瀑降与峡谷绳索”详情页:已完成第一版;使用客户文档的 4 张实拍图,补齐地理依托、三档分级、适合人群、五步流程、水量/岩面/锚点/绳索/人员/保险/撤离门槛和可加入线路,并通过英文默认、移动端、裂图与控制台检查。 +27. “峡谷溯溪与白水漂流”详情页:已完成第一版;使用客户文档的 5 张实拍图,补齐地理依托、三档水上模式、适合人群、五步流程、水文/河段/运营方/人员/装备/保险/退出门槛和可加入线路,并通过英文默认、移动端、裂图与控制台检查。 +28. “喀斯特峰林徒步与骑行”详情页:已完成第一版;使用客户文档的 4 张峰林徒步/景观实拍图,拆分万峰林田园慢骑或步行、茂兰森林徒步与赤水河谷进阶骑行三种独立产品,补齐五步流程、路线/天气/人员/装备/保险/退出门槛,并把“两万座峰林、160 公里专用自行车道、全年龄段”转为具名产品核验项。 +29. “高桥极限挑战”专项核验页:已完成第一版;采用“桥梁观景候选 + 坝陵河大桥蹦极高风险候选 + ‘破茧之翼’项目性质待确认”的三层结构。公开使用坝陵河位置、客户 3 张现场图和 2019-01-12 认证的 370.25 米商业蹦极设施历史事实;不把“世界最高”、370 米实际自由落差、低空跳伞/滑翔伞日常开放或“普通人翼装飞行”写成当前可售承诺。第 4 张合成宣传海报未作为真实客片使用。 +30. “洞穴野奢体验・地下咖啡与烛光晚宴”详情页:已完成第一版;从客户 6 张素材中采用 3 张能支撑洞穴接待空间的图片,未使用大型探洞团图片及带企业品牌和大量可识别人物的活动记录。将洞穴咖啡茶点、私家晚宴、轻量探洞后落座拆为三个等级,补齐场地授权、洞穴保护、消防/电力/照明、餐饮卫生/过敏原/酒水、人员/接驳/保险/撤离门槛;“18℃恒温”、真实烛火、专属英文人员和完整配套只按具名场地与报价确认。 +31. “悬崖与山野云端咖啡”详情页:已完成第一版;从客户 6 张素材中采用 4 张能够支撑公开观景咖啡馆、带护栏平台和山林咖啡空间的图片,未使用悬挂座椅“侠客咖啡”及专业洞穴活动图片。将具名观景咖啡馆、顺路山林/梯田/村寨咖啡停靠、私家户外冲煮拆为三个等级,补齐场地身份/授权、步道/临崖/天气、饮品/热水/火源/卫生/垃圾、客人/接驳/应急门槛;“小众、无人拥挤、独享景观”和图片地理归属只按具体点位与日期确认。 +32. “原生村寨深度生活体验”详情页:已完成第一版;核对黄岗村、掌坳苗寨的官方地理口径与 6 张客户素材,采用 4 张村落、木楼生活空间和田野图片,未使用无人物身份/授权说明的持枪人物及近距离老人肖像。把公开村寨慢行、具名主人半日与一至两晚住宿候选拆为三档,补齐主人/社区同意、住宿/消防/境外客人登记、餐饮/农事/儿童、隐私/拍摄/收益门槛;“原生态、完整民俗、传承人一对一、全部收益直达村民”不作统一承诺。 +33. “喀斯特野奢星空露营”详情页:已完成第一版;客户本组 3 张图片实际为山地景观住宿/观景平台,没有帐篷、夜景或营地服务证据,因此仅作为舒适度和景观参考,并补充采用一张客户此前提供的喀斯特谷地普通帐篷图片说明营位类型。将具名经营型营地、固定山地住宿 + 夜观和私家临时搭建拆成三档,补齐用地/经营、森林防火/篝火、雷电/风雨/山洪、固定避难空间、卫浴饮水/食品、夜间值守、儿童临边、撤离与垃圾污水门槛;银河、日出、无人打扰、24 小时值守和卫浴保障均不作无条件承诺。 +34. “非遗 + 户外融合体验”详情页:已完成第一版;客户本组 3 张图片均为扎染打卡空间概念拼图,没有展示梯田徒步、植物观察、古法造纸、茶园骑行或制茶,因此仅采用 1 张并在页面明确标注“客户概念参考 / 非真实场地证明”,正式主视觉和主体画面采用客户此前提供的田野与手作素材。将梯田慢行 + 具名蜡染工坊、植物观察 + 石桥古法造纸、茶园步行/骑行 + 制茶拆为三组独立产品,补齐两端具名主体、路线/接驳/季节、老师/材料/作品、野生植物不默认采集、骑行道路/头盔/保障车、儿童工具/热蜡/染料与天气备选门槛。 +35. “民族人文”栏目与核心体验入口:已完成第一版;采用客户第 15–17 页英文引言的核心意图,但把 `17 indigenous ethnic groups` 调整为有官方依据、语义更准确的 `17 long-established ethnic minority groups`。页面以客户 4 张工坊/村寨实拍构建低饱和编辑式视觉,设置苗族蜡染・苗绣、侗族草木染・木构建筑、水族马尾绣、布依传统织染技艺四个入口,并明确具名老师、真实时长、拍摄同意、作品带走和收益路径等接待原则。客户图片主要证明蜡染/手作氛围,未冒充水族马尾绣或布依技艺实拍;村寨和节庆仅做下一层入口与边界提示。 +36. “苗族蜡染・苗绣”详情页:已完成第一版;采用客户本组 5 张蜡染/手作实拍中的 4 张,主视觉使用无人物的工坊空间,人物近景明确标注“客户提供实拍,身份与公开使用授权需归档”。将蜡染主题、苗绣主题和双主题半日拆为三种策划方式,补齐具名工坊与老师、单一真实课程目标、蜡材/染料/针具/热源、儿童与皮肤敏感、英文人员、拍摄同意、费用结算、作品完成/干燥/带走或后寄五步流程及四类确认门槛;“第三代传承人、天然蓝靛、全程英文、所有作品当天带走”均改为按工坊与日期核验。 +37. “侗族草木染・木构建筑”详情页:已完成第一版;客户素材能够提供村寨、木构和蓝染氛围,但不能证明具体侗布工坊、老师与建筑身份,因此所有图片均标注具体地点/工坊待确认,其中蓝染图明确写明“非侗布工坊或课程证明”。将具名侗布染制工坊、鼓楼/风雨桥公共建筑观察、工坊 + 木构村寨完整一日拆为三种方式,补齐具名侗寨、工坊与建筑讲解人、染料/亮布整理材料、具体建筑结构来源、公共空间与社区活动优先、居民拍摄、木桥湿滑/临水临边、真实距离、英文支持和费用结算五步流程及四类确认门槛;不把公开参观包装成传承人私享课,也不把“纯天然草木染”“所有建筑不用一钉一铁”作统一承诺。 +38. “水族马尾绣”详情页:已完成第一版;客户提供的两张本组图片只能证明通用手作桌面、线材和操作氛围,不能证明三都水族马尾绣工坊、老师、材料或针法,因此页面主视觉、影集和流程图均主动标注“非马尾绣工序证明”,未把普通刺绣、蜡染或通用手作冒充马尾绣实拍。依据文化和旅游部、国家民委及贵州公开资料,将体验拆为 45–75 分钟工艺演示、2–3 小时马尾芯缠线与基础小样、4–5 小时或多次深度学习三种方式,补齐三都具名工坊与老师、官方传承人称号依据、马尾来源/清洁/预处理、丝线缠裹与盘绣关系、针具与儿童、拍摄同意、英文支持、费用结算、作品完成/老师收尾/后寄五步流程及四类确认门槛;复杂背带/服饰作品不作短课完成承诺,“刺绣活化石”只作为有来源的文化称谓。 +39. “布依族古法技艺”详情页:已完成第一版;客户原文提出“古法织造 + 葫芦彩绘 + 600 年石头寨”,但现有图片组只能证明通用贵州蜡染/手作氛围,无法证明布依工坊、石头寨、织机、葫芦彩绘或授课老师,因此页面所有图片均明确标注“非布依工坊或具体课程证明”。公开资料可以支持安顺石头寨有 600 多年历史及当地蜡染传统,也能支持黔西南布依纺织包含绞纱、上浆、排线、织布与服饰制作等复杂工序,但未找到“石头寨葫芦彩绘”对应的地方与传承依据;因此将体验拆为安顺石头寨具名蜡染、黔西南具名织造/服饰、葫芦彩绘待核验候选三种方向,补齐地区与技艺分开归属、具名工坊/老师/课程、单一可完成工序、蜡材/染液/织机/颜料或热针、儿童与工具安全、拍摄同意、英文支持、作品完成/干燥/后寄和费用结算五步流程及四类确认门槛;不把不同地区、材料和老师拼成“一站式布依古法课”。 +40. “原生村寨沉浸”系列归位:已完成;将原详情页从笼统的“公开慢行 / 主人半日 / 住宿候选”升级为客户明确提出的苗族吊脚楼住家、侗族鼓楼社区生活与布依石头寨慢居三条方向,并保留半日、一晚、最长 3 天 2 晚的逐级核验逻辑。掌坳、黄岗、安顺石头寨/高荡仅作地理候选,公开资料只能证明文化与建筑背景,不能证明当前可售房间、主人或涉外接待能力;页面因此补齐具名经营主体、真实房型与卫浴、现行卫生与消防、实名登记、境外客人入住非旅馆住所后 24 小时内登记、楼梯/火源/夜路、餐食过敏、家庭与居民拍摄、英文支持、费用与收益路径等门槛。侗族大歌、农事、家宴、火塘故事和手作均按社区、主人、季节与日期确认,不承诺每日发生;4 张客户图片新增逐图用途说明,不再暗示具体村寨、客房或住宿主体。 +41. “节庆民俗盛典”系列:已完成第一版;新增独立详情页并在民族人文栏目增加入口,保留客户提出的苗年、苗族姊妹节、侗族大歌节/黄岗喊天节、水族端节四项方向,但将传统历法日期、当年政府公共活动与村寨/家庭内部仪式拆开表达。页面写明 2026 年黔东南苗年州级假日为 11 月 15 日、2026 年台江姊妹节公共系列活动为 4 月 30 日至 5 月 10 日且现已结束;黄岗喊天节按农历六月十五核验,从江侗族大歌节历史上曾在 11 月 28 日前后举办但不作每年固定公历日期承诺;水族端节“49 天”解释为不同氏族/村寨批次的整体跨度,而非同一地点连续 49 天游客活动。补齐当年主办与通知、公开活动/仪式边界、交通管制/拥挤/烟火/斗牛/赛马、摄影与未成年人、无人机、具名住宿/涨价/预付退款、天气和取消替代等门槛。采用客户 4 张苗族节庆图片并逐图标注地点、年份、人物和公开授权待归档,明确不得用于证明侗族喊天节或水族端节。 +42. “民族美食文化”系列:已完成第一版;新增独立详情页并在民族人文栏目增加入口,保留客户提出的民族家宴烹饪课、原生长桌宴、在地市集风味探访三项方向,但将家庭厨房、私房餐叙、持证餐厅、节庆/社区宴席、景区商业表演与公共市场拆开表达。家宴课按具名主人、当天营业市场、实际厨房/场地与一至两道真实菜单确认;酸汤鱼、糯米饭和双语食谱只作候选,不承诺每位主人均可提供。长桌宴须核对具名组织者、村寨或场地、最低人数、菜单、座席、天气备选、敬酒/酒歌、无酒精替代、交通、洗手间、价格与取消,不把商业场次写成家庭宴,也不承诺临时到村即开席。市集探访按具名市场、真实营业时段与 3–5 份小份试吃设计,丝娃娃、牛肉粉、烤香猪仅作地区性线索,不承诺每个乡村早市都有。依据《中华人民共和国食品安全法》、市场监管总局《餐饮服务食品安全操作规范》和现行《贵州省食品安全条例》,补齐接待主体、原料采购/保存、生熟分离、饮水、清洁消毒、熟度、严重过敏原与交叉接触、辣度、素食/清真需求、刀具/热源、未成年人看护、酒精与驾车、紧急联系、拍摄同意、费用、最低人数和取消退款等门槛;无法安全满足时默认替换为具名餐厅地方风味分享餐。客户本组 90–94 为带品牌字样的商业宣传海报,未采用;采用 95–98 四张真实菜品/餐桌图片,并逐图标注菜名、餐厅、制作人、组织者、地点、年份、商业属性及使用授权待归档。 +43. “世界级瀑布群”系列:已完成第一版;新增独立详情页并在新奇体验栏目新增 `Iconic Landscapes` 景观系列入口,将黄果树成熟景区、滴水滩山谷多级瀑布候选和赤水丹霞瀑布拆成三套独立游览逻辑。黄果树依据公开资料保留大瀑布高 77.8 米、宽 101 米,以及陡坡塘—大瀑布—天星桥完整一日的分区概念,但入园时段、实名预约、观光车、水帘洞/步道开放、客流与真实步行按日期确认;不以“亚洲最大”、固定丰水、固定彩虹或水帘洞必开作承诺。滴水滩依据贵州公开资料保留七级、约 410 米总落差,但明确其不是黄果树核心景区同一套成熟动线,入口、道路、停车、步道、观景台、洗手间、通信和当前开放必须单独核验;不使用“隐秘、无人、无遮挡、秘境直达”话术。赤水明确为世界自然遗产“中国丹霞”六个组成地之一,核心以赤水丹霞旅游区・大瀑布(原十丈洞,公开资料约高 76 米、宽 80 米)规划,四洞沟等其他景区按独立门票、接驳和时间确认,不写成“几十处瀑布一次看完”,也不与安顺黄果树做同日往返。补齐官方开放/票务/入口、上游降雨/涨水/雷电/山洪/落石/水雾湿滑、总步行/台阶/排队/电梯、儿童与长辈、轮椅或行动不便替代、接驳车安全带、摄影/三脚架/无人机、警戒线和关闭替代等门槛;2026 年价格只采用省发改委政府定价清单作规划参考,最终以当日官方渠道为准。客户本组 100–108 共 9 张瀑布图片,采用 100、102、105、108 四张无近距离人物且能支持主瀑、水幕、多级瀑布与丹霞地貌的画面;103、106、107 因人物靠近水边/非标准边缘可能暗示越界机位,104 因具名住宿和具体瀑布关系不清,均未采用;109 已进入下一章旧版页面截图。所有采用图片逐图标注具体瀑布、日期、机位与公开授权待归档,不把不同地点或不同水期混作同一处。 +44. “原生民族村寨”系列:已完成第一版;新增独立详情页,并将其与原“原生村寨沉浸”页分工为“比较去哪座代表村寨”与“说明半日/过夜怎样被接待”两层。页面保留西江、肇兴/黄岗、岜沙、安顺布依石寨四组方向,但取消“越不商业越原生态”的真实性排名:西江明确为服务成熟、客流与商业经营集中的景区型村寨,依据公开资料采用 1,300 余栋传统木质吊脚楼表述,预约、观光车、行李、台阶、木构消防、住宿和境外客人登记按日期确认,不承诺“私家避人机位”;肇兴保留仁义礼智信五座鼓楼,黄岗作为黎平县双江镇另一处具名社区单独说明,喊天节按农历六月十五与当年通知核验,侗族大歌按节庆、集体交往和接待语境确认,不写成每天随到随唱;岜沙使用正式村名,不以“枪手部落”为产品标题,将镰刀剃头、迎宾和火枪元素明确为可能进入景区演艺的表达,只按当日公开节目与官方现场管理,不保证鸣枪、剃头或成人礼,更不安排游客接触/操作枪械与镰刀;布依方向明确扁担山石头寨与高荡是两个不同村寨,不把两地历史、建筑与课程合并为“600 年全石头村”,家访、织染和慢行须落实具体村名、主人/老师、材料、费用与同意。补齐村寨/景区/主人身份、开放与收费边界、门票取消、交通接驳、真实房型/卫浴/消防/行李/住宿登记、节目与工具安全、儿童长者、住宅/仪式/成人/未成年人肖像/商业拍摄/无人机及图片版权等门槛;居民日常、农事、家宴、歌唱和人生礼俗均不作自动开放承诺。客户本组 image110–119 共 10 张图片采用 110、116、118、119 四张,用于西江暮色/全景和侗寨山谷/鼓楼氛围;其中侗寨两图的具体村名仍待确认,未拿西江或侗寨图片冒充岜沙、布依石头寨实拍。image120 起已核准进入下一章“历史古镇古村”。默认英文、中文切换、桌面与移动端、图片加载、控制台和水平溢出已完成检查。 +45. “历史古镇古村”系列:已完成第一版;新增独立详情页并纳入体验归档,将青岩古镇、镇远古城与天龙屯堡拆成明代石城、㵲阳河商贸古城和安顺屯堡村落三条不同历史线索,不用“古色古香”或江南水乡模板笼统合并。青岩依据贵州公开资料采用明洪武年间设堡、六百余年历史积累的口径,具体从石城墙、定广门、石牌坊、宗教建筑、街巷与小吃进入;公共古镇空间与收费景点/套票分开,2026 年政府定价清单所列景区门票和套票不直接硬编码为永久价格,正式报价须写明包含景点。镇远依据公开资料采用公元前 202 年置县、2,200 余年建置史及明清㵲阳河—湘黔滇驿道商贸节点表述,明确古城仍是居民与商业并存的县城;青龙洞、石屏山、下㵲阳河游船等为不同收费项目,灯光、游船、沿河噪声、水位/暴雨和住宿位置按日期确认。天龙明确为安顺屯堡文化的一处具名村落,明代军屯、后续移民屯田与各民族交往共同塑造其语言、服饰、石木建筑、饮食和地戏传统,不写成“六百年从未改变”的静态遗址;安顺地戏 2006 年列入首批国家级非遗,景区演武堂每天定时的约 10 分钟折子戏与春节、农历七月等传统节令中的村寨地戏分开说明,均不承诺随到随演。补齐建置史与具体遗存来源、公共空间/单点门票/联票、预约与开放、维修、演出、游船/接驳、停车、城墙/山体台阶、湿滑石板、临河和夜路、老人儿童、文物保护、宗教/仪式/住宅/地戏后台、成人与未成年人肖像、商业拍摄、三脚架、无人机及图片版权等门槛。客户本组 image120–124 共 5 张图片采用 120–123 四张,其中 120–121 仅标注为客户文档对应青岩的古镇/石城墙氛围,具体建筑和墙段待确认;122–123 对应镇远夜景并明确不保证同等亮灯、游船和客流;124 与 123 内容重复未采用。客户没有提供可明确证明天龙屯堡的图片,未拿青岩或镇远照片冒充天龙。image125 起已核准进入下一章“实景沉浸式历史演绎”。 +46. “青岩战斗・古镇实景沉浸演绎”专项页:已完成第一版;核验过程发现客户构想已经出现可对应的现有产品,但两者不能直接画等号。中国国防报 2026 年 5 月报道确认花溪区文旅部门与景区运营方以“青岩狮子山阻击战”为素材打造《战青岩》,用实景实战与角色扮演开展国防教育;贵阳网 2026 年 7 月进一步确认项目由贵阳青岩古镇景区管理有限公司与贵州创新文化旅游开发有限公司于 2026 年 1 月合力打造,4 月 29 日起全面运营,落地定广湖畔三处实景战场区域,截至 7 月 5 日累计接待超过 3 万人次,公开角色包括侦察兵、医务员、担架手、机枪手、士兵和物资小队。页面因此将状态修正为“已有运营产品 / 境外私家接待待专项确认”,不再写成纯概念。与此同时,客户文档所写的石巷、城墙、历史院落、线索追踪、情报传递、真人 NPC、剧情解锁、城墙声光电战斗和史实复盘,尚无证据证明全部属于当前《战青岩》的既有玩法,故作为二期共创方向单独标注。历史层面依据贵州省政协公开资料与贵阳市文旅规划,保留 1935 年 4 月青岩一带战斗及红军狮子山战斗遗址线索,但要求具名历史顾问将狮子山/簸箕山等史迹与现今动线逐点对应,不把整座古镇或所有院落称为原战场。补齐两家运营主体、当前场次/容量/散客或包团/价格/取消、私家与境外客接待、英文主持或翻译、真实时长、年龄/体能/健康与陪同、服装尺码清洁、仿真道具、爆破烟雾、消防急救通讯、雨天泥泞与障碍退出、医疗转运、保险、肖像同意、文物及公共空间许可、史实与戏剧化区分等门槛;客户提出的 3–4 小时、12+、全程英文、专业演员、私家包场、固定场次和城墙声光电均不作无条件承诺。后续检查客户插图锚点发现,紧跟娄山关标题的 image126 画面文字明确写着“战青岩”,实际属于青岩而非娄山关,已将其补入青岩页主视觉、图库和流程画面,同时保留人物同意、拍摄日期与商业使用授权待归档;未把娄山关 image125 冒充青岩。页面提供现有《战青岩》实景体验、青岩史迹步行和二期古镇任务剧本三种强度,允许不接受战争模拟的客人退出角色扮演并改为历史步行。 +47. “娄山关战役・山道沉浸行军演绎”专项页:已完成第一版;公开资料能够确认娄山关红军战斗遗址、《娄山关大捷》实景演出及游客参与型产品,但客户所写的完整山道移动剧场尚不能视为现有产品。依据党史资料采用 1935 年 2 月 25 日至 26 日主要战斗、遵义会议后首次大捷的口径,并将战斗遗址陈列馆、关口、大尖山/小尖山/点金山等公开遗址线索与演艺景区分开;纠正客户“登顶品读娄山关摩崖石刻”的表述,今天大尖山一侧展示的是后建的大理石《忆秦娥・娄山关》手迹碑,不写成 1935 年原始摩崖石刻。人民日报、人民网与贵州媒体可以证明《娄山关大捷》实景演出长期存在,2026 年“五一”由原演出升级推出“跟着团长攻打娄山关”游客参与项目,公开报道出现游客换装、跟随百余名演员进入战壕/密林及 13:30 场次;但场次、票价和每日运营均不直接固化,仍以出行日期运营方书面信息为准。客户要求的沿古驿道连续 4–5 小时、每个历史地标分段演员演绎、登顶剧情高潮、全员年代服装道具、完整英文剧本、专业英文历史向导、门票与演员协调全部包含,未找到对应的现行路线、供应商和英文接待证据,因此作为二期共创方案。页面将产品拆为现有参与型演出、战斗遗址与诗词半日线、二期 4–5 小时移动山道剧场三档,补齐具名运营主体、景区/演出/互动票种、容量场次、私家团、取消、演艺场与遗址地图、路线距离/爬升/坡度/路面/补水/退出点实测、历史审校、服装与仿真道具、火焰/烟雾/强声/风向/消防隔离/急停、山地高温暴雨雷电大雾湿滑落石森林火险、年龄与心肺/骨关节/听力/呼吸/孕期/创伤敏感、知情自愿、前后领队、通信急救医疗转运和保险等门槛。客户同组 image125–126 实际在同一图片段落中:image125 文字明确标注“攻打娄山关”,可用于支持演员、制服、烟雾与大型火焰的演出氛围,但拍摄日期、场次、制作方、人物同意和商业使用授权待归档;image126 明确标注“战青岩”,已移回青岩页,未拿来证明娄山关。企业团建适配标签继续按客户已确认边界删除。 +48. “在地市集・街头风味巡礼”内容归位:已完成;客户本段与已完成的“民族美食文化”详情页属于同一产品体系,因此未重复新建同质页面,而是在原页面新增独立 `Local Market / Street-Food Tour` 板块,完整保留客户指定的花溪牛肉粉、贵阳肠旺面、贵阳丝娃娃、青岩豆腐与玫瑰冰粉、水城烙锅五类内容。依据贵州“黔菜师傅”菜品遴选、传统优势食品产业方案及地方公开资料,明确花溪牛肉粉、肠旺面和丝娃娃属于贵阳核心早餐/小吃;肠旺面英文说明直译猪大肠、血旺、脆哨与红油,不用模糊“特色肉面”规避食材;丝娃娃不固定承诺十种以上蔬菜,并提示小麦、花生、芝麻、酱油、折耳根和辣椒;青岩风味炒豆腐与贵阳玫瑰冰粉分别有公开名录依据,但未证明是固定传统套餐,因此只作为一咸一甜的路线组合,分别核验豆制品、油炸交叉接触、冰品用水和糖量;水城烙锅明确归属六盘水/水城,更适合作为共享正餐,不为了凑齐“贵阳五种小吃”跨城搬运或算作一口式试吃。客户提出的英文向导带领 5–6 种小吃试吃,调整为通常 3–5 份,只有步行距离、客人食量与实际摊位都合适时扩展至 5–6 份;不承诺在同一市场一次吃齐五类。贵阳城市版拆为早餐线与夜市线二选一,青云市集可作为成熟夜间商业街区候选,但依据贵州省政府公开资料明确它是餐饮、文创与娱乐混合的现代综合市集,不包装成传统农贸早市;具名门店、真实营业、拥挤度、摊位身份、熟制状态、生熟分离、饮水、严重过敏原、辣度、支付、座位、洗手间和天气按日期确认。页面继续沿用客户已提供的真实菜品/餐桌素材,因为本段没有新增图片;桌面、移动、中英文、图片和构建完成验证。 +49. “用车服务”栏目页:已完成第一版;完整保留客户提出的全程私家团专属用车、机场/高铁专车接送、跨城景观专线和特殊场景车型四类结构,并采用客户文档中 5 座、7 座与 9 座车型组的 4 张车辆实图替换原来的无关风景图。页面将额定座位与建议客人数/行李容量分开,补齐日期与路线、成人/儿童、行李/设备、车型匹配、承运资质与保险、司机工时、报价/等候/变更条款、出发前车辆与接站信息五步确认流程;英文支持明确由英文司导、随车讲解或远程旅行顾问按订单确认,不假设每位司机会英语。依据现行旅游经营与道路客运要求加入具名合格供应商、营运资质、车辆技术状态、承运人责任险、司机连续驾驶与休息、山区夜间道路、座位/安全带和儿童座椅等门槛。“全部车龄 5 年以内、司机均有 5 年山路经验且能基础英文、免费儿童座椅、足额营运保险、延误免费等候 60 分钟、同一司机全程、所有合理改线不加价、无隐藏费用/全包价”等改为报价和派车确认单逐项锁定,不作无条件官网承诺;企业团建、会议与研学标签已删除或改为亲友/户外/同业小团。默认英文、中文切换、桌面与移动端、4 类服务、8 类车型、5 项服务标准、图片加载、水平溢出及构建均完成检查。 +50. “新增特色酒店”栏目页:已完成第一版;按野奢地貌、民族村寨、田园山野、城市/主题四类整理客户列出的 8 家住宿候选,并补回客户原文缺失的“民族风情村寨美宿”分区标题。页面完整纳入兴义峰兮・洞穴民宿、朱砂古镇・放下云居、雷公山树蛙部落、榕江加宜梯田民宿、台江拾仓来隐、云屯・星空野奢树屋、枕宿・枕山河和兴义蘑菇野奢酒店,逐家提供位置线索、路线适配、客户卖点的安全改写和预订前核验项;新增万峰林/万峰湖、雷公山/榕江/台江、铜仁/梵净山、六盘水四组线路联动,以及经营与预订主体、真实房型与行李动线、境外客人住宿登记、消防/临崖/木构/泳池与儿童设施、活动运营与保险、价格/预付/取消/备选六项统一确认流程。客户文档没有嵌入这 8 家酒店的对应原图,因此新版主动删除旧式无关风景图卡片,采用清晰标注“客户推荐・待确认”的无图编辑式候选卡,不冒充酒店实景。峰兮可由贵州公开报道和正规预订平台支持品牌与万峰湖方向,但具体悬崖高度、房量、房型、泳池和餐饮仍按日期确认;放下云居可由铜仁公开资料支持其与朱砂古镇的关系;加宜村梯田和月亮山地理可由榕江县政府资料支持。树蛙部落具体地址及是否位于保护区、其他酒店正式中英文名和当前运营状态均继续作为待核验项。依据国家移民管理局 2026 年外国人旅馆以外住宿网上登记政策、贵州民宿高质量发展指导意见及现行贵州民宿消防标准,在页面加入住宿登记、治安、消防、食品、卫生、防灾、房屋与隐私门槛;不再把设计奖项、500 米悬崖、15 栋/12 间、270°视野、保护区位置、萤火虫、智能设施、泳池、儿童乐园或具体文化/户外活动写成统一保证。默认英文、中文切换、桌面与移动端、4 个分区、8 家候选、6 项核验、图片加载、水平溢出及生产构建均完成检查。 +51. 全站最终验收:已完成;遍历首页、栏目页、线路/体验/美食/交通/酒店详情和咨询页共 40 个内部路径,并抽查桌面与 390px 手机断点。修复移动端线路标题被主视觉遮挡、线路详情标签横向溢出、交通与酒店页重复 H1、全屏菜单酒店入口仍指向旧酒店、菜单键盘焦点/关闭,以及搜索框不产生筛选结果等问题。确认默认英文、中英文切换、咨询表单必填校验、内部图片、锚点、主导航、全屏菜单与搜索交互正常;生产构建、ESLint 和 `git diff --check` 通过。完整结果与截图见 `docs/final-audit/验收报告.md`。 +52. 下一步:进入客户验收与真实资料补齐。优先确认 8 家酒店原图及商业使用授权、每家经营/预订主体与境外客人登记方式、户外和文化体验的具名供应商/老师/向导/保险与应急资料、正式合作或资质文件、可公开的英文真实评价,以及最终价格、包含/不含、预付、取消和变更条款;客户确认后再做发布前内容定版与部署。 diff --git a/docs/首页版本管理说明.md b/docs/首页版本管理说明.md new file mode 100644 index 0000000..fd72741 --- /dev/null +++ b/docs/首页版本管理说明.md @@ -0,0 +1,24 @@ +# WanderQ 首页版本管理 + +从 2026-08-12 起,首页设计采用“只新增、不覆盖”的版本管理方式。 + +## 固定预览入口 + +| 版本 | 用途 | 本地地址 | +| --- | --- | --- | +| Classic | 客户意见实施完成后的原始首页,作为永久基准版 | `/preview/classic/` | +| V1 | 参考业务矩阵与三屏叙事完成的高级版 | `/preview/v1/` | +| Current | 当前准备继续开发或展示的版本 | `/` | + +## 规则 + +1. `Classic` 只用于回看和对比,不在其上直接开发。 +2. 新方向依次增加为 `V2`、`V3`、`V4`,旧版本不得改名或覆盖。 +3. 根地址 `/` 可以指向当前推荐方案,但所有历史版本继续保留独立入口。 +4. 每个确认版本都同时创建 Git 提交和版本标签,确保代码可以完整恢复。 +5. 给客户展示前,先内部确认要展示的版本入口,避免把实验中的页面误当成最终版。 + +## 当前代码存档 + +- 工作分支:`codex/homepage-version-lab` +- 基准与 V1 的固定标签会在首次版本存档提交后创建。 diff --git a/docs/首页结构确认表.md b/docs/首页结构确认表.md new file mode 100644 index 0000000..041c1b2 --- /dev/null +++ b/docs/首页结构确认表.md @@ -0,0 +1,105 @@ +# WanderQ 官网首页结构确认表(第一版,已由 V2 实施清单取代) + +> 本文件保留为早期讨论记录。客户已确认文档内含大量中英文内容和高清图片,且企业团建会务暂不纳入官网;后续以 `docs/客户修改意见实施清单.md` 为准。 + +更新时间:2026-08-11 +依据:当前首页代码、客户《飞书文档》32 页修改意见 +当前阶段:只确认结构、内容职责与素材需求,暂不继续做视觉和前端细节修改。 + +## 一、先给结论 + +1. 首页应继续聚焦“面向境外游客的贵州高端私家定制旅行”,不把所有线路、景点、团建、酒店和交通详情都堆进首页。 +2. 客户文档中的“团建与会务”属于另一类 B2B 用户需求,建议单独做栏目或落地页,不与境外私家旅行首页混排。 +3. 首页建议由 13 个部分组成,其中真正的主体内容模块为 9 个;当前首页的多数内容可以重组,不需要全部推倒重写。 +4. 首屏建议最终只使用 1 张具有代表性的主图,而不是继续保留 4 张质量与风格不统一的轮播图片。其余优质图片分配给下方具体板块。 +5. 第三方背书、合作标识、客人评价和服务数据必须有真实证明、原始素材与使用授权,不能仅按文案制作。 + +## 二、建议的首页结构(从上到下) + +| 序号 | 板块 | 核心作用 | 建议展示内容 | 素材要求 | 当前处理建议 | 需要业务确认 | +|---|---|---|---|---|---|---| +| 01 | 顶部导航栏 | 帮助用户快速理解网站提供什么,并进入线路、体验、酒店、交通和品牌页面 | Logo、中英文切换、6 个一级导航、菜单、搜索、开始规划 | 已有 Logo;无需新增大图 | 保留现有结构,后续只检查导航名称和链接 | 一级导航名称是否最终确定;英文是否为默认语言 | +| 02 | 首屏主视觉 | 在 5 秒内说清“谁、在哪里、提供什么服务” | 贵州私家定制定位、主标题、1 句价值说明、开始规划按钮 | 推荐 1 张横向主图;真实贵州场景;低饱和;画面干净;可用于桌面和手机裁切 | 当前方案作为结构参考,最终主图待重新选择;建议取消 4 图轮播 | 单图还是轮播;最终主标题;客户能否提供可商用主图 | +| 03 | 顶部信任背书栏 | 立即降低境外游客对资质、可靠性和当地执行能力的顾虑 | 3–4 项真实背书:正规入境接待、本地运营、协会会员、官方合作或真实媒体推荐 | 官方 Logo 矢量文件、证书扫描件、授权说明 | 新增;用简洁单色标识,不做花哨卡片 | 《国家地理》推荐是否真实且可证明;贵州文旅、户外协会、非遗工坊合作是否有授权 | +| 04 | 品牌主张与核心价值 | 解释万趣为什么不同,以及用户为什么愿意为私家定制支付溢价 | “打破旅游泡泡”“不赶场”“接触真实贵州”;精选 4–5 个核心价值 | 1 张有真实人物和贵州环境的品牌照片,或简洁文字版式 | 合并当前品牌引语和部分“为什么选择万趣”内容 | 最终品牌主张;是否以“创造改变生命的旅行体验”为核心表达 | +| 05 | 三大贵州体验方向 | 让用户快速选择自己感兴趣的旅行类型 | 户外探险、民族人文、自然风光;每类只保留标题、短说明和入口 | 3 张同一摄影风格的代表图;建议竖图或统一比例 | 保留当前三类体验,但减少文字、统一图片风格 | 三大分类是否最终确定;“极限户外”是否要改成更适合境外高端客群的称呼 | +| 06 | 三条代表性定制线路 | 把抽象体验转化为可以咨询的旅行方案 | 经典全景线、喀斯特户外探险线、均衡探索线;天数、适合人群、3 个独家亮点、查看详情 | 每条线路 1 张主图;路线地图后续放详情页,不放首页 | 保留现有 3 张线路卡片,但按客户文档补充独家亮点,暂不展示未经确认的价格 | 三条线路是否已成熟;名称、天数、价格区间、独家资源是否真实可交付 | +| 07 | 团队与在地服务能力 | 用真人和量化信息建立信任,证明不是匿名旅行产品网站 | 团队合照、2–4 位定制师/司导简介、语言、年限、服务国家数、24 小时在地支持 | 必须提供真实团队合照与职业/户外实拍;不能用图库人物 | 重做当前“为什么选择万趣”板块,把抽象优势变成人物和真实能力 | 团队成员是否愿意公开;可公开的姓名、照片、语言能力和服务数据 | +| 08 | 定制流程 | 告诉用户咨询之后会发生什么,降低联系门槛 | 01 提交需求、02 设计方案、03 确认与出发;可补充响应时间 | 不需要大图,可用极简步骤排版 | 将当前紧贴首屏的三步骤移动到团队之后、评价之前 | 是否承诺具体响应时间,例如 24 小时内回复 | +| 09 | 真实客片与英文评价 | 证明真实服务过境外游客,并展示实际旅行氛围 | 3 个精选案例;游客国籍、人数、线路、英文短评、旅行照片 | 每个案例至少 2–4 张真实照片和评价授权;需要原图 | 升级当前“贵州现场影集”,不再只是无说明的图片轮播 | 是否已有境外游客评价、照片和公开授权;是否可展示国籍与人数 | +| 10 | 万趣与其他出行方式对比 | 帮助用户理解私家定制的价值,而不是只比较价格 | 万趣私家定制 vs 普通大巴团 vs 国际 OTA 套餐;比较灵活性、语言、在地深度、价格透明、安全支持 | 不需要照片;使用克制的对比表或对比列表 | 新增,但保持简短,避免攻击性表达 | 对比维度和事实是否可验证;是否需要法务或业务审核 | +| 11 | 最终咨询行动区 | 在用户理解价值和看到证据后推动咨询 | 一句总结、开始规划按钮、预计沟通内容:日期、人数、预算、偏好 | 可使用纯色背景,或 1 张极低干扰的横图 | 新增明确的页面收口,不让首页以图片轮播突然结束 | 联系方式、表单字段、响应时效是否确定 | +| 12 | 底部合作与资质标识 | 在页面结束前再次强化可信度 | 贵州文旅合作、协会会员、非遗工坊合作、保险或接待资质等 | 官方原始 Logo、证书缩略图、授权证明 | 新增;只放确认过的真实标识 | 哪些标识可以公开;名称和 Logo 使用规范 | +| 13 | 页脚 | 提供基础公司、联系、法律和社交信息 | 公司名称、邮箱、社交媒体、服务协议、隐私政策、备案信息 | 已有 Logo 和社交图标 | 保留并补齐真实公司与法律信息;社交媒体入口移入页脚 | 公司主体、备案、地址、电话及隐私政策是否最终确定 | + +## 三、当前首页内容如何处理 + +| 当前首页板块 | 新结构中的位置 | 处理方式 | +|---|---|---| +| 顶部导航 | 01 顶部导航栏 | 保留,不作为本轮重点修改 | +| 首屏四图轮播 | 02 首屏主视觉 | 保留结构方向,建议改为单图;重新建立选图标准 | +| 三步定制流程 | 08 定制流程 | 保留内容,向下移动,不再紧贴首屏 | +| 三大体验方向 | 05 三大贵州体验方向 | 保留,精简文字并统一图片风格 | +| 三条线路卡片 | 06 三条代表性线路 | 保留,补充真实独家亮点;价格未确认前不展示具体数字 | +| 为什么选择万趣 | 04 品牌主张 + 07 团队能力 | 拆成两个板块:品牌价值负责讲理念,团队板块负责讲真人与能力 | +| 品牌引语 | 04 品牌主张 | 合并,避免单独占用一个内容重复的板块 | +| 社交媒体横条 | 13 页脚 | 不再单独占一整段,合并进入页脚或客片评价区 | +| 贵州现场影集 | 09 真实客片与英文评价 | 重做为有国籍、人数、线路和评价的真实案例 | +| 当前缺少的背书 | 03 + 12 | 页面顶部放简洁信任条,底部放完整合作与资质标识 | +| 当前缺少的对比 | 10 对比板块 | 新增一组简短、可核验的比较内容 | +| 当前缺少的收口 | 11 最终咨询行动区 | 新增明确咨询入口 | + +## 四、图片与素材清单(确认结构后再统一收集) + +| 用途 | 建议数量 | 建议比例 | 必须满足的条件 | 当前状态 | +|---|---:|---|---|---| +| 首屏主图 | 1 张,最多 2 张备选 | 桌面约 16:7;同时保留手机裁切空间 | 贵州真实场景、低饱和、主体明确、无杂乱文字、具备商用权 | 现有 4 张均需重新评估 | +| 品牌主张照片 | 1 张 | 3:2 或横向 | 真人与真实环境,有“在地旅行”感,不使用摆拍图库人物 | 缺失 | +| 三大体验图 | 3 张 | 统一 4:5 或 3:4 | 户外、人文、风光各 1 张;摄影语言统一 | 现有图片风格不统一 | +| 三条线路图 | 3 张 | 统一 3:2 | 每张能代表对应线路,而不是通用贵州风景 | 部分可用,需业务确认 | +| 团队素材 | 1 张合照 + 2–4 张个人照 | 合照 3:2;个人 4:5 | 真人、清晰、统一拍摄风格、可公开 | 缺失 | +| 客片案例 | 3 组,每组 2–4 张 | 横竖图均可,但每组需统一编排 | 真实境外游客、评价授权、可标注国籍/人数/线路 | 未确认 | +| 合作与资质 | 3–6 项 | SVG/PNG 原文件 | 真实、可核验、可公开、符合 Logo 使用规范 | 未提供原件 | + +## 五、当前最需要业务回答的问题 + +### A. 定位与受众 + +1. 首页第一目标是否确定为“境外游客贵州高端私家定制”? +2. 团建与会务是否同样是核心业务?如果是,建议独立做“企业团建/会务”页面,而不是放入当前首页主线。 +3. 官网默认展示语言是英文还是中文?从客户文档看,境外用户应当以英文为主。 + +### B. 可信度与法律风险 + +4. 是否真实获得《国家地理》推荐?可以提供链接、证书、文章或正式授权吗? +5. “贵州文旅官方合作地接”“贵州户外探险协会会员”“非遗工坊合作”分别有哪些可公开证明? +6. 现有网站使用的所有图片是否有版权或客户授权?客户文档中的参考图不能默认直接用于官网。 + +### C. 产品与内容 + +7. 三条代表线路是否已经可以稳定交付?名称、天数、价格、独家资源是否已经确认? +8. 是否有真实境外游客评价、客片和公开授权? +9. 团队成员是否愿意展示真人照片、姓名、语言能力、从业年限和服务数据? +10. “24 小时在地服务”是否可以公开承诺具体响应标准? + +## 六、进入 Figma 前的确认门槛 + +满足以下条件后,再进入高保真视觉设计: + +- 首页主受众确定。 +- 上述 13 个板块确定保留、删除或合并。 +- 三条代表线路的名称和定位确定。 +- 第三方背书真实性确定。 +- 团队、客片和合作标识能否提供确定。 +- 首屏采用单图还是轮播确定。 + +在此之前,Figma 只做黑白或低保真结构稿;确认后再制作完整首页视觉稿、字体与颜色系统、图片风格规范和组件规范。 + +## 七、建议的下一步顺序 + +1. 先由业务回答第五部分的 10 个问题。 +2. 根据答案删减或确认首页 13 个板块。 +3. 制作首页低保真结构稿。 +4. 收集并审核图片、团队、评价和背书素材。 +5. 制作完整高保真 Figma 视觉稿。 +6. 视觉稿确认后,再按板块修改前端。 diff --git a/hero-comparison-final.jpg b/hero-comparison-final.jpg new file mode 100644 index 0000000..9db136c Binary files /dev/null and b/hero-comparison-final.jpg differ diff --git a/implementation-hero-final-visible.png b/implementation-hero-final-visible.png new file mode 100644 index 0000000..c53bd8a Binary files /dev/null and b/implementation-hero-final-visible.png differ diff --git a/implementation-hero-mobile-final.png b/implementation-hero-mobile-final.png new file mode 100644 index 0000000..2495a11 Binary files /dev/null and b/implementation-hero-mobile-final.png differ diff --git a/index.html b/index.html index 4ee9759..60eaa40 100644 --- a/index.html +++ b/index.html @@ -2,7 +2,7 @@ - + 万趣旅行|贵州秘境定制旅行 diff --git a/public/client-assets/ancient-towns-qingyan-overview.jpg b/public/client-assets/ancient-towns-qingyan-overview.jpg new file mode 100644 index 0000000..71ba10d Binary files /dev/null and b/public/client-assets/ancient-towns-qingyan-overview.jpg differ diff --git a/public/client-assets/ancient-towns-stone-wall.jpg b/public/client-assets/ancient-towns-stone-wall.jpg new file mode 100644 index 0000000..157bdb0 Binary files /dev/null and b/public/client-assets/ancient-towns-stone-wall.jpg differ diff --git a/public/client-assets/ancient-towns-zhenyuan-night.jpg b/public/client-assets/ancient-towns-zhenyuan-night.jpg new file mode 100644 index 0000000..32f46f3 Binary files /dev/null and b/public/client-assets/ancient-towns-zhenyuan-night.jpg differ diff --git a/public/client-assets/ancient-towns-zhenyuan-river.jpg b/public/client-assets/ancient-towns-zhenyuan-river.jpg new file mode 100644 index 0000000..e17a2f6 Binary files /dev/null and b/public/client-assets/ancient-towns-zhenyuan-river.jpg differ diff --git a/public/client-assets/atlas-hero-waterfall.webp b/public/client-assets/atlas-hero-waterfall.webp new file mode 100644 index 0000000..bb64ec2 Binary files /dev/null and b/public/client-assets/atlas-hero-waterfall.webp differ diff --git a/public/client-assets/atlas-itinerary-map.jpg b/public/client-assets/atlas-itinerary-map.jpg new file mode 100644 index 0000000..b1ef8b0 Binary files /dev/null and b/public/client-assets/atlas-itinerary-map.jpg differ diff --git a/public/client-assets/brand-real-guizhou.webp b/public/client-assets/brand-real-guizhou.webp new file mode 100644 index 0000000..90cef70 Binary files /dev/null and b/public/client-assets/brand-real-guizhou.webp differ diff --git a/public/client-assets/camp-cloud-deck.jpg b/public/client-assets/camp-cloud-deck.jpg new file mode 100644 index 0000000..18abb7b Binary files /dev/null and b/public/client-assets/camp-cloud-deck.jpg differ diff --git a/public/client-assets/camp-mountain-portrait.jpg b/public/client-assets/camp-mountain-portrait.jpg new file mode 100644 index 0000000..1f60adf Binary files /dev/null and b/public/client-assets/camp-mountain-portrait.jpg differ diff --git a/public/client-assets/camp-view-lounge.jpg b/public/client-assets/camp-view-lounge.jpg new file mode 100644 index 0000000..6527dac Binary files /dev/null and b/public/client-assets/camp-view-lounge.jpg differ diff --git a/public/client-assets/cave-luxury-dining.jpg b/public/client-assets/cave-luxury-dining.jpg new file mode 100644 index 0000000..c323221 Binary files /dev/null and b/public/client-assets/cave-luxury-dining.jpg differ diff --git a/public/client-assets/cave-luxury-lounge.jpg b/public/client-assets/cave-luxury-lounge.jpg new file mode 100644 index 0000000..89109f0 Binary files /dev/null and b/public/client-assets/cave-luxury-lounge.jpg differ diff --git a/public/client-assets/cave-luxury-waterwalk.jpg b/public/client-assets/cave-luxury-waterwalk.jpg new file mode 100644 index 0000000..a47fd3b Binary files /dev/null and b/public/client-assets/cave-luxury-waterwalk.jpg differ diff --git a/public/client-assets/culinary-long-table-banquet.jpg b/public/client-assets/culinary-long-table-banquet.jpg new file mode 100644 index 0000000..ed23fa7 Binary files /dev/null and b/public/client-assets/culinary-long-table-banquet.jpg differ diff --git a/public/client-assets/culinary-shared-griddle.jpg b/public/client-assets/culinary-shared-griddle.jpg new file mode 100644 index 0000000..5a5b716 Binary files /dev/null and b/public/client-assets/culinary-shared-griddle.jpg differ diff --git a/public/client-assets/culinary-sour-soup-pot.jpg b/public/client-assets/culinary-sour-soup-pot.jpg new file mode 100644 index 0000000..af77734 Binary files /dev/null and b/public/client-assets/culinary-sour-soup-pot.jpg differ diff --git a/public/client-assets/culinary-sour-soup-table.jpg b/public/client-assets/culinary-sour-soup-table.jpg new file mode 100644 index 0000000..9f37cde Binary files /dev/null and b/public/client-assets/culinary-sour-soup-table.jpg differ diff --git a/public/client-assets/culture-batik-gallery.jpg b/public/client-assets/culture-batik-gallery.jpg new file mode 100644 index 0000000..c2fc504 Binary files /dev/null and b/public/client-assets/culture-batik-gallery.jpg differ diff --git a/public/client-assets/culture-batik-making.jpg b/public/client-assets/culture-batik-making.jpg new file mode 100644 index 0000000..67a7e21 Binary files /dev/null and b/public/client-assets/culture-batik-making.jpg differ diff --git a/public/client-assets/culture-batik-wax-detail.jpg b/public/client-assets/culture-batik-wax-detail.jpg new file mode 100644 index 0000000..73304d3 Binary files /dev/null and b/public/client-assets/culture-batik-wax-detail.jpg differ diff --git a/public/client-assets/culture-craft-hands.jpg b/public/client-assets/culture-craft-hands.jpg new file mode 100644 index 0000000..db52460 Binary files /dev/null and b/public/client-assets/culture-craft-hands.jpg differ diff --git a/public/client-assets/culture-craft-table.jpg b/public/client-assets/culture-craft-table.jpg new file mode 100644 index 0000000..99e8215 Binary files /dev/null and b/public/client-assets/culture-craft-table.jpg differ diff --git a/public/client-assets/culture-village-dong-view.jpg b/public/client-assets/culture-village-dong-view.jpg new file mode 100644 index 0000000..2e45f55 Binary files /dev/null and b/public/client-assets/culture-village-dong-view.jpg differ diff --git a/public/client-assets/culture-village-timber-homes.jpg b/public/client-assets/culture-village-timber-homes.jpg new file mode 100644 index 0000000..6ff3102 Binary files /dev/null and b/public/client-assets/culture-village-timber-homes.jpg differ diff --git a/public/client-assets/experience-entry-culture.webp b/public/client-assets/experience-entry-culture.webp new file mode 100644 index 0000000..449e752 Binary files /dev/null and b/public/client-assets/experience-entry-culture.webp differ diff --git a/public/client-assets/experience-entry-landscape.webp b/public/client-assets/experience-entry-landscape.webp new file mode 100644 index 0000000..14aad53 Binary files /dev/null and b/public/client-assets/experience-entry-landscape.webp differ diff --git a/public/client-assets/experience-entry-outdoor.webp b/public/client-assets/experience-entry-outdoor.webp new file mode 100644 index 0000000..b9c1b63 Binary files /dev/null and b/public/client-assets/experience-entry-outdoor.webp differ diff --git a/public/client-assets/festival-leishan-procession.jpg b/public/client-assets/festival-leishan-procession.jpg new file mode 100644 index 0000000..c8802f3 Binary files /dev/null and b/public/client-assets/festival-leishan-procession.jpg differ diff --git a/public/client-assets/festival-miao-blue-procession.jpg b/public/client-assets/festival-miao-blue-procession.jpg new file mode 100644 index 0000000..2e40868 Binary files /dev/null and b/public/client-assets/festival-miao-blue-procession.jpg differ diff --git a/public/client-assets/festival-miao-gathering.jpg b/public/client-assets/festival-miao-gathering.jpg new file mode 100644 index 0000000..ebde38a Binary files /dev/null and b/public/client-assets/festival-miao-gathering.jpg differ diff --git a/public/client-assets/festival-miao-silver-parade.jpg b/public/client-assets/festival-miao-silver-parade.jpg new file mode 100644 index 0000000..1558bc7 Binary files /dev/null and b/public/client-assets/festival-miao-silver-parade.jpg differ diff --git a/public/client-assets/fusion-indigo-concept.jpg b/public/client-assets/fusion-indigo-concept.jpg new file mode 100644 index 0000000..f70c4ab Binary files /dev/null and b/public/client-assets/fusion-indigo-concept.jpg differ diff --git a/public/client-assets/gallery-cave-dinner.webp b/public/client-assets/gallery-cave-dinner.webp new file mode 100644 index 0000000..59bf148 Binary files /dev/null and b/public/client-assets/gallery-cave-dinner.webp differ diff --git a/public/client-assets/gallery-heritage-hands.webp b/public/client-assets/gallery-heritage-hands.webp new file mode 100644 index 0000000..8be0ea8 Binary files /dev/null and b/public/client-assets/gallery-heritage-hands.webp differ diff --git a/public/client-assets/gallery-karst-adventure.webp b/public/client-assets/gallery-karst-adventure.webp new file mode 100644 index 0000000..10b468f Binary files /dev/null and b/public/client-assets/gallery-karst-adventure.webp differ diff --git a/public/client-assets/gallery-local-table.webp b/public/client-assets/gallery-local-table.webp new file mode 100644 index 0000000..5c5e9e2 Binary files /dev/null and b/public/client-assets/gallery-local-table.webp differ diff --git a/public/client-assets/gallery-mountain-pause.webp b/public/client-assets/gallery-mountain-pause.webp new file mode 100644 index 0000000..e72dd15 Binary files /dev/null and b/public/client-assets/gallery-mountain-pause.webp differ diff --git a/public/client-assets/gallery-waterfall-traveler.webp b/public/client-assets/gallery-waterfall-traveler.webp new file mode 100644 index 0000000..dbc3b14 Binary files /dev/null and b/public/client-assets/gallery-waterfall-traveler.webp differ diff --git a/public/client-assets/hero-miao-home-meal.webp b/public/client-assets/hero-miao-home-meal.webp new file mode 100644 index 0000000..12ff3e9 Binary files /dev/null and b/public/client-assets/hero-miao-home-meal.webp differ diff --git a/public/client-assets/hero-real-travelers.webp b/public/client-assets/hero-real-travelers.webp new file mode 100644 index 0000000..52cc915 Binary files /dev/null and b/public/client-assets/hero-real-travelers.webp differ diff --git a/public/client-assets/hero-river-adventure.webp b/public/client-assets/hero-river-adventure.webp new file mode 100644 index 0000000..88e3f6c Binary files /dev/null and b/public/client-assets/hero-river-adventure.webp differ diff --git a/public/client-assets/high-bridge-bungee.jpg b/public/client-assets/high-bridge-bungee.jpg new file mode 100644 index 0000000..4b1555d Binary files /dev/null and b/public/client-assets/high-bridge-bungee.jpg differ diff --git a/public/client-assets/high-bridge-cocoon.jpg b/public/client-assets/high-bridge-cocoon.jpg new file mode 100644 index 0000000..f5550ac Binary files /dev/null and b/public/client-assets/high-bridge-cocoon.jpg differ diff --git a/public/client-assets/high-bridge-record.jpg b/public/client-assets/high-bridge-record.jpg new file mode 100644 index 0000000..469f2bc Binary files /dev/null and b/public/client-assets/high-bridge-record.jpg differ diff --git a/public/client-assets/karst-hike-ridge.jpg b/public/client-assets/karst-hike-ridge.jpg new file mode 100644 index 0000000..a27f66b Binary files /dev/null and b/public/client-assets/karst-hike-ridge.jpg differ diff --git a/public/client-assets/karst-hike-river-sunset.jpg b/public/client-assets/karst-hike-river-sunset.jpg new file mode 100644 index 0000000..9965772 Binary files /dev/null and b/public/client-assets/karst-hike-river-sunset.jpg differ diff --git a/public/client-assets/karst-hike-sunset.jpg b/public/client-assets/karst-hike-sunset.jpg new file mode 100644 index 0000000..178d047 Binary files /dev/null and b/public/client-assets/karst-hike-sunset.jpg differ diff --git a/public/client-assets/karst-valley-camp.jpg b/public/client-assets/karst-valley-camp.jpg new file mode 100644 index 0000000..99448bc Binary files /dev/null and b/public/client-assets/karst-valley-camp.jpg differ diff --git a/public/client-assets/loushanguan-immersive-march-01.png b/public/client-assets/loushanguan-immersive-march-01.png new file mode 100644 index 0000000..dfef33b Binary files /dev/null and b/public/client-assets/loushanguan-immersive-march-01.png differ diff --git a/public/client-assets/qingyan-battle-client-scene.png b/public/client-assets/qingyan-battle-client-scene.png new file mode 100644 index 0000000..a982ef3 Binary files /dev/null and b/public/client-assets/qingyan-battle-client-scene.png differ diff --git a/public/client-assets/river-calm-rafting.jpg b/public/client-assets/river-calm-rafting.jpg new file mode 100644 index 0000000..3fdf62a Binary files /dev/null and b/public/client-assets/river-calm-rafting.jpg differ diff --git a/public/client-assets/river-canyon-pool.jpg b/public/client-assets/river-canyon-pool.jpg new file mode 100644 index 0000000..cae4c2e Binary files /dev/null and b/public/client-assets/river-canyon-pool.jpg differ diff --git a/public/client-assets/river-forest-rest.jpg b/public/client-assets/river-forest-rest.jpg new file mode 100644 index 0000000..31f5364 Binary files /dev/null and b/public/client-assets/river-forest-rest.jpg differ diff --git a/public/client-assets/river-karst-aerial.jpg b/public/client-assets/river-karst-aerial.jpg new file mode 100644 index 0000000..cd864e9 Binary files /dev/null and b/public/client-assets/river-karst-aerial.jpg differ diff --git a/public/client-assets/river-packraft-shore.jpg b/public/client-assets/river-packraft-shore.jpg new file mode 100644 index 0000000..7aa329b Binary files /dev/null and b/public/client-assets/river-packraft-shore.jpg differ diff --git a/public/client-assets/route-entry-balanced.webp b/public/client-assets/route-entry-balanced.webp new file mode 100644 index 0000000..bf75956 Binary files /dev/null and b/public/client-assets/route-entry-balanced.webp differ diff --git a/public/client-assets/route-entry-classic.webp b/public/client-assets/route-entry-classic.webp new file mode 100644 index 0000000..ff145c2 Binary files /dev/null and b/public/client-assets/route-entry-classic.webp differ diff --git a/public/client-assets/route-entry-outdoor.webp b/public/client-assets/route-entry-outdoor.webp new file mode 100644 index 0000000..3ce300a Binary files /dev/null and b/public/client-assets/route-entry-outdoor.webp differ diff --git a/public/client-assets/team-field-day.webp b/public/client-assets/team-field-day.webp new file mode 100644 index 0000000..9e5984a Binary files /dev/null and b/public/client-assets/team-field-day.webp differ diff --git a/public/client-assets/team-wanderq-group.webp b/public/client-assets/team-wanderq-group.webp new file mode 100644 index 0000000..46e0b71 Binary files /dev/null and b/public/client-assets/team-wanderq-group.webp differ diff --git a/public/client-assets/transport-light-van.jpg b/public/client-assets/transport-light-van.jpg new file mode 100644 index 0000000..bba280b Binary files /dev/null and b/public/client-assets/transport-light-van.jpg differ diff --git a/public/client-assets/transport-premium-mpv.jpg b/public/client-assets/transport-premium-mpv.jpg new file mode 100644 index 0000000..12f2f0f Binary files /dev/null and b/public/client-assets/transport-premium-mpv.jpg differ diff --git a/public/client-assets/transport-sedan-suv.jpg b/public/client-assets/transport-sedan-suv.jpg new file mode 100644 index 0000000..2068b08 Binary files /dev/null and b/public/client-assets/transport-sedan-suv.jpg differ diff --git a/public/client-assets/transport-van-interior.jpg b/public/client-assets/transport-van-interior.jpg new file mode 100644 index 0000000..23ea5b3 Binary files /dev/null and b/public/client-assets/transport-van-interior.jpg differ diff --git a/public/client-assets/village-balcony-life.jpg b/public/client-assets/village-balcony-life.jpg new file mode 100644 index 0000000..5da16bb Binary files /dev/null and b/public/client-assets/village-balcony-life.jpg differ diff --git a/public/client-assets/village-drumtower-roofs.jpg b/public/client-assets/village-drumtower-roofs.jpg new file mode 100644 index 0000000..45e3945 Binary files /dev/null and b/public/client-assets/village-drumtower-roofs.jpg differ diff --git a/public/client-assets/village-forest-homes.jpg b/public/client-assets/village-forest-homes.jpg new file mode 100644 index 0000000..c8eb4c4 Binary files /dev/null and b/public/client-assets/village-forest-homes.jpg differ diff --git a/public/client-assets/village-valley-fields.jpg b/public/client-assets/village-valley-fields.jpg new file mode 100644 index 0000000..7ec4049 Binary files /dev/null and b/public/client-assets/village-valley-fields.jpg differ diff --git a/public/client-assets/villages-dong-drumtowers.jpg b/public/client-assets/villages-dong-drumtowers.jpg new file mode 100644 index 0000000..d84a789 Binary files /dev/null and b/public/client-assets/villages-dong-drumtowers.jpg differ diff --git a/public/client-assets/villages-dong-valley.jpg b/public/client-assets/villages-dong-valley.jpg new file mode 100644 index 0000000..f4ce6b8 Binary files /dev/null and b/public/client-assets/villages-dong-valley.jpg differ diff --git a/public/client-assets/villages-xijiang-dusk.jpg b/public/client-assets/villages-xijiang-dusk.jpg new file mode 100644 index 0000000..c0cfd71 Binary files /dev/null and b/public/client-assets/villages-xijiang-dusk.jpg differ diff --git a/public/client-assets/villages-xijiang-panorama.jpg b/public/client-assets/villages-xijiang-panorama.jpg new file mode 100644 index 0000000..8a9d4be Binary files /dev/null and b/public/client-assets/villages-xijiang-panorama.jpg differ diff --git a/public/client-assets/waterfall-abseil-canyon.jpg b/public/client-assets/waterfall-abseil-canyon.jpg new file mode 100644 index 0000000..ea53886 Binary files /dev/null and b/public/client-assets/waterfall-abseil-canyon.jpg differ diff --git a/public/client-assets/waterfall-abseil-descent.jpg b/public/client-assets/waterfall-abseil-descent.jpg new file mode 100644 index 0000000..8eaf72b Binary files /dev/null and b/public/client-assets/waterfall-abseil-descent.jpg differ diff --git a/public/client-assets/waterfall-abseil-rope.jpg b/public/client-assets/waterfall-abseil-rope.jpg new file mode 100644 index 0000000..5024bff Binary files /dev/null and b/public/client-assets/waterfall-abseil-rope.jpg differ diff --git a/public/client-assets/waterfall-abseil-spray.jpg b/public/client-assets/waterfall-abseil-spray.jpg new file mode 100644 index 0000000..45bff58 Binary files /dev/null and b/public/client-assets/waterfall-abseil-spray.jpg differ diff --git a/public/client-assets/waterfall-chishui-danxia.jpg b/public/client-assets/waterfall-chishui-danxia.jpg new file mode 100644 index 0000000..f4fbdbb Binary files /dev/null and b/public/client-assets/waterfall-chishui-danxia.jpg differ diff --git a/public/client-assets/waterfall-dishuitan-tiered.jpg b/public/client-assets/waterfall-dishuitan-tiered.jpg new file mode 100644 index 0000000..626c9b4 Binary files /dev/null and b/public/client-assets/waterfall-dishuitan-tiered.jpg differ diff --git a/public/client-assets/waterfall-huangguoshu-curtain.jpg b/public/client-assets/waterfall-huangguoshu-curtain.jpg new file mode 100644 index 0000000..404de04 Binary files /dev/null and b/public/client-assets/waterfall-huangguoshu-curtain.jpg differ diff --git a/public/client-assets/waterfall-huangguoshu-main.jpg b/public/client-assets/waterfall-huangguoshu-main.jpg new file mode 100644 index 0000000..2fb6a63 Binary files /dev/null and b/public/client-assets/waterfall-huangguoshu-main.jpg differ diff --git a/public/client-assets/wild-coffee-cliff-cup.jpg b/public/client-assets/wild-coffee-cliff-cup.jpg new file mode 100644 index 0000000..83852d5 Binary files /dev/null and b/public/client-assets/wild-coffee-cliff-cup.jpg differ diff --git a/public/client-assets/wild-coffee-forest-cafe.jpg b/public/client-assets/wild-coffee-forest-cafe.jpg new file mode 100644 index 0000000..d8ed8c7 Binary files /dev/null and b/public/client-assets/wild-coffee-forest-cafe.jpg differ diff --git a/public/client-assets/wild-coffee-rain-deck.jpg b/public/client-assets/wild-coffee-rain-deck.jpg new file mode 100644 index 0000000..6560b65 Binary files /dev/null and b/public/client-assets/wild-coffee-rain-deck.jpg differ diff --git a/public/client-assets/wild-coffee-terrace-view.jpg b/public/client-assets/wild-coffee-terrace-view.jpg new file mode 100644 index 0000000..8bfca52 Binary files /dev/null and b/public/client-assets/wild-coffee-terrace-view.jpg differ diff --git a/public/favicon.png b/public/favicon.png new file mode 100644 index 0000000..df54c14 Binary files /dev/null and b/public/favicon.png differ diff --git a/public/guizhou-assets/destination-fanjing.webp b/public/guizhou-assets/destination-fanjing.webp new file mode 100644 index 0000000..c6ca108 Binary files /dev/null and b/public/guizhou-assets/destination-fanjing.webp differ diff --git a/public/guizhou-assets/destination-huangguoshu.webp b/public/guizhou-assets/destination-huangguoshu.webp new file mode 100644 index 0000000..27fb0df Binary files /dev/null and b/public/guizhou-assets/destination-huangguoshu.webp differ diff --git a/public/guizhou-assets/destination-liboxqk.webp b/public/guizhou-assets/destination-liboxqk.webp new file mode 100644 index 0000000..dfcdbb8 Binary files /dev/null and b/public/guizhou-assets/destination-liboxqk.webp differ diff --git a/public/guizhou-assets/destination-wanfenglin.webp b/public/guizhou-assets/destination-wanfenglin.webp new file mode 100644 index 0000000..22021c6 Binary files /dev/null and b/public/guizhou-assets/destination-wanfenglin.webp differ diff --git a/public/guizhou-assets/destination-xijiang.webp b/public/guizhou-assets/destination-xijiang.webp new file mode 100644 index 0000000..675c77e Binary files /dev/null and b/public/guizhou-assets/destination-xijiang.webp differ diff --git a/public/guizhou-assets/destination-zhenyuan.webp b/public/guizhou-assets/destination-zhenyuan.webp new file mode 100644 index 0000000..11e1b22 Binary files /dev/null and b/public/guizhou-assets/destination-zhenyuan.webp differ diff --git a/public/guizhou-assets/experience-cave.webp b/public/guizhou-assets/experience-cave.webp new file mode 100644 index 0000000..c841fc0 Binary files /dev/null and b/public/guizhou-assets/experience-cave.webp differ diff --git a/public/guizhou-assets/experience-coffee-village.webp b/public/guizhou-assets/experience-coffee-village.webp new file mode 100644 index 0000000..e414144 Binary files /dev/null and b/public/guizhou-assets/experience-coffee-village.webp differ diff --git a/public/guizhou-assets/experience-miao-craft.webp b/public/guizhou-assets/experience-miao-craft.webp new file mode 100644 index 0000000..46a1f9c Binary files /dev/null and b/public/guizhou-assets/experience-miao-craft.webp differ diff --git a/public/guizhou-assets/experience-rafting.webp b/public/guizhou-assets/experience-rafting.webp new file mode 100644 index 0000000..a971601 Binary files /dev/null and b/public/guizhou-assets/experience-rafting.webp differ diff --git a/public/guizhou-assets/faq-outdoor.webp b/public/guizhou-assets/faq-outdoor.webp new file mode 100644 index 0000000..e6b40bf Binary files /dev/null and b/public/guizhou-assets/faq-outdoor.webp differ diff --git a/public/guizhou-assets/footer-cta.webp b/public/guizhou-assets/footer-cta.webp new file mode 100644 index 0000000..ffb7ba6 Binary files /dev/null and b/public/guizhou-assets/footer-cta.webp differ diff --git a/public/guizhou-assets/hero-fanjing.webp b/public/guizhou-assets/hero-fanjing.webp new file mode 100644 index 0000000..a38cf93 Binary files /dev/null and b/public/guizhou-assets/hero-fanjing.webp differ diff --git a/public/guizhou-assets/hero-huangguoshu.webp b/public/guizhou-assets/hero-huangguoshu.webp new file mode 100644 index 0000000..355b43b Binary files /dev/null and b/public/guizhou-assets/hero-huangguoshu.webp differ diff --git a/public/guizhou-assets/hero-wanfenglin.webp b/public/guizhou-assets/hero-wanfenglin.webp new file mode 100644 index 0000000..6608258 Binary files /dev/null and b/public/guizhou-assets/hero-wanfenglin.webp differ diff --git a/public/guizhou-assets/hero-xijiang.webp b/public/guizhou-assets/hero-xijiang.webp new file mode 100644 index 0000000..5c8b5d0 Binary files /dev/null and b/public/guizhou-assets/hero-xijiang.webp differ diff --git a/public/guizhou-assets/hotel-bolian-spa.webp b/public/guizhou-assets/hotel-bolian-spa.webp new file mode 100644 index 0000000..0a3810d Binary files /dev/null and b/public/guizhou-assets/hotel-bolian-spa.webp differ diff --git a/public/guizhou-assets/hotel-reference.webp b/public/guizhou-assets/hotel-reference.webp new file mode 100644 index 0000000..50fde51 Binary files /dev/null and b/public/guizhou-assets/hotel-reference.webp differ diff --git a/public/guizhou-assets/menu-culture.webp b/public/guizhou-assets/menu-culture.webp new file mode 100644 index 0000000..ab702e4 Binary files /dev/null and b/public/guizhou-assets/menu-culture.webp differ diff --git a/public/guizhou-assets/menu-food.webp b/public/guizhou-assets/menu-food.webp new file mode 100644 index 0000000..0db0fa9 Binary files /dev/null and b/public/guizhou-assets/menu-food.webp differ diff --git a/public/guizhou-assets/menu-hotels.webp b/public/guizhou-assets/menu-hotels.webp new file mode 100644 index 0000000..dba71fa Binary files /dev/null and b/public/guizhou-assets/menu-hotels.webp differ diff --git a/public/guizhou-assets/menu-landscape.webp b/public/guizhou-assets/menu-landscape.webp new file mode 100644 index 0000000..3886dc1 Binary files /dev/null and b/public/guizhou-assets/menu-landscape.webp differ diff --git a/public/guizhou-assets/menu-outdoor.webp b/public/guizhou-assets/menu-outdoor.webp new file mode 100644 index 0000000..9511379 Binary files /dev/null and b/public/guizhou-assets/menu-outdoor.webp differ diff --git a/public/guizhou-assets/menu-transport.webp b/public/guizhou-assets/menu-transport.webp new file mode 100644 index 0000000..2a5a038 Binary files /dev/null and b/public/guizhou-assets/menu-transport.webp differ diff --git a/public/guizhou-assets/quote-guests.webp b/public/guizhou-assets/quote-guests.webp new file mode 100644 index 0000000..bed2237 Binary files /dev/null and b/public/guizhou-assets/quote-guests.webp differ diff --git a/public/guizhou-assets/route-classic.webp b/public/guizhou-assets/route-classic.webp new file mode 100644 index 0000000..d27a00c Binary files /dev/null and b/public/guizhou-assets/route-classic.webp differ diff --git a/public/guizhou-assets/route-mixed.webp b/public/guizhou-assets/route-mixed.webp new file mode 100644 index 0000000..c335aab Binary files /dev/null and b/public/guizhou-assets/route-mixed.webp differ diff --git a/public/guizhou-assets/route-outdoor.webp b/public/guizhou-assets/route-outdoor.webp new file mode 100644 index 0000000..b87bae8 Binary files /dev/null and b/public/guizhou-assets/route-outdoor.webp differ diff --git a/public/wanderq-logo.png b/public/wanderq-logo.png new file mode 100644 index 0000000..9899da3 Binary files /dev/null and b/public/wanderq-logo.png differ diff --git a/scripts/build_client_acceptance_doc.py b/scripts/build_client_acceptance_doc.py new file mode 100644 index 0000000..eccc5cf --- /dev/null +++ b/scripts/build_client_acceptance_doc.py @@ -0,0 +1,423 @@ +from pathlib import Path + +from docx import Document +from docx.enum.table import WD_CELL_VERTICAL_ALIGNMENT +from docx.enum.text import WD_ALIGN_PARAGRAPH +from docx.oxml import OxmlElement +from docx.oxml.ns import qn +from docx.shared import Inches, Pt, RGBColor + + +OUT = Path(__file__).resolve().parents[1] / "docs" / "WanderQ官网客户验收与资料确认清单.docx" + +GREEN = "315A46" +DEEP_GREEN = "18382A" +LIGHT_GREEN = "EAF2ED" +PALE_GREEN = "F5F8F6" +GOLD = "A77A3F" +INK = "26332C" +MUTED = "68736C" +LINE = "CCD8D0" +WHITE = "FFFFFF" + + +def set_cell_shading(cell, fill): + tc_pr = cell._tc.get_or_add_tcPr() + shd = tc_pr.find(qn("w:shd")) + if shd is None: + shd = OxmlElement("w:shd") + tc_pr.append(shd) + shd.set(qn("w:fill"), fill) + + +def set_cell_margins(cell, top=100, start=120, bottom=100, end=120): + tc = cell._tc + tc_pr = tc.get_or_add_tcPr() + tc_mar = tc_pr.first_child_found_in("w:tcMar") + if tc_mar is None: + tc_mar = OxmlElement("w:tcMar") + tc_pr.append(tc_mar) + for margin, value in (("top", top), ("start", start), ("bottom", bottom), ("end", end)): + node = tc_mar.find(qn(f"w:{margin}")) + if node is None: + node = OxmlElement(f"w:{margin}") + tc_mar.append(node) + node.set(qn("w:w"), str(value)) + node.set(qn("w:type"), "dxa") + + +def set_cell_width(cell, width_dxa): + tc_pr = cell._tc.get_or_add_tcPr() + tc_w = tc_pr.find(qn("w:tcW")) + if tc_w is None: + tc_w = OxmlElement("w:tcW") + tc_pr.append(tc_w) + tc_w.set(qn("w:w"), str(width_dxa)) + tc_w.set(qn("w:type"), "dxa") + + +def set_table_geometry(table, widths, indent=120): + table.autofit = False + tbl_pr = table._tbl.tblPr + tbl_w = tbl_pr.find(qn("w:tblW")) + if tbl_w is None: + tbl_w = OxmlElement("w:tblW") + tbl_pr.append(tbl_w) + tbl_w.set(qn("w:w"), str(sum(widths))) + tbl_w.set(qn("w:type"), "dxa") + tbl_ind = tbl_pr.find(qn("w:tblInd")) + if tbl_ind is None: + tbl_ind = OxmlElement("w:tblInd") + tbl_pr.append(tbl_ind) + tbl_ind.set(qn("w:w"), str(indent)) + tbl_ind.set(qn("w:type"), "dxa") + grid = table._tbl.tblGrid + for child in list(grid): + grid.remove(child) + for width in widths: + col = OxmlElement("w:gridCol") + col.set(qn("w:w"), str(width)) + grid.append(col) + for row in table.rows: + for index, cell in enumerate(row.cells): + set_cell_width(cell, widths[index]) + set_cell_margins(cell) + cell.vertical_alignment = WD_CELL_VERTICAL_ALIGNMENT.CENTER + + +def set_repeat_table_header(row): + tr_pr = row._tr.get_or_add_trPr() + tbl_header = OxmlElement("w:tblHeader") + tbl_header.set(qn("w:val"), "true") + tr_pr.append(tbl_header) + + +def set_cant_split(row): + tr_pr = row._tr.get_or_add_trPr() + cant_split = OxmlElement("w:cantSplit") + cant_split.set(qn("w:val"), "true") + tr_pr.append(cant_split) + + +def set_run(run, size=11, bold=False, color=INK, font="Noto Sans CJK SC"): + run.font.name = font + run._element.get_or_add_rPr().rFonts.set(qn("w:ascii"), font) + run._element.get_or_add_rPr().rFonts.set(qn("w:hAnsi"), font) + run._element.get_or_add_rPr().rFonts.set(qn("w:eastAsia"), font) + run.font.size = Pt(size) + run.bold = bold + run.font.color.rgb = RGBColor.from_string(color) + + +def add_text(paragraph, text, size=11, bold=False, color=INK): + run = paragraph.add_run(text) + set_run(run, size=size, bold=bold, color=color) + return run + + +def add_header_footer(section): + header = section.header + p = header.paragraphs[0] + p.alignment = WD_ALIGN_PARAGRAPH.RIGHT + p.paragraph_format.space_after = Pt(0) + add_text(p, "WANDERQ · CLIENT ACCEPTANCE", size=8.5, bold=True, color=MUTED) + + footer = section.footer + p = footer.paragraphs[0] + p.alignment = WD_ALIGN_PARAGRAPH.CENTER + p.paragraph_format.space_before = Pt(0) + add_text(p, "WanderQ 官网客户验收与资料确认清单 · 2026-08-12", size=8.5, color=MUTED) + + +def add_title_block(doc): + p = doc.add_paragraph() + p.paragraph_format.space_before = Pt(10) + p.paragraph_format.space_after = Pt(2) + add_text(p, "WANDERQ / 万趣旅行", size=10.5, bold=True, color=GOLD) + + p = doc.add_paragraph() + p.paragraph_format.space_before = Pt(0) + p.paragraph_format.space_after = Pt(6) + add_text(p, "官网客户验收与资料确认清单", size=27, bold=True, color=DEEP_GREEN) + + p = doc.add_paragraph() + p.paragraph_format.space_after = Pt(16) + add_text(p, "用于整站内容确认、真实资料补齐与正式发布前定版", size=12.5, color=MUTED) + + table = doc.add_table(rows=2, cols=2) + set_table_geometry(table, [4680, 4680], indent=120) + info = [ + ("当前阶段", "已完成第一版开发与全站技术验收"), + ("确认方式", "可在本文勾选、批注,或按编号逐项回复"), + ("本轮范围", "贵州私家定制旅行官网(不含企业团建会务)"), + ("建议顺序", "先确认整站方向,再分批补齐酒店与供应资料"), + ] + for index, (label, value) in enumerate(info): + cell = table.cell(index // 2, index % 2) + set_cell_shading(cell, LIGHT_GREEN if index < 2 else PALE_GREEN) + p = cell.paragraphs[0] + p.paragraph_format.space_after = Pt(1) + add_text(p, label + "\n", size=8.5, bold=True, color=GREEN) + add_text(p, value, size=10.5, color=INK) + doc.add_paragraph() + + +def add_heading(doc, number, title, intro=None): + p = doc.add_paragraph(style="Heading 1") + p.paragraph_format.keep_with_next = True + add_text(p, f"{number} {title}", size=16, bold=True, color=DEEP_GREEN) + if intro: + p = doc.add_paragraph() + p.paragraph_format.space_after = Pt(8) + add_text(p, intro, size=10.5, color=MUTED) + + +def add_subheading(doc, title): + p = doc.add_paragraph(style="Heading 2") + p.paragraph_format.keep_with_next = True + add_text(p, title, size=12.5, bold=True, color=GREEN) + + +def add_checkbox_line(doc, text, indent=0): + p = doc.add_paragraph() + p.paragraph_format.left_indent = Inches(indent) + p.paragraph_format.space_after = Pt(4) + p.paragraph_format.keep_together = True + add_text(p, "☐ ", size=11.5, color=GREEN) + add_text(p, text, size=10.5) + + +def add_response_box(doc, prompt="客户意见 / 补充说明:", lines=2): + table = doc.add_table(rows=1, cols=1) + set_table_geometry(table, [9360], indent=120) + cell = table.cell(0, 0) + set_cell_shading(cell, PALE_GREEN) + set_cell_margins(cell, top=120, start=160, bottom=120, end=160) + p = cell.paragraphs[0] + p.paragraph_format.space_after = Pt(3) + add_text(p, prompt, size=9, bold=True, color=GREEN) + for _ in range(lines): + p = cell.add_paragraph() + p.paragraph_format.space_after = Pt(3) + add_text(p, "________________________________________________________________________________", size=9, color=LINE) + doc.add_paragraph().paragraph_format.space_after = Pt(2) + + +def add_status_table(doc): + rows = [ + ("整站视觉", "浅色、低饱和、欧美极简与编辑式排版", "请确认方向"), + ("首屏主视觉", "保留自动轮播,并支持手动切换与暂停", "已按前期确认执行"), + ("默认语言", "首次打开默认英文,可切换中文", "已按前期确认执行"), + ("业务范围", "暂不加入企业团建会务", "已按前期确认执行"), + ("第三方背书", "无正式文件前,不展示政府、媒体、协会等暗示性 Logo", "需资料后再上线"), + ("英文评价", "无可核验原始评价和授权前,不编造评价", "需资料后再上线"), + ] + table = doc.add_table(rows=1, cols=3) + set_table_geometry(table, [1900, 5060, 2400], indent=120) + for i, text in enumerate(("项目", "当前处理", "本轮确认")): + cell = table.rows[0].cells[i] + set_cell_shading(cell, GREEN) + p = cell.paragraphs[0] + p.alignment = WD_ALIGN_PARAGRAPH.CENTER + add_text(p, text, size=9.5, bold=True, color=WHITE) + set_repeat_table_header(table.rows[0]) + for row_index, row_data in enumerate(rows): + row = table.add_row() + set_cant_split(row) + cells = row.cells + for i, text in enumerate(row_data): + set_cell_shading(cells[i], WHITE if row_index % 2 == 0 else PALE_GREEN) + p = cells[i].paragraphs[0] + p.alignment = WD_ALIGN_PARAGRAPH.LEFT if i == 1 else WD_ALIGN_PARAGRAPH.CENTER + add_text(p, text, size=9.5, bold=(i == 0), color=INK) + set_table_geometry(table, [1900, 5060, 2400], indent=120) + + +def add_hotel_table(doc): + hotels = [ + "兴义峰兮・洞穴民宿", + "朱砂古镇・放下云居", + "雷公山树蛙部落", + "榕江加宜梯田民宿", + "台江拾仓来隐", + "云屯・星空野奢树屋", + "枕宿・枕山河", + "兴义蘑菇野奢酒店", + ] + table = doc.add_table(rows=1, cols=4) + widths = [700, 2800, 3960, 1900] + set_table_geometry(table, widths, indent=120) + headers = ("序号", "酒店候选", "请提供 / 确认", "状态") + for i, text in enumerate(headers): + cell = table.rows[0].cells[i] + set_cell_shading(cell, GREEN) + p = cell.paragraphs[0] + p.alignment = WD_ALIGN_PARAGRAPH.CENTER + add_text(p, text, size=9.2, bold=True, color=WHITE) + set_repeat_table_header(table.rows[0]) + detail = "正式中英文名、准确地址/地图点位、经营或预订主体、可接待境外客人方式、4–6 张原图及授权、当前房型与价格渠道" + for index, hotel in enumerate(hotels, 1): + row = table.add_row() + set_cant_split(row) + cells = row.cells + values = (f"{index:02d}", hotel, detail, "☐ 待提供\n☐ 已确认") + for i, text in enumerate(values): + set_cell_shading(cells[i], WHITE if index % 2 else PALE_GREEN) + p = cells[i].paragraphs[0] + p.alignment = WD_ALIGN_PARAGRAPH.CENTER if i in (0, 3) else WD_ALIGN_PARAGRAPH.LEFT + add_text(p, text, size=8.8, bold=(i == 1), color=INK) + set_table_geometry(table, widths, indent=120) + + +def add_material_block(doc, title, items): + table = doc.add_table(rows=1, cols=1) + set_table_geometry(table, [9360], indent=120) + cell = table.cell(0, 0) + set_cell_shading(cell, PALE_GREEN) + set_cell_margins(cell, top=130, start=170, bottom=130, end=170) + p = cell.paragraphs[0] + p.paragraph_format.space_after = Pt(5) + add_text(p, title, size=11, bold=True, color=DEEP_GREEN) + for item in items: + p = cell.add_paragraph() + p.paragraph_format.space_after = Pt(3) + add_text(p, "☐ ", size=10.5, color=GREEN) + add_text(p, item, size=9.7) + doc.add_paragraph().paragraph_format.space_after = Pt(2) + + +def build(): + doc = Document() + section = doc.sections[0] + section.page_width = Inches(8.5) + section.page_height = Inches(11) + section.top_margin = Inches(0.78) + section.bottom_margin = Inches(0.75) + section.left_margin = Inches(0.9) + section.right_margin = Inches(0.9) + section.header_distance = Inches(0.35) + section.footer_distance = Inches(0.35) + add_header_footer(section) + + normal = doc.styles["Normal"] + normal.font.name = "Noto Sans CJK SC" + normal._element.rPr.rFonts.set(qn("w:ascii"), "Noto Sans CJK SC") + normal._element.rPr.rFonts.set(qn("w:hAnsi"), "Noto Sans CJK SC") + normal._element.rPr.rFonts.set(qn("w:eastAsia"), "Noto Sans CJK SC") + normal.font.size = Pt(10.5) + normal.font.color.rgb = RGBColor.from_string(INK) + normal.paragraph_format.space_after = Pt(6) + normal.paragraph_format.line_spacing = 1.25 + + for name, size, before, after in (("Heading 1", 16, 16, 8), ("Heading 2", 12.5, 12, 6)): + style = doc.styles[name] + style.font.name = "Noto Sans CJK SC" + style._element.rPr.rFonts.set(qn("w:ascii"), "Noto Sans CJK SC") + style._element.rPr.rFonts.set(qn("w:hAnsi"), "Noto Sans CJK SC") + style._element.rPr.rFonts.set(qn("w:eastAsia"), "Noto Sans CJK SC") + style.font.size = Pt(size) + style.font.bold = True + style.font.color.rgb = RGBColor.from_string(DEEP_GREEN if name == "Heading 1" else GREEN) + style.paragraph_format.space_before = Pt(before) + style.paragraph_format.space_after = Pt(after) + + add_title_block(doc) + + add_heading(doc, "01", "客户如何使用本清单", "请先完成整站方向确认;具体酒店、供应商和交易资料可以分批补充。任何暂时无法确认的项目,官网都会继续使用“待确认”或安全边界表达,不会替客户作无依据承诺。") + add_checkbox_line(doc, "整站方向无重大问题,可继续进入真实资料补齐和发布前定版。") + add_checkbox_line(doc, "整体方向认可,但需要按本文编号进行局部修改。") + add_checkbox_line(doc, "需要重新讨论某个栏目结构;请注明栏目和原因。") + add_response_box(doc, "请填写本轮总意见:", 3) + + add_heading(doc, "02", "整站方向确认", "以下项目是此前沟通结果与当前官网的执行方式,请客户确认是否继续沿用。") + add_status_table(doc) + add_subheading(doc, "请客户确认") + add_checkbox_line(doc, "认可当前整站视觉方向,不需要大规模重做。") + add_checkbox_line(doc, "认可当前首页到详情页的栏目结构和内容顺序。") + add_checkbox_line(doc, "认可英文为默认语言,中文作为切换语言。") + add_checkbox_line(doc, "认可暂不加入企业团建会务。") + add_checkbox_line(doc, "认可未提供证明的卖点、资质和背书暂不上线。") + add_response_box(doc, "如有页面级修改,请写“页面名称 + 位置 + 修改内容”:", 3) + + add_heading(doc, "03", "8 家特色酒店资料确认", "官网已经按照客户提出的 8 家住宿候选完成栏目结构,但目前不使用无关风景图冒充酒店实景。请按酒店逐家提供下列资料。") + add_hotel_table(doc) + add_subheading(doc, "每家酒店图片最低要求") + add_checkbox_line(doc, "外观或环境 1–2 张、代表房型 2–3 张、公共空间或餐饮 1–2 张,尽量提供原始高清图。") + add_checkbox_line(doc, "明确图片对应的酒店、房型、拍摄时间和是否允许官网商业使用。") + add_checkbox_line(doc, "如图片来自酒店官方或第三方平台,请提供授权依据,不能仅提供网络截图。") + add_response_box(doc, "酒店资料负责人 / 预计提供日期:", 2) + + add_heading(doc, "04", "体验供应与安全资料", "客户文档中的体验方向已完整进入网站。正式对外销售前,需要把“概念内容”落实到具名运营方、具名人员和可执行条件。") + add_material_block(doc, "户外体验", [ + "洞穴、瀑降、溯溪、漂流、徒步/骑行、高桥挑战等项目的具名运营方与联系人。", + "领队、向导、教练或救援人员的相关资质、经验与可公开介绍。", + "适用年龄、体能/健康限制、装备清单、天气/水位取消条件与替代方案。", + "保险责任、应急通信、撤离路线、最近医疗资源和事故处理流程。", + "真实产品时长、人数上下限、当前价格、可约日期和取消规则。", + ]) + add_material_block(doc, "文化与村寨体验", [ + "苗绣/蜡染、侗族技艺、水族马尾绣、布依技艺等具名老师、工坊和地点。", + "村寨拜访、家庭接待、住宿、家宴、节庆参与的主人/社区/运营主体同意。", + "课程可完成内容、材料与工具、儿童参与边界、拍摄同意和作品带走/后寄方式。", + "英文支持由谁提供,以及费用如何分配给老师、主人或社区。", + ]) + add_material_block(doc, "特别场景与历史演绎", [ + "洞穴咖啡/晚宴、山野咖啡、露营的场地许可、餐饮、消防、电力、天气与撤离资料。", + "《战青岩》《娄山关大捷》等现有产品的运营主体、当前场次、票价、英文接待与包团条件。", + "客户提出但尚未成为现有产品的二期共创内容,需单独确认开发主体、预算和周期。", + ]) + add_response_box(doc, "供应商与安全资料负责人 / 预计提供日期:", 2) + + add_heading(doc, "05", "合作背书与真实评价", "这一部分能够显著增强官网信任感,但必须保证来源真实、关联准确并获得公开使用许可。") + add_subheading(doc, "合作、媒体与资质") + add_checkbox_line(doc, "合作机构或政府单位:正式名称、合作内容、有效期、证明文件及 Logo 使用授权。") + add_checkbox_line(doc, "媒体报道或推荐:原始报道链接/文件、准确标题和允许引用的内容。") + add_checkbox_line(doc, "协会会员、行业认证或获奖:证书、有效期、认证主体和允许展示的标识。") + add_subheading(doc, "真实英文客户评价") + add_checkbox_line(doc, "英文原评(不由开发侧翻译成“原评”)、客户姓名或允许公开的署名方式。") + add_checkbox_line(doc, "客户照片、国籍/地区、人数、实际参加线路或体验、出行时间。") + add_checkbox_line(doc, "照片和评价公开用于官网及营销材料的授权。") + add_response_box(doc, "如暂时没有完整资料,可注明“本次不上线”:", 2) + + add_heading(doc, "06", "价格、预订与法律信息", "官网进入正式发布和接单阶段前,请确认以下交易信息,避免页面卖点与实际报价、履约条件不一致。") + for item in [ + "各线路、体验、酒店和用车是展示参考价、起价、询价制,还是暂不公开价格。", + "报价包含与不包含:门票、住宿、餐饮、车辆、司导、装备、保险、税费和服务费。", + "预订金比例、尾款时间、支付方式、汇率或跨境支付费用。", + "取消、退款、日期变更、人数变化、天气取消和供应商取消条款。", + "公司/经营主体正式名称、注册地址、联系人、客服邮箱及适用的隐私与服务条款。", + "客户咨询信息由谁接收、如何跟进、保存多久,以及是否需要单独的隐私同意。", + ]: + add_checkbox_line(doc, item) + add_response_box(doc, "价格与合同资料负责人 / 预计提供日期:", 2) + + add_heading(doc, "07", "回复优先级与最终确认", "为了不影响当前设计确认,资料可以按以下顺序分批提供。") + priorities = [ + ("P0 / 本轮确认", "整站视觉、结构、默认英文、业务范围,以及需要立即修改的页面。"), + ("P1 / 发布前必须", "酒店原图与授权、具名供应商与安全资料、价格/取消条款、经营与法律信息。"), + ("P2 / 可后补增强", "合作背书、媒体材料、真实英文评价和新增内容。"), + ] + table = doc.add_table(rows=1, cols=2) + set_table_geometry(table, [2200, 7160], indent=120) + for index, (level, detail) in enumerate(priorities): + row = table.rows[0] if index == 0 else table.add_row() + set_cell_shading(row.cells[0], GREEN if index == 0 else LIGHT_GREEN) + set_cell_shading(row.cells[1], PALE_GREEN) + p = row.cells[0].paragraphs[0] + add_text(p, level, size=10, bold=True, color=WHITE if index == 0 else GREEN) + p = row.cells[1].paragraphs[0] + add_text(p, detail, size=10) + set_table_geometry(table, [2200, 7160], indent=120) + doc.add_paragraph() + add_checkbox_line(doc, "确认当前官网可作为客户整站验收版本继续推进。") + add_checkbox_line(doc, "确认按本清单分批补充资料;未提供或未核验内容不作为官网承诺。") + add_checkbox_line(doc, "确认客户提供的文字、图片、Logo、评价与证明材料拥有相应公开和商业使用权限。") + add_response_box(doc, "客户代表 / 日期 / 其他说明:", 4) + + OUT.parent.mkdir(parents=True, exist_ok=True) + doc.save(OUT) + print(OUT) + + +if __name__ == "__main__": + build() diff --git a/site-audit.md b/site-audit.md new file mode 100644 index 0000000..f7cf392 --- /dev/null +++ b/site-audit.md @@ -0,0 +1,86 @@ +# WanderQ site-wide UX, visual, and accessibility audit + +Date: 2026-08-22 +Surface: local WanderQ website at `http://127.0.0.1:5175/` +Goal: help an international visitor understand the three Guizhou experience directions, trust the local team, and reach a workable inquiry path. + +## Audit scope + +- Combined UX, visual-consistency, responsive, and screenshot-based accessibility review. +- Desktop viewport: `1512 × 1000` CSS px. +- Mobile viewport: `390 × 844` CSS px. +- Routes scanned at both breakpoints: homepage, Guizhou Experiences, two experience details, one landscape detail, Hotels, Food, About, Service Cases, FAQ, Trade Portal, and Contact. +- Browser-rendered screenshots and DOM/interaction checks were captured in the current audit run. + +## 1. Homepage entry — healthy + +The desktop hero has a clear destination promise, strong photography, and one dominant journey-planning action. The mobile hierarchy reflows cleanly without losing the promise or CTA. + +![Homepage desktop](/tmp/wanqu-site-audit-2026-08-22/01-home-desktop.png) + +![Homepage mobile](/tmp/wanqu-site-audit-2026-08-22/05-home-mobile.png) + +## 2. Guizhou Experiences selection — healthy + +The three-category model is easy to scan and remains consistent across desktop and mobile. All cards remain inside the viewport and point to the expected category or detail content. + +![Guizhou Experiences desktop](/tmp/wanqu-site-audit-2026-08-22/02-experiences-desktop.png) + +![Guizhou Experiences mobile](/tmp/wanqu-site-audit-2026-08-22/08-experiences-mobile.png) + +## 3. Representative experience detail — healthy after navigation cleanup + +The detail page has a clear hero, readable activity positioning, and useful in-page navigation. Route-pairing cards previously used removed `/safaris/` destinations; they now return visitors to the correct merged experience category. English culture-detail breadcrumbs no longer contain an untranslated Chinese category label. + +![Experience detail desktop](/tmp/wanqu-site-audit-2026-08-22/03-experience-detail-desktop.png) + +## 4. Menu and search — healthy after accessibility cleanup + +The full menu exposes the current information architecture without the removed Transport or standalone Routes categories. Search has a clear empty state. Menu and search triggers now expose dialog state, dialogs have programmatic names, keyboard focus loops inside each dialog, Escape closes them, and focus returns to the opening control. + +![Mobile full menu](/tmp/wanqu-site-audit-2026-08-22/06-menu-mobile.png) + +![Mobile search empty state](/tmp/wanqu-site-audit-2026-08-22/10-search-empty-mobile.png) + +## 5. Contact page — healthy after form polish + +The inquiry page explains the three-step process and keeps the form visible against the photographic background. Field names are now present for form semantics, the travelers example no longer truncates on desktop, native required-field validation focuses the first invalid field, and mobile reflow has no horizontal overflow. + +![Contact desktop](/tmp/wanqu-site-audit-2026-08-22/04-contact-desktop.png) + +![Contact mobile](/tmp/wanqu-site-audit-2026-08-22/07-contact-mobile.png) + +## 6. No-backend submission recovery — workable fallback + +The project still has no inquiry backend, so direct online delivery cannot be guaranteed. Instead of leaving visitors at a generic failure message, the error state now offers a prefilled email containing all form values and the destination address `travel@wanderq.com`. + +![Contact email fallback mobile](/tmp/wanqu-site-audit-2026-08-22/09-contact-fallback-mobile.png) + +## 7. Cross-route integrity scan — healthy + +All 12 representative routes were checked at desktop and mobile widths. No broken images or horizontal overflow were found. The production build and lint checks pass. + +## Strengths + +- The homepage now forms a coherent five-part funnel: promise, three experience choices, planning method, local-team trust, and inquiry. +- The green/cream/forest palette, square corners, editorial display type, and supporting sans type are consistent across the main journey. +- Navigation terminology matches the simplified information architecture. +- Real project imagery is used throughout the primary customer journey. +- English is the default, and checked Chinese states preserve the same structure and meaning. + +## Issues fixed during this audit + +1. **P1 — inquiry dead end without a backend:** added a prefilled email recovery path with the submitted details. +2. **P2 — removed route links still exposed in detail pages:** mapped legacy route cards to the three merged experience anchors. +3. **P2 — untranslated English breadcrumbs:** replaced the hard-coded culture category with bilingual content. +4. **P2 — truncated traveler guidance:** shortened the placeholder to a scannable example. +5. **P2 — modal state and focus behavior:** added dialog relationships, expanded state, focus containment, Escape close, and focus restoration. + +## Accessibility evidence and limits + +- Confirmed from rendered DOM and interactions: labeled form controls, native required validation, dialog naming, dialog trigger relationships, focus containment, Escape close, focus restoration, responsive reflow, and no hidden horizontal content at tested widths. +- Screenshots and DOM checks cannot establish full WCAG compliance, screen-reader announcement quality across platforms, color contrast ratios in every state, or performance on all devices. Those require dedicated automated and assistive-technology testing. + +## Remaining product dependency + +The email fallback is honest and usable for a frontend-only site, but a seamless successful submission still requires a real backend or third-party form delivery service. diff --git a/spacing-refinement-audit.md b/spacing-refinement-audit.md new file mode 100644 index 0000000..0704327 --- /dev/null +++ b/spacing-refinement-audit.md @@ -0,0 +1,50 @@ +# WanderQ spacing and framed-layout refinement + +Date: 2026-08-22 +Surface: homepage, Guizhou Experiences archive, representative cave-experience detail +Goal: remove oversized pauses between sections and replace rigid rectangular frames with a softer, more premium editorial card system. + +## 1. Homepage story rhythm — improved + +The experience section no longer begins after an extra 104px margin. Its internal top and bottom spacing was reduced from 88/118px to 72/82px at the desktop reference width. The story, local-team, and final inquiry sections were also tightened while retaining enough space to distinguish the five main story beats. + +![Homepage cards after refinement](/tmp/wanqu-spacing-audit-2026-08-22/07-home-cards-after.png) + +![Homepage transition and story after refinement](/tmp/wanqu-spacing-audit-2026-08-22/08-home-story-after.png) + +## 2. Homepage frames and calls to action — improved + +The three experience choices now use 24px clipping, restrained depth, and a lighter hover lift. Outline and primary actions use a pill silhouette, softer border, and subtle depth so they no longer read as plain rectangular form controls. + +![Homepage experience action after refinement](/tmp/wanqu-spacing-audit-2026-08-22/17-home-button-after.png) + +## 3. Guizhou Experiences archive — improved + +The three entry cards and all category cards now form independent surfaces instead of a rigid tile wall. Section padding was reduced by roughly 25–35%, while 18–24px radii, controlled shadows, and larger inter-card gaps establish hierarchy without making the site playful or overly rounded. + +![Experience categories after refinement](/tmp/wanqu-spacing-audit-2026-08-22/10-experiences-nav-after.png) + +![Outdoor experience cards after refinement](/tmp/wanqu-spacing-audit-2026-08-22/11-experiences-cards-after.png) + +## 4. Experience detail framing — improved + +The activity levels, safety gates, route options, image panel, and decision boundary now use separated cards and calmer corners. Large vertical paddings in the detail flow were reduced from 135–150px to 96–110px on desktop. + +![Activity levels after refinement](/tmp/wanqu-spacing-audit-2026-08-22/12-detail-levels-after.png) + +![Safety gates after refinement](/tmp/wanqu-spacing-audit-2026-08-22/13-detail-gates-after.png) + +## 5. Responsive health — healthy + +Homepage, Guizhou Experiences, and the representative detail page were checked at 390px mobile width and 1512px desktop width. No broken images or horizontal overflow were found. Mobile cards retain the softer frame system with reduced 15–18px radii and tighter 50–66px section spacing. + +![Homepage mobile after refinement](/tmp/wanqu-spacing-audit-2026-08-22/14-home-mobile-after.png) + +![Guizhou Experiences mobile after refinement](/tmp/wanqu-spacing-audit-2026-08-22/15-experiences-mobile-after.png) + +## Accessibility evidence and limits + +- Existing focus-visible outlines remain intact after the radius and shadow changes. +- The updated button shapes retain at least a 46px mobile target height. +- Responsive DOM checks found no hidden horizontal content at the tested widths. +- Screenshot checks cannot establish complete assistive-technology behavior or full WCAG compliance. diff --git a/src/TravelSite.css b/src/TravelSite.css index cd537b0..b8b1f7d 100644 --- a/src/TravelSite.css +++ b/src/TravelSite.css @@ -21,6 +21,4679 @@ font-family: 'Assistant', Arial, sans-serif; } + +/* -------------------------------------------------------------------------- */ +/* Homepage V2 — travel journal / MI Travel-inspired editorial direction */ +/* -------------------------------------------------------------------------- */ + +.oc-home-v2 { + --v2-navy: #111d26; + --v2-paper: #f2eee7; + --v2-cyan: #c8eced; + --v2-coral: #ef755d; + --v2-line: rgba(17, 29, 38, .18); + background: var(--v2-paper); + color: var(--v2-navy); + overflow: clip; +} + +.oc-v2-hero { position: relative; min-height: calc(100svh - 91px); color: #fff; isolation: isolate; overflow: hidden; } +.oc-v2-hero > img, +.oc-v2-hero-shade { position: absolute; inset: 0; width: 100%; height: 100%; } +.oc-v2-hero > img { z-index: -2; object-fit: cover; object-position: center 46%; filter: saturate(.72) contrast(1.06); } +.oc-v2-hero-shade { z-index: -1; background: linear-gradient(90deg, rgba(10,22,30,.78), rgba(10,22,30,.13) 68%), linear-gradient(0deg, rgba(10,22,30,.72), transparent 55%); } +.oc-v2-hero-copy { width: min(calc(100% - 120px), 1500px); min-height: calc(100svh - 91px); margin: 0 auto; padding: 70px 0 82px; display: flex; flex-direction: column; justify-content: space-between; } +.oc-v2-hero-copy > p { margin: 0; font-size: 11px; letter-spacing: .17em; text-transform: uppercase; color: rgba(255,255,255,.74); } +.oc-site .oc-v2-hero h1 { margin: auto 0 54px; max-width: 1070px; color: #fff; font: 500 clamp(70px, 9.2vw, 150px)/.82 'Cormorant Garamond', Georgia, serif; letter-spacing: -.055em; } +.oc-v2-hero h1 em { color: var(--v2-cyan); font-weight: 400; } +.oc-v2-hero-bottom { display: grid; grid-template-columns: minmax(280px, 470px) auto; gap: 60px; align-items: end; } +.oc-v2-hero-bottom > span { font-size: 15px; line-height: 1.7; color: rgba(255,255,255,.75); } +.oc-v2-hero-bottom > a, +.oc-v2-final a { justify-self: end; display: inline-flex; align-items: center; justify-content: center; gap: 16px; min-width: 218px; padding: 20px 24px; background: var(--v2-coral); color: #fff; font-size: 13px; letter-spacing: .08em; text-transform: uppercase; transition: background .25s ease, transform .25s ease; } +.oc-v2-hero-bottom > a:hover, +.oc-v2-final a:hover { background: #da604c; transform: translateY(-2px); } +.oc-v2-hero-scroll { position: absolute; right: 0; bottom: 0; width: 76px; height: 76px; display: grid; place-items: center; background: var(--v2-cyan); color: var(--v2-navy); } +.oc-v2-hero-scroll svg { transform: rotate(90deg); } + +.oc-home-v2 [style*="clip-path"], +.oc-home-v1 [style*="clip-path"] { will-change: clip-path, transform, opacity; } +.oc-v2-hero > img, +.oc-v2-experience-card > img, +.oc-v2-route-card img, +.oc-v2-field-collage img, +.oc-v2-final > img, +.oc-home-v1 .oc-experience-band img, +.oc-home-v1 .oc-home-safari-image { will-change: transform; } + +.oc-v2-discover, +.oc-v2-routes, +.oc-v2-field { padding: clamp(100px, 11vw, 175px) clamp(24px, 5.5vw, 88px); } +.oc-v2-section-intro { display: grid; grid-template-columns: 190px 1fr; gap: 5vw; align-items: start; max-width: 1510px; margin: 0 auto 82px; border-top: 1px solid var(--v2-line); padding-top: 23px; } +.oc-v2-section-intro > span, +.oc-v2-feature-copy > span, +.oc-v2-field-heading > span, +.oc-v2-local-copy > span { font-size: 10px; letter-spacing: .18em; text-transform: uppercase; } +.oc-v2-section-intro > div { display: grid; grid-template-columns: minmax(340px, 1.2fr) minmax(280px, .55fr); gap: 7vw; align-items: start; } +.oc-site .oc-v2-section-intro h2 { margin: 0; color: var(--v2-navy); font: 500 clamp(48px, 6.1vw, 94px)/.92 'Cormorant Garamond', Georgia, serif; letter-spacing: -.05em; } +.oc-v2-section-intro p { margin: 7px 0 0; color: #5c666b; font-size: 15px; line-height: 1.8; } + +.oc-v2-experience-grid { max-width: 1510px; margin: 0 auto; display: grid; grid-template-columns: repeat(12, 1fr); grid-template-rows: 330px 460px; gap: 14px; } +.oc-v2-experience-card { position: relative; min-height: 0; overflow: hidden; isolation: isolate; color: #fff; } +.oc-v2-experience-card.is-1 { grid-column: 1 / 8; grid-row: 1 / 3; } +.oc-v2-experience-card.is-2 { grid-column: 8 / 13; grid-row: 1; } +.oc-v2-experience-card.is-3 { grid-column: 8 / 11; grid-row: 2; } +.oc-v2-experience-card.is-4 { grid-column: 11 / 13; grid-row: 2; } +.oc-v2-experience-card::after { content: ''; position: absolute; inset: 0; z-index: -1; background: linear-gradient(0deg, rgba(6,16,22,.75), transparent 65%); } +.oc-v2-experience-card > img { position: absolute; inset: 0; z-index: -2; width: 100%; height: 100%; object-fit: cover; filter: saturate(.78); transition: transform .7s cubic-bezier(.22,1,.36,1), filter .4s ease; } +.oc-v2-experience-card:hover > img { transform: scale(1.045); filter: saturate(1); } +.oc-v2-experience-card > span { position: absolute; top: 20px; left: 22px; font-size: 10px; letter-spacing: .15em; } +.oc-v2-experience-card > div { position: absolute; left: 24px; right: 24px; bottom: 26px; } +.oc-v2-experience-card small { display: block; margin-bottom: 8px; color: rgba(255,255,255,.68); font-size: 9px; letter-spacing: .14em; text-transform: uppercase; } +.oc-site .oc-v2-experience-card h3 { margin: 0; color: #fff; font: 500 clamp(30px, 3.3vw, 56px)/.9 'Cormorant Garamond', Georgia, serif; letter-spacing: -.04em; } +.oc-v2-experience-card > svg { position: absolute; right: 22px; top: 19px; transition: transform .25s ease; } +.oc-v2-experience-card:hover > svg { transform: translate(5px,-3px); } + +.oc-v2-feature { display: grid; grid-template-columns: minmax(0, 1.12fr) minmax(390px, .88fr); min-height: 850px; background: var(--v2-cyan); } +.oc-v2-feature-image { position: relative; min-height: 760px; } +.oc-v2-feature-image img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; filter: saturate(.72); } +.oc-v2-feature-image > span { position: absolute; bottom: 22px; left: 25px; padding: 10px 13px; background: var(--v2-paper); color: var(--v2-navy); font-size: 9px; letter-spacing: .14em; text-transform: uppercase; } +.oc-v2-feature-copy { padding: clamp(70px, 8vw, 130px) clamp(44px, 7vw, 110px); align-self: center; } +.oc-site .oc-v2-feature-copy h2 { margin: 38px 0 32px; color: var(--v2-navy); font: 500 clamp(51px, 6.1vw, 94px)/.88 'Cormorant Garamond', Georgia, serif; letter-spacing: -.055em; } +.oc-v2-feature-copy > p { max-width: 580px; color: #415257; font-size: 16px; line-height: 1.8; } +.oc-v2-feature-copy > a, +.oc-v2-local-copy > a { display: inline-flex; align-items: center; gap: 14px; margin-top: 24px; padding-bottom: 7px; border-bottom: 1px solid; color: var(--v2-navy); font-size: 12px; letter-spacing: .1em; text-transform: uppercase; } +.oc-v2-feature-facts { display: grid; grid-template-columns: repeat(3, 1fr); gap: 18px; margin-top: 72px; padding-top: 26px; border-top: 1px solid rgba(17,29,38,.23); } +.oc-v2-feature-facts b { display: block; font: 500 clamp(28px, 3vw, 44px)/1 'Cormorant Garamond', Georgia, serif; } +.oc-v2-feature-facts span { display: block; margin-top: 9px; color: #536367; font-size: 10px; letter-spacing: .08em; text-transform: uppercase; } + +.oc-v2-routes { background: var(--v2-navy); color: #fff; } +.oc-v2-section-intro.is-light { border-color: rgba(255,255,255,.2); } +.oc-v2-section-intro.is-light > span, +.oc-v2-section-intro.is-light p { color: rgba(255,255,255,.64); } +.oc-site .oc-v2-section-intro.is-light h2 { color: #fff; } +.oc-v2-route-grid { max-width: 1510px; margin: 0 auto; display: grid; grid-template-columns: repeat(12, 1fr); grid-template-rows: 290px 430px; gap: 15px; } +.oc-v2-route-card { position: relative; overflow: hidden; isolation: isolate; color: #fff; } +.oc-v2-route-card.is-1 { grid-column: 1 / 8; grid-row: 1 / 3; } +.oc-v2-route-card.is-2 { grid-column: 8 / 13; grid-row: 1; } +.oc-v2-route-card.is-3 { grid-column: 8 / 13; grid-row: 2; } +.oc-v2-route-card::after { content: ''; position: absolute; inset: 0; z-index: -1; background: linear-gradient(0deg, rgba(6,14,20,.88), rgba(6,14,20,.05) 75%); } +.oc-v2-route-card img { position: absolute; inset: 0; z-index: -2; width: 100%; height: 100%; object-fit: cover; filter: saturate(.7); transition: transform .7s cubic-bezier(.22,1,.36,1), filter .4s; } +.oc-v2-route-card:hover img { transform: scale(1.04); filter: saturate(.93); } +.oc-v2-route-card > div { position: absolute; left: clamp(22px, 3vw, 45px); right: clamp(22px, 3vw, 45px); bottom: clamp(24px, 3vw, 44px); } +.oc-v2-route-card span { font-size: 9px; letter-spacing: .13em; text-transform: uppercase; color: rgba(255,255,255,.67); } +.oc-site .oc-v2-route-card h3 { margin: 11px 0 13px; color: #fff; font: 500 clamp(33px, 4vw, 67px)/.9 'Cormorant Garamond', Georgia, serif; letter-spacing: -.045em; } +.oc-v2-route-card p { max-width: 570px; margin: 0 0 17px; color: rgba(255,255,255,.65); font-size: 13px; line-height: 1.6; } +.oc-v2-route-card b { display: inline-flex; align-items: center; gap: 9px; color: var(--v2-cyan); font-size: 10px; letter-spacing: .1em; text-transform: uppercase; } + +.oc-v2-field { background: #e8e3da; } +.oc-v2-field-heading { max-width: 1510px; margin: 0 auto 75px; display: grid; grid-template-columns: 190px minmax(0, 900px); gap: 5vw; border-top: 1px solid var(--v2-line); padding-top: 23px; } +.oc-site .oc-v2-field-heading h2 { margin: 0; color: var(--v2-navy); font: 500 clamp(52px, 6.7vw, 103px)/.88 'Cormorant Garamond', Georgia, serif; letter-spacing: -.055em; } +.oc-v2-field-collage { max-width: 1510px; height: 920px; margin: 0 auto; display: grid; grid-template-columns: repeat(12, 1fr); grid-template-rows: 300px 240px 330px; gap: 14px; } +.oc-v2-field-collage figure { position: relative; margin: 0; overflow: hidden; } +.oc-v2-field-collage figure img { width: 100%; height: 100%; object-fit: cover; filter: saturate(.74); } +.oc-v2-field-collage figure.is-1 { grid-column: 1 / 8; grid-row: 1 / 3; } +.oc-v2-field-collage figure.is-2 { grid-column: 8 / 13; grid-row: 1; } +.oc-v2-field-collage figure.is-3 { grid-column: 8 / 11; grid-row: 2; } +.oc-v2-field-collage figure.is-4 { grid-column: 11 / 13; grid-row: 2; } +.oc-v2-field-collage figure.is-5 { grid-column: 5 / 13; grid-row: 3; } +.oc-v2-field-collage figcaption { position: absolute; left: 22px; bottom: 22px; padding: 9px 12px; background: var(--v2-paper); font-size: 10px; letter-spacing: .08em; } +.oc-v2-field-note { grid-column: 1 / 5; grid-row: 3; display: flex; flex-direction: column; justify-content: space-between; padding: 31px; background: var(--v2-coral); color: #fff; } +.oc-v2-field-note p { margin: 0; font: 500 clamp(27px, 2.5vw, 40px)/1.02 'Cormorant Garamond', Georgia, serif; letter-spacing: -.03em; } + +.oc-v2-local { display: grid; grid-template-columns: 1.05fr .95fr; min-height: 900px; background: var(--v2-paper); } +.oc-v2-local-media { position: relative; min-height: 760px; margin: clamp(70px, 8vw, 120px) 0 clamp(70px, 8vw, 120px) clamp(24px, 5.5vw, 88px); } +.oc-v2-local-media img:first-child { width: 83%; height: 82%; object-fit: cover; filter: saturate(.65); } +.oc-v2-local-media img:last-child { position: absolute; right: 0; bottom: 0; width: 46%; height: 42%; object-fit: cover; border: 12px solid var(--v2-paper); filter: saturate(.72); } +.oc-v2-local-copy { align-self: center; padding: 80px clamp(44px, 7vw, 120px); } +.oc-site .oc-v2-local-copy h2 { margin: 38px 0 30px; color: var(--v2-navy); font: 500 clamp(50px, 6vw, 94px)/.89 'Cormorant Garamond', Georgia, serif; letter-spacing: -.055em; } +.oc-v2-local-copy > p { max-width: 560px; color: #59646a; font-size: 15px; line-height: 1.8; } +.oc-v2-local-copy ul { padding: 0; margin: 43px 0 0; list-style: none; border-top: 1px solid var(--v2-line); } +.oc-v2-local-copy li { position: relative; padding: 19px 0 19px 23px; border-bottom: 1px solid var(--v2-line); font-size: 13px; } +.oc-v2-local-copy li::before { content: ''; position: absolute; left: 0; top: 50%; width: 7px; height: 7px; background: var(--v2-coral); transform: translateY(-50%); } + +.oc-v2-final { position: relative; min-height: 760px; display: grid; place-items: center; text-align: center; color: #fff; isolation: isolate; } +.oc-v2-final > img { position: absolute; inset: 0; z-index: -2; width: 100%; height: 100%; object-fit: cover; filter: saturate(.65) brightness(.7); } +.oc-v2-final::after { content: ''; position: absolute; inset: 0; z-index: -1; background: rgba(10,22,30,.38); } +.oc-v2-final > div { padding: 50px 24px; } +.oc-v2-final span { font-size: 11px; letter-spacing: .15em; text-transform: uppercase; color: rgba(255,255,255,.7); } +.oc-site .oc-v2-final h2 { margin: 28px auto 50px; color: #fff; font: 500 clamp(72px, 10vw, 155px)/.82 'Cormorant Garamond', Georgia, serif; letter-spacing: -.06em; } +.oc-v2-final a { justify-self: center; } + +.oc-home-v2 :is(a, button):focus-visible { outline: 3px solid var(--v2-coral); outline-offset: 4px; } + +@media (prefers-reduced-motion: reduce) { + .oc-home-v2 *, + .oc-home-v1 * { + animation-duration: .01ms !important; + animation-iteration-count: 1 !important; + scroll-behavior: auto !important; + } + + .oc-home-v2 [style], + .oc-home-v1 [style] { + translate: none !important; + rotate: none !important; + scale: none !important; + } +} + +@media (max-width: 960px) { + .oc-v2-hero-copy { width: calc(100% - 48px); } + .oc-v2-section-intro, + .oc-v2-field-heading { grid-template-columns: 1fr; gap: 25px; } + .oc-v2-section-intro > div { grid-template-columns: 1fr; gap: 22px; } + .oc-v2-experience-grid { grid-template-rows: 470px 300px 300px; } + .oc-v2-experience-card.is-1 { grid-column: 1 / 13; grid-row: 1; } + .oc-v2-experience-card.is-2 { grid-column: 1 / 7; grid-row: 2; } + .oc-v2-experience-card.is-3 { grid-column: 7 / 13; grid-row: 2; } + .oc-v2-experience-card.is-4 { grid-column: 1 / 13; grid-row: 3; } + .oc-v2-feature { grid-template-columns: 1fr; } + .oc-v2-feature-image { min-height: 650px; } + .oc-v2-route-grid { grid-template-rows: 550px 360px 360px; } + .oc-v2-route-card.is-1 { grid-column: 1 / 13; grid-row: 1; } + .oc-v2-route-card.is-2 { grid-column: 1 / 13; grid-row: 2; } + .oc-v2-route-card.is-3 { grid-column: 1 / 13; grid-row: 3; } + .oc-v2-local { grid-template-columns: 1fr; } + .oc-v2-local-media { min-height: 680px; margin-right: 24px; } +} + +@media (max-width: 640px) { + .oc-v2-hero { min-height: calc(100svh - 76px); } + .oc-v2-hero-copy { width: calc(100% - 40px); min-height: calc(100svh - 76px); padding: 39px 0 64px; } + .oc-site .oc-v2-hero h1 { font-size: 62px; margin-bottom: 35px; } + .oc-v2-hero-bottom { grid-template-columns: 1fr; gap: 23px; } + .oc-v2-hero-bottom > a { justify-self: start; } + .oc-v2-hero-scroll { display: none; } + .oc-v2-discover, + .oc-v2-routes, + .oc-v2-field { padding-inline: 20px; } + .oc-site .oc-v2-section-intro h2, + .oc-site .oc-v2-field-heading h2 { font-size: 49px; } + .oc-v2-experience-grid { display: grid; grid-template-columns: 1fr; grid-template-rows: repeat(4, 360px); } + .oc-v2-experience-card.is-1, + .oc-v2-experience-card.is-2, + .oc-v2-experience-card.is-3, + .oc-v2-experience-card.is-4 { grid-column: 1; grid-row: auto; } + .oc-v2-feature-image { min-height: 520px; } + .oc-v2-feature-copy { padding: 74px 20px; } + .oc-site .oc-v2-feature-copy h2, + .oc-site .oc-v2-local-copy h2 { font-size: 51px; } + .oc-v2-feature-facts { grid-template-columns: 1fr; } + .oc-v2-field-collage { height: auto; display: grid; grid-template-columns: 1fr 1fr; grid-template-rows: 420px 230px 230px 300px; } + .oc-v2-field-collage figure.is-1 { grid-column: 1 / 3; grid-row: 1; } + .oc-v2-field-collage figure.is-2 { grid-column: 1; grid-row: 2; } + .oc-v2-field-collage figure.is-3 { grid-column: 2; grid-row: 2; } + .oc-v2-field-collage figure.is-4 { grid-column: 1; grid-row: 3; } + .oc-v2-field-collage figure.is-5 { grid-column: 2; grid-row: 3; } + .oc-v2-field-note { grid-column: 1 / 3; grid-row: 4; } + .oc-v2-local-media { min-height: 480px; margin: 70px 20px 0; } + .oc-v2-local-copy { padding: 70px 20px 90px; } + .oc-v2-final { min-height: 620px; } +} + +/* -------------------------------------------------------------------------- */ +/* Homepage V1 complete system — bold editorial / business narrative */ +/* -------------------------------------------------------------------------- */ + +.oc-home-v1 { + --v1-ink: #172319; + --v1-paper: #f2efe5; + --v1-acid: #d9f266; + --v1-line: rgba(23, 35, 25, .22); + background: var(--v1-paper); + color: var(--v1-ink); + overflow: clip; +} + +.oc-home-v1 .oc-home-trust { + background: var(--v1-ink); + color: #f7f3e9; + border: 0; +} + +.oc-home-v1 .oc-home-trust-grid { + max-width: none; + padding-inline: clamp(24px, 5vw, 78px); +} + +.oc-home-v1 .oc-home-trust-item { border-color: rgba(255,255,255,.18); } +.oc-home-v1 .oc-home-trust-item svg { color: var(--v1-acid); } +.oc-home-v1 .oc-home-trust-item span { color: rgba(255,255,255,.64); } + +.oc-home-v1 .oc-home-plan-row { + max-width: none; + margin: 0; + padding: 0 clamp(24px, 5vw, 78px) clamp(92px, 10vw, 150px); + background: var(--v1-ink); + color: #fff; + border-radius: 0; + border: 0; + display: grid; + grid-template-columns: repeat(3, 1fr); + gap: 0; +} + +.oc-home-v1 .oc-plan-panel .oc-step { + min-height: 260px; + padding: 54px 34px 30px 0; + border-top: 1px solid rgba(255,255,255,.25); + border-right: 1px solid rgba(255,255,255,.18); +} + +.oc-home-v1 .oc-plan-panel .oc-step + .oc-step { padding-left: 34px; } +.oc-home-v1 .oc-plan-panel .oc-step:last-child { border-right: 0; } +.oc-home-v1 .oc-plan-panel .oc-step b { color: var(--v1-acid); font: 500 13px/1 var(--oc-sans); } +.oc-home-v1 .oc-plan-panel .oc-step h3 { margin-top: 68px; color: #fff; font-size: clamp(25px, 2.2vw, 36px); letter-spacing: -.035em; } +.oc-home-v1 .oc-plan-panel .oc-step p { color: rgba(255,255,255,.62); max-width: 330px; } + +.oc-home-v1 .oc-home-section, +.oc-home-v1 .oc-home-team, +.oc-home-v1 .oc-quote, +.oc-home-v1 .oc-live { + max-width: none; + padding-inline: clamp(24px, 5vw, 78px); +} + +.oc-home-v1 .oc-home-experiences { + width: auto; + padding-top: clamp(58px, 6vw, 88px); + padding-bottom: clamp(78px, 8vw, 118px); +} + +.oc-home-v1 .oc-home-experiences .oc-section-title { + display: block; + max-width: 920px; + margin: 0 auto 40px; + padding-top: 0; + border-top: 0; + text-align: center; +} + +.oc-home-v1 .oc-home-experiences .oc-section-title h2 { + max-width: none; + font-size: clamp(48px, 4.4vw, 68px); + line-height: .94; +} + +.oc-home-v1 .oc-home-experiences .oc-section-title p { + max-width: 700px; + margin: 22px auto 0; +} + +.oc-home-v1 .oc-section-title { + display: grid; + grid-template-columns: minmax(280px, .9fr) minmax(360px, 1.1fr); + align-items: end; + gap: 8vw; + border-top: 1px solid var(--v1-line); + padding-top: 24px; + margin-bottom: 72px; +} + +.oc-home-v1 .oc-section-title h2 { + max-width: 730px; + font-size: clamp(54px, 7vw, 116px); + line-height: .88; + letter-spacing: -.065em; + color: var(--v1-ink); +} + +.oc-home-v1 .oc-section-title p { + margin: 0 0 8px; + max-width: 520px; + color: #516052; + font-size: 16px; + line-height: 1.75; +} + +.oc-home-v1 .oc-experience-stack { + display: grid; + grid-template-columns: repeat(3, minmax(0, 1fr)); + gap: clamp(12px, 1.25vw, 22px); + background: transparent; + border: 0; +} +.oc-home-v1 .oc-experience-band { + height: 660px; + min-height: 660px; + grid-template-rows: 360px 300px; + border: 0; + border-radius: 0; + box-shadow: none; + transition: transform .55s cubic-bezier(.2,.75,.3,1), box-shadow .55s ease; +} +.oc-home-v1 .oc-experience-band.charcoal { background: #173b28; color: #f5f2e8; } +.oc-home-v1 .oc-experience-band.clay { background: #478d4f; color: #fffdf5; } +.oc-home-v1 .oc-experience-band.tan { background: #a4bd75; color: #173326; } +.oc-home-v1 .oc-experience-band img { + filter: saturate(.74) contrast(.98); + transition: transform .85s cubic-bezier(.2,.75,.3,1), filter .55s ease; +} +.oc-home-v1 .oc-experience-band:hover { + transform: translateY(-9px); + box-shadow: 0 28px 55px rgba(21, 39, 28, .14); +} +.oc-home-v1 .oc-experience-band:hover img { transform: scale(1.055); filter: saturate(.98) contrast(1.02); } +.oc-home-v1 .oc-experience-band-content { padding: clamp(25px, 2.25vw, 36px); } +.oc-home-v1 .oc-experience-band-meta, +.oc-home-v1 .oc-experience-band h3, +.oc-home-v1 .oc-experience-band p, +.oc-home-v1 .oc-experience-band small { color: inherit; } +.oc-home-v1 .oc-experience-band-meta { opacity: .78; } +.oc-home-v1 .oc-experience-band h3 { + max-width: 360px; + font-family: 'Assistant', Arial, sans-serif; + font-size: clamp(31px, 2.7vw, 45px); + font-weight: 560; + line-height: 1.02; + letter-spacing: -.045em; +} +.oc-home-v1 .oc-experience-band p { opacity: .78; } +.oc-home-v1 .oc-experience-band small { border-top-color: currentColor; opacity: .82; } +.oc-home-v1 .oc-experience-band small svg { transition: transform .3s ease; } +.oc-home-v1 .oc-experience-band:hover small svg { transform: translateX(7px); } +.oc-home-v1 .oc-experience-band:focus-visible { + outline: 3px solid var(--v1-acid); + outline-offset: 5px; +} +.oc-home-v1 .oc-home-experiences > .oc-center { margin-top: 44px; } + +.oc-home-v1 .oc-home-safaris-section { + background: #cfd7ca; + padding-top: clamp(92px, 11vw, 160px); + padding-bottom: clamp(100px, 12vw, 165px); +} +.oc-home-v1 .oc-home-safaris { gap: 1px; background: rgba(23,35,25,.2); } +.oc-home-v1 .oc-home-safari { border: 0; border-radius: 0; box-shadow: none; background: #f6f3e9; } +.oc-home-v1 .oc-home-safari-media { min-height: 380px; } +.oc-home-v1 .oc-home-safari-image { filter: saturate(.74); } +.oc-home-v1 .oc-home-safari:hover .oc-home-safari-image { transform: scale(1.035); filter: saturate(.95); } +.oc-home-v1 .oc-home-safari-media > span { background: var(--v1-acid); color: var(--v1-ink); border: 0; } +.oc-home-v1 .oc-home-safari-body { padding: 30px 28px 34px; } +.oc-home-v1 .oc-home-safari-body h3 { font-size: clamp(30px, 3vw, 44px); line-height: 1; letter-spacing: -.045em; } +.oc-home-v1 .oc-home-safari-footer { border-top-color: var(--v1-line); } +.oc-home-v1 .oc-clay-btn { border-radius: 0; background: var(--v1-ink); color: #fff; border: 1px solid var(--v1-ink); } +.oc-home-v1 .oc-clay-btn:hover { background: var(--v1-acid); color: var(--v1-ink); } + +.oc-home-v1 .oc-home-team { + width: auto; + margin-top: 0; + padding-top: clamp(92px, 9vw, 132px); + padding-bottom: clamp(92px, 9vw, 132px); + background: #d9ded3; +} +.oc-home-v1 .oc-home-team-layout { gap: clamp(54px, 7vw, 108px); align-items: center; } +.oc-home-v1 .oc-home-team-media { min-height: 690px; } +.oc-home-v1 .oc-home-team-main-image { width: 100%; height: 610px; border-radius: 0; filter: saturate(.78) contrast(.97); } +.oc-home-v1 .oc-home-team-field-image { border-radius: 0; border: 9px solid #d9ded3; width: 42%; height: 230px; } +.oc-home-v1 .oc-home-team-copy h2 { max-width: 650px; color: var(--v1-ink); font-size: clamp(50px, 5.1vw, 78px); line-height: .94; letter-spacing: -.055em; } +.oc-home-v1 .oc-home-team-intro { max-width: 570px; color: #506051; } +.oc-home-v1 .oc-home-team-service { border-top-color: var(--v1-line); } +.oc-home-v1 .oc-home-team-service > span { color: #738072; } +.oc-home-v1 .oc-home-team-service h3 { font-family: 'Assistant', Arial, sans-serif; font-weight: 650; } +.oc-home-v1 .oc-outline-btn { border-radius: 0; border-color: var(--v1-ink); color: var(--v1-ink); } +.oc-home-v1 .oc-outline-btn:hover { background: var(--v1-ink); color: #fff; } + +.oc-home-v1 .oc-quote { + padding-block: clamp(80px, 9vw, 135px); + background: var(--v1-ink); + color: #fff; +} +.oc-home-v1 .oc-quote-media img { border-radius: 0; filter: saturate(.68); } +.oc-home-v1 .oc-quote-copy blockquote p { color: #fff; font-size: clamp(35px, 5vw, 72px); letter-spacing: -.045em; line-height: 1.02; } +.oc-home-v1 .oc-quote-copy > span { color: var(--v1-acid); } + +.oc-home-v1 .oc-home-social-strip { padding-top: 0; padding-bottom: 0; background: var(--v1-ink); } +.oc-home-v1 .oc-social-channel-list { border-block: 1px solid rgba(255,255,255,.18); } +.oc-home-v1 .oc-social-channel { border-color: rgba(255,255,255,.18); color: #fff; border-radius: 0; background: transparent; } +.oc-home-v1 .oc-social-channel span { color: rgba(255,255,255,.58); } + +.oc-home-v1 .oc-live { padding-top: clamp(100px, 12vw, 175px); padding-bottom: clamp(100px, 12vw, 175px); } +.oc-home-v1 .oc-live-heading { display: grid; grid-template-columns: 150px 1.15fr .65fr; gap: 4vw; align-items: start; border-top: 1px solid var(--v1-line); padding-top: 24px; } +.oc-home-v1 .oc-live-heading h2 { margin: 0; color: var(--v1-ink); font-size: clamp(50px, 6.3vw, 96px); line-height: .9; letter-spacing: -.06em; } +.oc-home-v1 .oc-live-heading p { margin: 0; color: #526052; line-height: 1.7; } +.oc-home-v1 .oc-live-grid { margin-top: 70px; gap: 10px; } +.oc-home-v1 .oc-live-photo { border-radius: 0; } +.oc-home-v1 .oc-live-photo img { filter: saturate(.74); } +.oc-home-v1 .oc-live-photo:hover img { filter: saturate(.98); } + +.oc-home-v1 .oc-home-comparison { background: #d9ded3; padding-block: clamp(92px, 11vw, 160px); } +.oc-home-v1 .oc-comparison-heading { display: grid; grid-template-columns: 150px 1.1fr .7fr; gap: 4vw; align-items: start; } +.oc-home-v1 .oc-comparison-heading h2 { margin: 0; color: var(--v1-ink); font-size: clamp(48px, 5.7vw, 88px); line-height: .92; letter-spacing: -.055em; } +.oc-home-v1 .oc-comparison-heading p { margin: 0; color: #4b594d; } +.oc-home-v1 .oc-comparison-table { border-collapse: collapse; border-radius: 0; } +.oc-home-v1 .oc-comparison-table :is(th, td) { border-color: rgba(23,35,25,.18); } +.oc-home-v1 .oc-comparison-table .is-wanderq { background: var(--v1-ink); color: #fff; } + +.oc-home-v1 .oc-home-final-cta { + background: var(--v1-ink); + color: #f7f5ef; + padding-block: clamp(100px, 10.5vw, 158px); +} +.oc-home-v1 .oc-home-final-cta::before { display: none; } +.oc-home-v1 .oc-home-final-cta-layout { grid-template-columns: minmax(0, 1.12fr) minmax(360px, .72fr); align-items: end; } +.oc-home-v1 .oc-home-final-cta-copy { max-width: 790px; } +.oc-home-v1 .oc-home-final-cta-copy h2 { + max-width: 790px; + color: #f7f5ef; + font-size: clamp(62px, 7.1vw, 108px); + line-height: .88; + letter-spacing: -.064em; +} +.oc-home-v1 .oc-home-final-cta-copy h2 em { color: var(--v1-acid); font-style: normal; } +.oc-home-v1 .oc-home-final-cta-copy p { max-width: 610px; color: rgba(247,245,239,.68); } +.oc-home-v1 .oc-home-final-eyebrow { color: rgba(247,245,239,.66); } +.oc-home-v1 .oc-home-final-cta .oc-orange-btn { border-radius: 0; background: var(--v1-acid); color: var(--v1-ink); } +.oc-home-v1 .oc-home-final-cta .oc-orange-btn:hover { background: #f7f5ef; color: var(--v1-ink); } +.oc-home-v1 .oc-home-final-cta-button { transform: none !important; } +.oc-home-v1 .oc-home-final-cta-note { + display: block; + margin-top: 18px; + color: rgba(247,245,239,.48); + font-size: 10px; + font-weight: 650; + letter-spacing: .09em; + line-height: 1.55; + text-transform: uppercase; +} +.oc-home-v1 .oc-home-inquiry-prompts { border-color: rgba(247,245,239,.28); } +.oc-home-v1 .oc-home-inquiry-prompt { border-color: rgba(247,245,239,.15); } +.oc-home-v1 .oc-home-inquiry-prompt h3 { color: #f7f5ef; font-family: 'Assistant', Arial, sans-serif; font-weight: 650; } +.oc-home-v1 .oc-home-inquiry-prompt p { color: rgba(247,245,239,.56); } +.oc-home-v1 .oc-home-inquiry-prompt > span { color: rgba(185,207,70,.75); } +.oc-home-v1 .oc-home-inquiry-prompts-label { color: var(--v1-acid); } + +@media (max-width: 900px) { + .oc-home-v1 .oc-home-plan-row { grid-template-columns: 1fr; } + .oc-home-v1 .oc-plan-panel .oc-step, + .oc-home-v1 .oc-plan-panel .oc-step + .oc-step { min-height: 0; padding: 34px 0 38px; border-right: 0; } + .oc-home-v1 .oc-plan-panel .oc-step h3 { margin-top: 28px; } + .oc-home-v1 .oc-section-title, + .oc-home-v1 .oc-live-heading, + .oc-home-v1 .oc-comparison-heading { grid-template-columns: 1fr; gap: 24px; } + .oc-home-v1 .oc-live-heading h2, + .oc-home-v1 .oc-comparison-heading h2 { max-width: 700px; } + .oc-home-v1 .oc-home-final-cta-layout { grid-template-columns: 1fr; gap: 58px; } + .oc-home-v1 .oc-home-final-cta-copy, + .oc-home-v1 .oc-home-inquiry-prompts { max-width: 680px; } +} + +@media (max-width: 640px) { + .oc-home-v1 .oc-home-trust-grid { padding-inline: 20px; } + .oc-home-v1 .oc-home-plan-row, + .oc-home-v1 .oc-home-section, + .oc-home-v1 .oc-home-team, + .oc-home-v1 .oc-quote, + .oc-home-v1 .oc-live { padding-inline: 20px; } + .oc-home-v1 .oc-section-title h2 { font-size: 50px; } + .oc-home-v1 .oc-experience-band { min-height: 560px; } + .oc-home-v1 .oc-home-safari-media { min-height: 290px; } + .oc-home-v1 .oc-live-heading h2, + .oc-home-v1 .oc-comparison-heading h2 { font-size: 47px; } + .oc-home-v1 .oc-home-final-cta { padding-block: 78px 82px; } + .oc-home-v1 .oc-home-final-cta-layout { gap: 48px; } + .oc-home-v1 .oc-home-final-cta-copy h2 { margin-top: 18px; font-size: 44px; line-height: .96; } + .oc-home-v1 .oc-home-final-cta-copy p { margin-top: 22px; font-size: 14px; line-height: 1.68; } + .oc-home-v1 .oc-home-final-cta-button { width: 100%; min-width: 0; margin-top: 30px; } + .oc-home-v1 .oc-home-final-cta-note { margin-top: 15px; letter-spacing: .055em; } +} + +@media (max-width: 820px) { + .oc-home-v1 .oc-home-team { + padding-top: 76px; + padding-bottom: 82px; + } + + .oc-home-v1 .oc-home-team-media { + min-height: 560px; + } + + .oc-home-v1 .oc-home-team-main-image { + height: 480px; + } + + .oc-home-v1 .oc-home-team-field-image { + width: 44%; + height: 210px; + } +} + +@media (max-width: 640px) { + .oc-home-v1 .oc-home-team-media { + min-height: 430px; + } + + .oc-home-v1 .oc-home-team-main-image { + height: 340px; + } + + .oc-home-v1 .oc-home-team-field-image { + width: 58%; + height: 176px; + border-width: 7px; + } + + .oc-home-v1 .oc-home-team-copy h2 { + font-size: 42px; + line-height: 1; + } + + .oc-home-v1 .oc-home-team-cta { + transform: none !important; + } +} + +@media (max-width: 360px) { + .oc-home-v1 .oc-home-team-cta { + gap: 8px; + padding-inline: 12px; + font-size: 10px; + letter-spacing: .03em; + white-space: normal; + text-align: center; + } +} + +@media (max-width: 820px) { + .oc-home-v1 .oc-experience-stack { + grid-template-columns: 1fr; + gap: 22px; + } + + .oc-home-v1 .oc-experience-band { + height: auto; + min-height: 390px; + grid-template-columns: minmax(0, .86fr) minmax(0, 1.14fr); + grid-template-rows: 1fr; + } +} + +@media (max-width: 640px) { + .oc-home-v1 .oc-home-experiences { + padding-top: 72px; + padding-bottom: 60px; + } + + .oc-home-v1 .oc-home-experiences .oc-section-title { + margin-bottom: 36px; + text-align: left; + } + + .oc-home-v1 .oc-home-experiences .oc-section-title p { + margin-left: 0; + } + + .oc-home-v1 .oc-experience-band { + height: auto; + min-height: 0; + grid-template-columns: 1fr; + grid-template-rows: auto auto; + } + + .oc-home-v1 .oc-experience-band-media { + min-height: 0; + aspect-ratio: 4 / 3.25; + } + + .oc-home-v1 .oc-experience-band-content { + min-height: 280px; + padding: 24px 22px; + } + + .oc-home-v1 .oc-experience-band h3 { + font-size: 30px; + } + + .oc-home-v1 .oc-home-experiences > .oc-center { + margin-top: 34px; + } +} + +/* Homepage concept 2026 — bold destination matrix + narrative funnel */ +.oc-prototype-hero { + position: relative; + min-height: calc(100svh - 91px); + overflow: hidden; + isolation: isolate; + color: #f7f5ed; + background: #17221b; +} + +.oc-prototype-hero-image, +.oc-prototype-hero-shade { + position: absolute; + inset: 0; + width: 100%; + height: 112%; +} + +.oc-prototype-hero-image { + z-index: -3; + object-fit: cover; + object-position: center 48%; + filter: saturate(.72) contrast(1.04) brightness(.8); + animation: oc-prototype-image-in 1.2s cubic-bezier(.22, 1, .36, 1) both; +} + +@keyframes oc-prototype-image-in { + from { opacity: .35; transform: scale(1.055); } + to { opacity: 1; transform: scale(1); } +} + +.oc-prototype-hero-shade { + z-index: -2; + height: 100%; + background: + linear-gradient(90deg, rgba(8, 14, 10, .62) 0%, rgba(8, 14, 10, .13) 61%, rgba(8, 14, 10, .31) 100%), + linear-gradient(0deg, rgba(8, 14, 10, .73) 0%, rgba(8, 14, 10, .02) 52%, rgba(8, 14, 10, .22) 100%); +} + +.oc-prototype-hero-content { + width: min(calc(100% - 96px), 1500px); + min-height: calc(100svh - 91px); + display: grid; + grid-template-columns: minmax(0, 1fr) 340px; + grid-template-rows: auto 1fr; + column-gap: 58px; + align-items: end; + margin: 0 auto; + padding: 47px 0 150px; +} + +.oc-prototype-hero-kicker { + grid-column: 1 / -1; + align-self: start; + margin: 0; + color: rgba(255, 255, 255, .76); + font-size: 11px; + font-weight: 700; + letter-spacing: .2em; + text-transform: uppercase; +} + +.oc-site .oc-prototype-hero-content h1 { + max-width: 1050px; + margin: 0; + color: #fff; + font-family: 'Assistant', Arial, sans-serif; + font-size: clamp(68px, 8.1vw, 132px); + font-weight: 650; + line-height: .82; + letter-spacing: -.072em; +} + +.oc-prototype-hero-title-row { + display: block; + overflow: hidden; + padding: 0 .08em .08em 0; +} + +.oc-prototype-hero-title-line { + display: block; +} + +.oc-prototype-hero-title-line.is-accent { + color: #d9ff57; +} + +/* Chinese glyphs need a taller line box than the compact Latin hero type. */ +html[data-oc-language='zh'] .oc-site .oc-prototype-hero-content h1 { + max-width: 100%; + font-family: 'PingFang SC', 'Microsoft YaHei', 'Noto Sans CJK SC', sans-serif; + font-size: clamp(58px, 6.6vw, 108px); + font-weight: 700; + line-height: 1.06; + letter-spacing: -.045em; +} + +html[data-oc-language='zh'] .oc-prototype-hero-title-row { + padding: .06em .08em .12em 0; +} + +@media (max-width: 540px) { + html[data-oc-language='zh'] .oc-site .oc-prototype-hero-content h1 { + font-size: clamp(36px, 12vw, 50px); + line-height: 1.08; + } +} + +.oc-prototype-hero-side { + align-self: end; + padding-bottom: 10px; +} + +.oc-prototype-hero-side p { + margin: 0 0 29px; + color: rgba(255, 255, 255, .79); + font-size: 16px; + line-height: 1.65; +} + +.oc-prototype-hero-side a, +.oc-prototype-story-copy > a { + display: inline-flex; + align-items: center; + gap: 18px; + padding-bottom: 9px; + color: currentColor; + border-bottom: 1px solid currentColor; + font-size: 12px; + font-weight: 700; + letter-spacing: .08em; + text-transform: uppercase; +} + +.oc-prototype-hero-footer { + position: absolute; + right: 0; + bottom: 0; + left: 0; + min-height: 80px; + display: grid; + grid-template-columns: 1fr auto auto; + gap: 48px; + align-items: center; + padding: 0 max(48px, calc((100vw - 1500px) / 2)); + border-top: 1px solid rgba(255, 255, 255, .24); + color: rgba(255, 255, 255, .72); + font-size: 10px; + font-weight: 700; + letter-spacing: .12em; + text-transform: uppercase; +} + +.oc-prototype-hero-assurances, +.oc-prototype-hero-controls { + display: flex; + align-items: center; +} + +.oc-prototype-hero-assurances { gap: 26px; } +.oc-prototype-hero-assurances span + span::before { content: '·'; margin-right: 26px; } +.oc-prototype-hero-controls { gap: 11px; } + +.oc-prototype-hero-dot { + width: 26px; + height: 1px; + padding: 7px 0; + border: 0; + background: linear-gradient(rgba(255,255,255,.42), rgba(255,255,255,.42)) center / 100% 1px no-repeat; + cursor: pointer; +} + +.oc-prototype-hero-dot.is-active { + background-image: linear-gradient(#d9ff57, #d9ff57); +} + +.oc-prototype-hero-playback { + width: 27px; + height: 27px; + display: grid; + place-items: center; + padding: 0; + border: 0; + color: #fff; + background: transparent; + cursor: pointer; +} + +.oc-prototype-hero :is(button, a):focus-visible, +.oc-prototype-themes a:focus-visible, +.oc-prototype-story a:focus-visible { + outline: 2px solid #d9ff57; + outline-offset: 5px; +} + +.oc-prototype-themes { + min-height: 100svh; + padding: 118px max(48px, calc((100vw - 1500px) / 2)) 104px; + color: #f3f1e8; + background: #142119; +} + +.oc-prototype-theme-head { + display: grid; + grid-template-columns: 160px minmax(0, 1fr) 320px; + gap: 45px; + align-items: end; + margin-bottom: 64px; +} + +.oc-prototype-theme-head > span, +.oc-prototype-story-copy > span { + align-self: start; + color: #d9ff57; + font-size: 10px; + font-weight: 700; + line-height: 1.5; + letter-spacing: .17em; + text-transform: uppercase; +} + +.oc-site .oc-prototype-theme-head h2, +.oc-site .oc-prototype-story-copy h2 { + margin: 0; + color: inherit; + font-family: 'Assistant', Arial, sans-serif; + font-size: clamp(52px, 6.2vw, 96px); + font-weight: 620; + line-height: .9; + letter-spacing: -.065em; + white-space: pre-line; +} + +.oc-site .oc-prototype-story-copy h2 em { + color: #527f58; + font-style: normal; + font-weight: inherit; +} + +.oc-prototype-theme-head p { + margin: 0 0 5px; + color: rgba(243, 241, 232, .58); + font-size: 15px; + line-height: 1.7; +} + +.oc-prototype-theme-grid { + display: grid; + grid-template-columns: repeat(4, minmax(0, 1fr)); + border-top: 1px solid rgba(255, 255, 255, .19); + border-left: 1px solid rgba(255, 255, 255, .19); +} + +.oc-prototype-theme-card { + position: relative; + min-height: clamp(230px, 21vw, 330px); + display: grid; + grid-template-columns: 1fr auto; + grid-template-rows: 1fr auto; + align-items: end; + padding: 25px 27px 27px; + overflow: hidden; + border-right: 1px solid rgba(255, 255, 255, .19); + border-bottom: 1px solid rgba(255, 255, 255, .19); + color: #f8f6ee; + isolation: isolate; +} + +.oc-prototype-theme-card::after { + content: ''; + position: absolute; + inset: 0; + z-index: -1; + background: linear-gradient(0deg, rgba(5, 10, 7, .88), rgba(5, 10, 7, .05) 70%); + transition: background-color .45s ease; +} + +.oc-prototype-theme-card img { + position: absolute; + inset: 0; + z-index: -2; + width: 100%; + height: 100%; + object-fit: cover; + filter: saturate(.62) brightness(.73); + transition: transform .7s cubic-bezier(.2,.75,.3,1), filter .5s ease; +} + +.oc-prototype-theme-card > span { + grid-column: 1 / -1; + align-self: start; + color: rgba(255, 255, 255, .66); + font-size: 10px; + letter-spacing: .15em; +} + +.oc-site .oc-prototype-theme-card h3 { + margin: 0; + color: inherit; + font-size: clamp(23px, 2vw, 34px); + font-weight: 600; + line-height: 1; + letter-spacing: -.035em; + font-family: 'Assistant', Arial, sans-serif; +} + +.oc-prototype-theme-card:hover img { transform: scale(1.065); filter: saturate(.9) brightness(.9); } +.oc-prototype-theme-card:hover::after { background-color: rgba(45, 75, 52, .25); } +.oc-prototype-theme-card:hover svg { transform: translate(5px, -5px); } +.oc-prototype-theme-card svg { transition: transform .25s ease; } + +.oc-prototype-story { + min-height: 0; + display: grid; + grid-template-columns: minmax(380px, .88fr) minmax(0, 1.12fr); + grid-template-rows: auto 1fr auto; + column-gap: clamp(64px, 7vw, 112px); + padding: 96px max(48px, calc((100vw - 1500px) / 2)) 88px; + color: #1d2b21; + background: #f1efe5; +} + +.oc-prototype-story-image { + position: relative; + grid-row: 1 / 4; + min-height: 780px; + overflow: hidden; + background: #d8ddd4; +} + +.oc-prototype-story-image::after { + content: ''; + position: absolute; + inset: 0; + background: linear-gradient(0deg, rgba(10, 20, 13, .48), transparent 44%); +} + +.oc-prototype-story-image img { + width: 100%; + height: 100%; + object-fit: cover; + filter: saturate(.75) contrast(.95); +} + +.oc-prototype-story-image span { + position: absolute; + bottom: 29px; + left: 31px; + z-index: 1; + color: #fff; + font-size: 10px; + font-weight: 700; + letter-spacing: .16em; + text-transform: uppercase; +} + +.oc-prototype-story-copy { + display: grid; + grid-template-columns: 125px 1fr; + column-gap: 35px; + align-content: start; +} + +.oc-prototype-story-copy h2 { grid-column: 2; } + +.oc-prototype-story-copy > p { + grid-column: 2; + max-width: 620px; + margin: 27px 0 0; + color: #5d695f; + font-size: 17px; + line-height: 1.75; +} + +.oc-prototype-story-copy > a { + grid-column: 2; + justify-self: start; + margin-top: 28px; + color: #263a2c; +} + +.oc-prototype-story-steps { + align-self: end; + margin-top: 54px; + border-top: 1px solid rgba(25, 42, 30, .22); +} + +.oc-prototype-story-step { + display: grid; + grid-template-columns: 70px 1fr; + gap: 25px; + padding: 24px 0; + border-bottom: 1px solid rgba(25, 42, 30, .18); +} + +.oc-prototype-story-step > span { + color: #66816c; + font-size: 11px; + font-weight: 700; + letter-spacing: .15em; +} + +.oc-site .oc-prototype-story-step h3 { + margin: 0 0 7px; + color: #253429; + font-size: 22px; + font-weight: 650; + line-height: 1.25; + font-family: 'Assistant', Arial, sans-serif; +} + +.oc-prototype-story-step p { + max-width: 680px; + margin: 0; + color: #667069; + font-size: 14px; + line-height: 1.65; +} + +.oc-prototype-story-proof { + margin: 30px 0 0; + color: #68816d; + font-size: 10px; + font-weight: 700; + letter-spacing: .12em; + text-transform: uppercase; +} + +@media (max-width: 1100px) { + .oc-prototype-hero-content { grid-template-columns: 1fr; align-content: end; } + .oc-prototype-hero-side { max-width: 520px; margin-top: 28px; } + .oc-prototype-hero-assurances { display: none; } + .oc-prototype-hero-footer { grid-template-columns: 1fr auto; } + .oc-prototype-theme-head { grid-template-columns: 120px 1fr; } + .oc-prototype-theme-head p { grid-column: 2; } + .oc-prototype-theme-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); } + .oc-prototype-story { grid-template-columns: minmax(300px, .8fr) 1.2fr; column-gap: 54px; } + .oc-prototype-story-copy { grid-template-columns: 1fr; } + .oc-prototype-story-copy > :is(h2, p, a) { grid-column: 1; } + .oc-prototype-story-copy > span { margin-bottom: 24px; } +} + +@media (max-width: 820px) { + .oc-prototype-hero { min-height: calc(100svh - 76px); } + .oc-prototype-hero-content { + width: min(100% - 40px, 700px); + min-height: calc(100svh - 76px); + padding: 33px 0 122px; + } + .oc-prototype-hero-content h1 { font-size: clamp(54px, 13vw, 86px); line-height: .87; } + .oc-prototype-hero-footer { min-height: 64px; padding: 0 20px; } + .oc-prototype-hero-footer > span { display: none; } + .oc-prototype-hero-footer { grid-template-columns: 1fr; } + .oc-prototype-hero-controls { justify-self: start; } + .oc-prototype-themes { padding: 84px 20px 74px; } + .oc-prototype-theme-head { grid-template-columns: 1fr; gap: 22px; margin-bottom: 42px; } + .oc-prototype-theme-head p { grid-column: 1; max-width: 480px; } + .oc-prototype-theme-card { min-height: 250px; } + .oc-prototype-story { grid-template-columns: 1fr; padding: 64px 20px 68px; } + .oc-prototype-story-image { grid-row: auto; min-height: 540px; margin-bottom: 60px; } +} + +@media (max-width: 540px) { + .oc-prototype-hero-content h1 { font-size: 52px; } + .oc-prototype-hero-side p { font-size: 14px; } + .oc-prototype-theme-grid { grid-template-columns: 1fr; } + .oc-prototype-theme-card { min-height: 235px; } + .oc-prototype-theme-head h2, + .oc-prototype-story-copy h2 { font-size: 48px; } + .oc-prototype-story-image { min-height: 440px; } + .oc-prototype-story-step { grid-template-columns: 42px 1fr; gap: 12px; } +} +/* Underground karst experience detail */ +.oc-cave-detail { + --oc-cave-ink: #172019; + --oc-cave-moss: #253a2f; + --oc-cave-sage: #a9b8a9; + --oc-cave-paper: #f3f1e9; + color: var(--oc-cave-ink); + background: #f8f7f2; +} + +.oc-cave-detail :is(section, nav)[id] { + scroll-margin-top: 96px; +} + +.oc-cave-detail-hero { + position: relative; + min-height: 760px; + display: grid; + overflow: hidden; + color: #fff; + background: #172019; +} + +.oc-cave-detail-hero > img, +.oc-cave-detail-shade { + position: absolute; + inset: 0; + width: 100%; + height: 100%; +} + +.oc-cave-detail-hero > img { + object-fit: cover; + object-position: center 54%; + filter: saturate(.72) contrast(.94) brightness(.82); +} + +.oc-cave-detail-shade { + background: + linear-gradient(90deg, rgba(9, 16, 12, .82) 0%, rgba(9, 16, 12, .57) 38%, rgba(9, 16, 12, .08) 73%), + linear-gradient(0deg, rgba(9, 16, 12, .48) 0%, transparent 48%); +} + +.oc-cave-detail-hero-content { + position: relative; + z-index: 1; + display: flex; + flex-direction: column; + justify-content: flex-end; + min-height: 760px; + padding-top: 120px; + padding-bottom: 90px; +} + +.oc-cave-detail-hero-copy > .oc-breadcrumb.is-light { + position: static; + margin: 0 0 23px; + padding: 0; +} + +.oc-cave-detail-hero-copy { + max-width: 790px; +} + +.oc-cave-detail-hero-copy > span, +.oc-cave-detail-section-head > span, +.oc-cave-detail-intro > span { + display: block; + margin-bottom: 22px; + color: #b9c8b9; + font-size: 11px; + font-weight: 700; + line-height: 1.3; + letter-spacing: .2em; + text-transform: uppercase; +} + +.oc-cave-detail-hero-copy h1 { + max-width: 760px; + margin: 0; + font-family: var(--oc-serif); + font-size: clamp(54px, 7.1vw, 108px); + font-weight: 400; + line-height: .92; + letter-spacing: -.055em; +} + +.oc-cave-detail-hero-copy p { + max-width: 650px; + margin: 31px 0 0; + color: rgba(255, 255, 255, .78); + font-size: clamp(16px, 1.45vw, 20px); + line-height: 1.65; +} + +.oc-cave-detail-hero-copy > a { + display: inline-flex; + align-items: center; + gap: 11px; + margin-top: 32px; + padding-bottom: 7px; + color: #fff; + border-bottom: 1px solid rgba(255, 255, 255, .55); + font-size: 12px; + font-weight: 700; + letter-spacing: .08em; + text-transform: uppercase; +} + +.oc-cave-detail-nav { + position: sticky; + z-index: 4; + top: 0; + display: flex; + justify-content: center; + gap: clamp(22px, 5vw, 68px); + min-height: 69px; + align-items: center; + background: rgba(248, 247, 242, .94); + border-bottom: 1px solid rgba(32, 49, 39, .13); + backdrop-filter: blur(14px); +} + +.oc-cave-detail-nav a { + color: #48544c; + font-size: 11px; + font-weight: 700; + letter-spacing: .08em; + text-transform: uppercase; +} + +.oc-cave-detail-overview { + display: grid; + grid-template-columns: minmax(0, 1.16fr) minmax(380px, .84fr); + gap: clamp(70px, 10vw, 150px); + padding-top: 145px; + padding-bottom: 145px; +} + +.oc-cave-detail-intro h2, +.oc-cave-detail-section-head h2 { + margin: 0; + font-family: var(--oc-serif); + font-size: clamp(38px, 4.6vw, 68px); + font-weight: 400; + line-height: 1.05; + letter-spacing: -.045em; +} + +.oc-cave-detail-intro > span { + color: #647468; +} + +.oc-cave-detail-intro p { + max-width: 760px; + margin: 35px 0 0; + color: #5a635d; + font-size: 16px; + line-height: 1.9; +} + +.oc-cave-detail-facts { + margin: 0; + border-top: 1px solid rgba(32, 49, 39, .2); +} + +.oc-cave-detail-facts > div { + display: grid; + grid-template-columns: 122px minmax(0, 1fr); + gap: 22px; + padding: 18px 0; + border-bottom: 1px solid rgba(32, 49, 39, .14); +} + +.oc-cave-detail-facts dt { + color: #788078; + font-size: 10px; + font-weight: 700; + letter-spacing: .08em; + text-transform: uppercase; +} + +.oc-cave-detail-facts dd { + margin: 0; + color: #26352c; + font-size: 13px; + line-height: 1.55; +} + +.oc-cave-detail-levels { + padding: 132px 0 142px; + color: #f5f3eb; + background: var(--oc-cave-moss); +} + +.oc-cave-detail-levels .oc-cave-detail-section-head { + display: grid; + grid-template-columns: minmax(0, 1fr) minmax(300px, .58fr); + column-gap: 100px; + align-items: end; +} + +.oc-cave-detail-levels .oc-cave-detail-section-head > span { + grid-column: 1 / -1; +} + +.oc-cave-detail-section-head > p { + margin: 0; + color: #67726a; + font-size: 14px; + line-height: 1.85; +} + +.oc-cave-detail-levels .oc-cave-detail-section-head > p { + color: rgba(245, 243, 235, .63); +} + +.oc-cave-detail-level-grid { + display: grid; + grid-template-columns: repeat(3, minmax(0, 1fr)); + margin-top: 76px; + border-top: 1px solid rgba(255, 255, 255, .18); + border-bottom: 1px solid rgba(255, 255, 255, .18); +} + +.oc-cave-detail-level-grid article { + min-height: 480px; + padding: 35px 38px 38px; + border-left: 1px solid rgba(255, 255, 255, .18); +} + +.oc-cave-detail-level-grid article:first-child { + border-left: 0; +} + +.oc-cave-detail-level-grid article > div { + display: flex; + align-items: center; + justify-content: space-between; +} + +.oc-cave-detail-level-grid article > div span { + color: rgba(255, 255, 255, .48); + font-family: var(--oc-serif); + font-size: 29px; +} + +.oc-cave-detail-level-grid article > div b { + padding: 7px 12px; + border: 1px solid rgba(255, 255, 255, .28); + border-radius: 999px; + font-size: 9px; + letter-spacing: .13em; + text-transform: uppercase; +} + +.oc-cave-detail-level-grid h3 { + min-height: 116px; + margin: 64px 0 25px; + font-family: var(--oc-serif); + font-size: 31px; + font-weight: 400; + line-height: 1.12; +} + +.oc-cave-detail-level-grid p { + margin: 0; + color: rgba(245, 243, 235, .67); + font-size: 13px; + line-height: 1.85; +} + +.oc-cave-detail-level-grid small { + display: block; + margin-top: 30px; + padding-top: 18px; + color: #d4ded3; + border-top: 1px solid rgba(255, 255, 255, .13); + font-size: 10px; + line-height: 1.65; +} + +.oc-cave-detail-flow { + display: grid; + grid-template-columns: minmax(0, .94fr) minmax(0, 1.06fr); + gap: clamp(60px, 8vw, 120px); + padding-top: 150px; + padding-bottom: 150px; +} + +.oc-cave-detail-flow figure { + position: sticky; + top: 98px; + height: 660px; + margin: 0; + overflow: hidden; + background: #d9ddd6; +} + +.oc-cave-detail-flow figure img { + width: 100%; + height: 100%; + object-fit: cover; + filter: saturate(.8); +} + +.oc-cave-detail-flow-copy .oc-cave-detail-section-head > span, +.oc-cave-detail-routes .oc-cave-detail-section-head > span { + color: #657469; +} + +.oc-cave-detail-flow ol { + margin: 66px 0 0; + padding: 0; + list-style: none; + border-top: 1px solid rgba(32, 49, 39, .18); +} + +.oc-cave-detail-flow li { + display: grid; + grid-template-columns: 52px minmax(0, 1fr); + gap: 22px; + padding: 27px 0; + border-bottom: 1px solid rgba(32, 49, 39, .14); +} + +.oc-cave-detail-flow li > span { + color: #8c968e; + font-family: var(--oc-serif); + font-size: 22px; +} + +.oc-cave-detail-flow h3 { + margin: 0; + font-family: var(--oc-serif); + font-size: 22px; + font-weight: 400; +} + +.oc-cave-detail-flow li p { + margin: 9px 0 0; + color: #69716c; + font-size: 12px; + line-height: 1.75; +} + +.oc-cave-detail-safety { + padding: 135px 0 140px; + background: #e7e9e1; +} + +.oc-cave-detail-safety .oc-cave-detail-section-head { + max-width: 930px; +} + +.oc-cave-detail-safety .oc-cave-detail-section-head > span { + color: #647468; +} + +.oc-cave-detail-safety .oc-cave-detail-section-head > p { + max-width: 690px; + margin-top: 29px; +} + +.oc-cave-detail-gate-grid { + display: grid; + grid-template-columns: repeat(4, minmax(0, 1fr)); + margin-top: 72px; + border-top: 1px solid rgba(32, 49, 39, .2); +} + +.oc-cave-detail-gate-grid article { + position: relative; + min-height: 310px; + padding: 31px 28px 34px; + border-right: 1px solid rgba(32, 49, 39, .16); +} + +.oc-cave-detail-gate-grid article:first-child { + border-left: 1px solid rgba(32, 49, 39, .16); +} + +.oc-cave-detail-gate-grid article > span { + color: #849087; + font-family: var(--oc-serif); + font-size: 21px; +} + +.oc-cave-detail-gate-grid article > svg { + position: absolute; + top: 30px; + right: 27px; + color: #617768; +} + +.oc-cave-detail-gate-grid h3 { + margin: 79px 0 18px; + font-family: var(--oc-serif); + font-size: 23px; + font-weight: 400; + line-height: 1.2; +} + +.oc-cave-detail-gate-grid p { + margin: 0; + color: #68726b; + font-size: 12px; + line-height: 1.75; +} + +.oc-cave-detail-boundary { + display: grid; + grid-template-columns: repeat(2, minmax(0, 1fr)); + gap: 1px; + margin-top: 82px; + background: rgba(255, 255, 255, .52); + border: 1px solid rgba(32, 49, 39, .12); +} + +.oc-cave-detail-boundary > div { + padding: 44px 48px; + background: rgba(255, 255, 255, .52); +} + +.oc-cave-detail-boundary > div:last-child { + background: rgba(36, 55, 44, .94); + color: #f4f2e9; +} + +.oc-cave-detail-boundary span { + display: block; + margin-bottom: 27px; + font-size: 10px; + font-weight: 700; + letter-spacing: .14em; + text-transform: uppercase; +} + +.oc-cave-detail-boundary ul { + display: grid; + gap: 13px; + margin: 0; + padding-left: 18px; +} + +.oc-cave-detail-boundary li { + color: #526057; + font-size: 12px; + line-height: 1.7; +} + +.oc-cave-detail-boundary > div:last-child li { + color: rgba(244, 242, 233, .71); +} + +.oc-cave-detail-routes { + padding-top: 140px; + padding-bottom: 146px; +} + +.oc-cave-detail-routes .oc-cave-detail-section-head { + max-width: 950px; +} + +.oc-cave-detail-route-grid { + display: grid; + grid-template-columns: repeat(3, minmax(0, 1fr)); + margin-top: 72px; + border-top: 1px solid rgba(32, 49, 39, .2); + border-bottom: 1px solid rgba(32, 49, 39, .2); +} + +.oc-cave-detail-route-grid a { + position: relative; + min-height: 275px; + padding: 29px 34px 34px; + color: var(--oc-cave-ink); + border-left: 1px solid rgba(32, 49, 39, .16); + transition: color .25s ease, background .25s ease; +} + +.oc-cave-detail-route-grid a:first-child { + border-left: 0; +} + +.oc-cave-detail-route-grid a:hover { + color: #fff; + background: var(--oc-cave-moss); +} + +.oc-cave-detail-route-grid a > span { + color: #8a958d; + font-family: var(--oc-serif); + font-size: 22px; +} + +.oc-cave-detail-route-grid h3 { + max-width: 320px; + margin: 70px 0 14px; + font-family: var(--oc-serif); + font-size: 25px; + font-weight: 400; +} + +.oc-cave-detail-route-grid p { + max-width: 340px; + margin: 0; + color: #6c756f; + font-size: 11px; + line-height: 1.75; + transition: color .25s ease; +} + +.oc-cave-detail-route-grid a:hover p { + color: rgba(255, 255, 255, .68); +} + +.oc-cave-detail-route-grid svg { + position: absolute; + top: 33px; + right: 30px; +} + +.oc-cave-detail > .oc-menu-bottom-prompt { + margin-bottom: 120px; +} + +@media (max-width: 1024px) { + .oc-cave-detail-hero, + .oc-cave-detail-hero-content { + min-height: 680px; + } + + .oc-cave-detail-overview, + .oc-cave-detail-levels .oc-cave-detail-section-head, + .oc-cave-detail-flow { + grid-template-columns: 1fr; + } + + .oc-cave-detail-overview { + gap: 64px; + } + + .oc-cave-detail-levels .oc-cave-detail-section-head > span { + grid-column: auto; + } + + .oc-cave-detail-levels .oc-cave-detail-section-head > p { + margin-top: 26px; + } + + .oc-cave-detail-level-grid { + grid-template-columns: 1fr; + } + + .oc-cave-detail-level-grid article, + .oc-cave-detail-level-grid article:first-child { + min-height: 0; + border-top: 1px solid rgba(255, 255, 255, .15); + border-left: 0; + } + + .oc-cave-detail-level-grid article:first-child { + border-top: 0; + } + + .oc-cave-detail-level-grid h3 { + min-height: 0; + margin-top: 45px; + } + + .oc-cave-detail-flow figure { + position: relative; + top: auto; + height: 580px; + } + + .oc-cave-detail-gate-grid { + grid-template-columns: repeat(2, minmax(0, 1fr)); + } + + .oc-cave-detail-gate-grid article:nth-child(3) { + border-left: 1px solid rgba(32, 49, 39, .16); + } +} + +@media (max-width: 720px) { + .oc-cave-detail-hero, + .oc-cave-detail-hero-content { + min-height: 650px; + } + + .oc-cave-detail-hero > img { + object-position: 58% center; + } + + .oc-cave-detail-shade { + background: linear-gradient(0deg, rgba(9, 16, 12, .88) 0%, rgba(9, 16, 12, .2) 86%); + } + + .oc-cave-detail-hero-content { + padding-top: 92px; + padding-bottom: 58px; + } + + .oc-cave-detail-hero-copy h1 { + font-size: clamp(49px, 15vw, 72px); + } + + .oc-cave-detail-hero-copy p { + font-size: 15px; + } + + .oc-cave-detail-nav { + justify-content: flex-start; + gap: 26px; + min-height: 61px; + overflow-x: auto; + padding-right: 22px; + padding-left: 22px; + scrollbar-width: none; + } + + .oc-cave-detail-nav::-webkit-scrollbar { + display: none; + } + + .oc-cave-detail-nav a { + flex: 0 0 auto; + } + + .oc-cave-detail-overview, + .oc-cave-detail-flow, + .oc-cave-detail-levels, + .oc-cave-detail-safety, + .oc-cave-detail-routes { + padding-top: 82px; + padding-bottom: 88px; + } + + .oc-cave-detail-intro h2, + .oc-cave-detail-section-head h2 { + font-size: clamp(37px, 11vw, 52px); + } + + .oc-cave-detail-facts > div { + grid-template-columns: 96px minmax(0, 1fr); + gap: 15px; + } + + .oc-cave-detail-level-grid { + margin-top: 50px; + } + + .oc-cave-detail-level-grid article { + padding: 29px 4px 32px; + } + + .oc-cave-detail-level-grid h3 { + margin-top: 38px; + font-size: 27px; + } + + .oc-cave-detail-flow { + gap: 50px; + } + + .oc-cave-detail-flow figure { + height: 430px; + } + + .oc-cave-detail-flow ol { + margin-top: 48px; + } + + .oc-cave-detail-flow li { + grid-template-columns: 39px minmax(0, 1fr); + gap: 13px; + } + + .oc-cave-detail-gate-grid, + .oc-cave-detail-boundary, + .oc-cave-detail-route-grid { + grid-template-columns: 1fr; + } + + .oc-cave-detail-gate-grid article, + .oc-cave-detail-gate-grid article:first-child, + .oc-cave-detail-gate-grid article:nth-child(3) { + min-height: 250px; + border-top: 1px solid rgba(32, 49, 39, .16); + border-right: 1px solid rgba(32, 49, 39, .16); + border-left: 1px solid rgba(32, 49, 39, .16); + } + + .oc-cave-detail-gate-grid h3 { + margin-top: 54px; + } + + .oc-cave-detail-boundary { + margin-top: 55px; + } + + .oc-cave-detail-boundary > div { + padding: 34px 26px; + } + + .oc-cave-detail-route-grid a, + .oc-cave-detail-route-grid a:first-child { + min-height: 235px; + padding-right: 24px; + padding-left: 24px; + border-top: 1px solid rgba(32, 49, 39, .16); + border-left: 0; + } + + .oc-cave-detail-route-grid h3 { + margin-top: 52px; + } + + .oc-cave-detail > .oc-menu-bottom-prompt { + margin-bottom: 70px; + } +} + +/* Waterfall abseiling detail reuses the outdoor-detail grammar with a colder, wetter field palette. */ +.oc-waterfall-detail { + --oc-cave-ink: #142326; + --oc-cave-moss: #18383a; + --oc-cave-sage: #9cb9b8; + --oc-cave-paper: #eef2ee; + background: #f3f5f1; +} + +.oc-waterfall-detail .oc-cave-detail-hero > img { + object-position: center 47%; + filter: saturate(.78) contrast(.98) brightness(.79); +} + +.oc-waterfall-detail .oc-cave-detail-shade { + background: + linear-gradient(90deg, rgba(8, 22, 24, .84) 0%, rgba(8, 22, 24, .57) 42%, rgba(8, 22, 24, .08) 76%), + linear-gradient(0deg, rgba(8, 22, 24, .52) 0%, transparent 52%); +} + +.oc-waterfall-detail .oc-cave-detail-hero-copy { + max-width: 980px; +} + +.oc-waterfall-detail .oc-cave-detail-hero-copy h1 { + max-width: 960px; + font-size: clamp(50px, 6.25vw, 94px); +} + +.oc-waterfall-detail .oc-cave-detail-levels { + background: #18383a; +} + +.oc-waterfall-detail .oc-cave-detail-safety { + background: #e1e9e5; +} + +.oc-waterfall-detail-gallery { + display: grid; + grid-template-columns: minmax(0, 1.08fr) minmax(0, .92fr); + grid-template-rows: repeat(2, 330px); + gap: 14px; + padding-bottom: 145px; +} + +.oc-waterfall-detail-gallery figure { + margin: 0; + overflow: hidden; + background: #cdd9d5; +} + +.oc-waterfall-detail-gallery figure.is-tall { + grid-row: 1 / 3; +} + +.oc-waterfall-detail-gallery img { + width: 100%; + height: 100%; + object-fit: cover; + filter: saturate(.84) contrast(.97); + transition: transform .7s ease; +} + +.oc-waterfall-detail-gallery figure:hover img { + transform: scale(1.018); +} + +.oc-waterfall-detail-gallery figure:nth-child(2) img { + object-position: center 47%; +} + +.oc-waterfall-detail-gallery figure:nth-child(3) img { + object-position: center 56%; +} + +.oc-waterfall-detail .oc-cave-detail-flow figure img { + object-position: center 54%; +} + +@media (max-width: 720px) { + .oc-waterfall-detail .oc-cave-detail-hero > img { + object-position: 55% center; + } + + .oc-waterfall-detail .oc-cave-detail-hero-copy h1 { + font-size: clamp(45px, 13.6vw, 62px); + } + + .oc-waterfall-detail-gallery { + grid-template-columns: 1fr; + grid-template-rows: 430px 300px 300px; + gap: 10px; + padding-bottom: 88px; + } + + .oc-waterfall-detail-gallery figure.is-tall { + grid-row: auto; + } +} + +/* Canyon river detail separates calm water, tracing, and white water within one consistent decision system. */ +.oc-river-detail { + --oc-cave-ink: #132b2c; + --oc-cave-moss: #173c3b; + --oc-cave-sage: #9fc5bd; + --oc-cave-paper: #eef4ef; + background: #f3f6f1; +} + +.oc-river-detail .oc-cave-detail-hero > img { + object-position: center 52%; + filter: saturate(.76) contrast(.96) brightness(.76); +} + +.oc-river-detail .oc-cave-detail-shade { + background: + linear-gradient(90deg, rgba(7, 25, 26, .88) 0%, rgba(7, 25, 26, .58) 44%, rgba(7, 25, 26, .08) 78%), + linear-gradient(0deg, rgba(7, 25, 26, .48) 0%, transparent 52%); +} + +.oc-river-detail .oc-cave-detail-hero-copy { + max-width: 1060px; +} + +.oc-river-detail .oc-cave-detail-hero-copy h1 { + max-width: 1030px; + font-size: clamp(48px, 5.55vw, 84px); + line-height: .95; +} + +.oc-river-detail .oc-cave-detail-hero-copy p { + max-width: 750px; +} + +.oc-river-detail .oc-cave-detail-levels { + background: #173c3b; +} + +.oc-river-detail .oc-cave-detail-safety { + background: #e3ece7; +} + +.oc-river-detail-gallery { + display: grid; + grid-template-columns: repeat(3, minmax(0, 1fr)); + grid-template-rows: repeat(2, 320px); + gap: 12px; + padding-bottom: 145px; +} + +.oc-river-detail-gallery figure { + margin: 0; + overflow: hidden; + background: #ceddd7; +} + +.oc-river-detail-gallery figure:first-child { + grid-column: 1 / 3; +} + +.oc-river-detail-gallery figure:nth-child(2) { + grid-column: 3; + grid-row: 1 / 3; +} + +.oc-river-detail-gallery img { + width: 100%; + height: 100%; + object-fit: cover; + filter: saturate(.82) contrast(.96); + transition: transform .7s ease; +} + +.oc-river-detail-gallery figure:hover img { + transform: scale(1.018); +} + +.oc-river-detail-gallery figure:first-child img { + object-position: center 54%; +} + +.oc-river-detail-gallery figure:nth-child(2) img { + object-position: center 54%; +} + +.oc-river-detail-gallery figure:nth-child(3) img { + object-position: center 64%; +} + +.oc-river-detail-gallery figure:nth-child(4) img { + object-position: center 58%; +} + +.oc-river-detail .oc-cave-detail-flow figure img { + object-position: center 60%; +} + +@media (max-width: 720px) { + .oc-river-detail .oc-cave-detail-hero > img { + object-position: 58% center; + } + + .oc-river-detail .oc-cave-detail-shade { + background: linear-gradient(0deg, rgba(7, 25, 26, .9) 0%, rgba(7, 25, 26, .45) 62%, rgba(7, 25, 26, .08) 100%); + } + + .oc-river-detail .oc-cave-detail-hero-copy h1 { + font-size: clamp(41px, 11.8vw, 55px); + line-height: .96; + } + + .oc-river-detail-gallery { + grid-template-columns: 1fr; + grid-template-rows: 300px 430px 330px 330px; + gap: 10px; + padding-bottom: 88px; + } + + .oc-river-detail-gallery figure:first-child, + .oc-river-detail-gallery figure:nth-child(2) { + grid-column: auto; + grid-row: auto; + } +} + +/* Karst hiking and cycling uses a dry-land palette and separates three distant regions into distinct products. */ +.oc-hike-detail { + --oc-cave-ink: #263126; + --oc-cave-moss: #34452f; + --oc-cave-sage: #c2c997; + --oc-cave-paper: #f3f0e6; + background: #f6f3e9; +} + +.oc-hike-detail .oc-cave-detail-hero > img { + object-position: center 48%; + filter: saturate(.78) contrast(.96) brightness(.8); +} + +.oc-hike-detail .oc-cave-detail-shade { + background: + linear-gradient(90deg, rgba(24, 30, 20, .88) 0%, rgba(24, 30, 20, .55) 45%, rgba(24, 30, 20, .06) 78%), + linear-gradient(0deg, rgba(24, 30, 20, .5) 0%, transparent 54%); +} + +.oc-hike-detail .oc-cave-detail-hero-copy { + max-width: 1060px; +} + +.oc-hike-detail .oc-cave-detail-hero-copy h1 { + max-width: 1050px; + font-size: clamp(48px, 5.35vw, 82px); + line-height: .96; +} + +.oc-hike-detail .oc-cave-detail-hero-copy p { + max-width: 740px; +} + +.oc-hike-detail .oc-cave-detail-levels { + background: #34452f; +} + +.oc-hike-detail .oc-cave-detail-safety { + background: #ebe8da; +} + +.oc-hike-detail-gallery { + display: grid; + grid-template-columns: 1.1fr .9fr 1fr; + grid-template-rows: 640px; + gap: 12px; + padding-bottom: 145px; +} + +.oc-hike-detail-gallery figure { + margin: 0; + overflow: hidden; + background: #d8d7c1; +} + +.oc-hike-detail-gallery img { + width: 100%; + height: 100%; + object-fit: cover; + filter: saturate(.82) contrast(.96); + transition: transform .7s ease; +} + +.oc-hike-detail-gallery figure:hover img { + transform: scale(1.018); +} + +.oc-hike-detail-gallery figure:first-child img { + object-position: center 55%; +} + +.oc-hike-detail-gallery figure:nth-child(2) img { + object-position: center 48%; +} + +.oc-hike-detail-gallery figure:nth-child(3) img { + object-position: center 56%; +} + +.oc-hike-detail .oc-cave-detail-flow figure img { + object-position: center 60%; +} + +@media (max-width: 720px) { + .oc-hike-detail .oc-cave-detail-hero > img { + object-position: 58% center; + } + + .oc-hike-detail .oc-cave-detail-shade { + background: linear-gradient(0deg, rgba(24, 30, 20, .9) 0%, rgba(24, 30, 20, .42) 62%, rgba(24, 30, 20, .05) 100%); + } + + .oc-hike-detail .oc-cave-detail-hero-copy h1 { + font-size: clamp(40px, 11.4vw, 53px); + line-height: .98; + } + + .oc-hike-detail-gallery { + grid-template-columns: 1fr; + grid-template-rows: 410px 410px 460px; + gap: 10px; + padding-bottom: 88px; + } +} + +/* High-bridge review page is intentionally evidentiary rather than a direct-booking product page. */ +.oc-bridge-detail { + --oc-cave-ink: #2f2b27; + --oc-cave-moss: #4a2f27; + --oc-cave-sage: #d9a47e; + --oc-cave-paper: #f4eee8; + background: #f6f1eb; +} + +.oc-bridge-detail .oc-cave-detail-hero > img { + object-position: center 56%; + filter: saturate(.72) contrast(.98) brightness(.73); +} + +.oc-bridge-detail .oc-cave-detail-shade { + background: + linear-gradient(90deg, rgba(27, 20, 18, .91) 0%, rgba(37, 24, 20, .62) 47%, rgba(37, 24, 20, .08) 80%), + linear-gradient(0deg, rgba(28, 20, 18, .55) 0%, transparent 55%); +} + +.oc-bridge-detail .oc-cave-detail-hero-copy { + max-width: 1110px; +} + +.oc-bridge-detail .oc-cave-detail-hero-copy h1 { + max-width: 1080px; + font-size: clamp(47px, 5.25vw, 81px); + line-height: .96; +} + +.oc-bridge-detail .oc-cave-detail-hero-copy p { + max-width: 780px; +} + +.oc-bridge-detail .oc-cave-detail-levels { + background: #4a2f27; +} + +.oc-bridge-detail .oc-cave-detail-safety { + background: #eee5dc; +} + +.oc-bridge-detail-gallery { + display: grid; + grid-template-columns: .9fr 1.1fr 1fr; + grid-template-rows: 660px; + gap: 12px; + padding-bottom: 145px; +} + +.oc-bridge-detail-gallery figure { + margin: 0; + overflow: hidden; + background: #d8cbc2; +} + +.oc-bridge-detail-gallery img { + width: 100%; + height: 100%; + object-fit: cover; + filter: saturate(.82) contrast(.98); + transition: transform .7s ease; +} + +.oc-bridge-detail-gallery figure:hover img { + transform: scale(1.018); +} + +.oc-bridge-detail-gallery figure:first-child img { + object-position: center 46%; +} + +.oc-bridge-detail-gallery figure:nth-child(2) img { + object-position: center 58%; +} + +.oc-bridge-detail-gallery figure:nth-child(3) img { + object-position: center 50%; +} + +.oc-bridge-detail .oc-cave-detail-flow figure img { + object-position: center 52%; +} + +.oc-bridge-detail-source { + max-width: 930px; + margin: 34px auto 0; + padding-top: 22px; + border-top: 1px solid rgba(78, 53, 43, .16); + color: #776960; + font-size: 10px; + line-height: 1.75; + text-align: center; +} + +@media (max-width: 720px) { + .oc-bridge-detail .oc-cave-detail-hero > img { + object-position: 51% center; + } + + .oc-bridge-detail .oc-cave-detail-shade { + background: linear-gradient(0deg, rgba(27, 20, 18, .92) 0%, rgba(37, 24, 20, .52) 64%, rgba(37, 24, 20, .08) 100%); + } + + .oc-bridge-detail .oc-cave-detail-hero-copy h1 { + font-size: clamp(38px, 10.8vw, 51px); + line-height: .99; + } + + .oc-bridge-detail-gallery { + grid-template-columns: 1fr; + grid-template-rows: 430px 480px 430px; + gap: 10px; + padding-bottom: 88px; + } +} + +/* Cave hospitality uses warm mineral tones while keeping venue and operating boundaries explicit. */ +.oc-cave-luxury-detail { + --oc-cave-ink: #302923; + --oc-cave-moss: #4a392c; + --oc-cave-sage: #d1ad79; + --oc-cave-paper: #f4eee5; + background: #f7f2e9; +} + +.oc-cave-luxury-detail .oc-cave-detail-hero > img { + object-position: center 58%; + filter: saturate(.76) contrast(.98) brightness(.74); +} + +.oc-cave-luxury-detail .oc-cave-detail-shade { + background: + linear-gradient(90deg, rgba(24, 18, 14, .92) 0%, rgba(36, 27, 20, .59) 48%, rgba(36, 27, 20, .08) 82%), + linear-gradient(0deg, rgba(25, 19, 15, .55) 0%, transparent 55%); +} + +.oc-cave-luxury-detail .oc-cave-detail-hero-copy { + max-width: 1120px; +} + +.oc-cave-luxury-detail .oc-cave-detail-hero-copy h1 { + max-width: 1080px; + font-size: clamp(45px, 5.1vw, 78px); + line-height: .97; +} + +.oc-cave-luxury-detail .oc-cave-detail-hero-copy p { + max-width: 760px; +} + +.oc-cave-luxury-detail .oc-cave-detail-levels { + background: #4a392c; +} + +.oc-cave-luxury-detail .oc-cave-detail-safety { + background: #eee5d8; +} + +.oc-cave-luxury-gallery { + display: grid; + grid-template-columns: .95fr .9fr 1.15fr; + grid-template-rows: 650px; + gap: 12px; + padding-bottom: 145px; +} + +.oc-cave-luxury-gallery figure { + margin: 0; + overflow: hidden; + background: #d7cbbb; +} + +.oc-cave-luxury-gallery img { + width: 100%; + height: 100%; + object-fit: cover; + filter: saturate(.82) contrast(.98); + transition: transform .7s ease; +} + +.oc-cave-luxury-gallery figure:hover img { + transform: scale(1.018); +} + +.oc-cave-luxury-gallery figure:first-child img { + object-position: center 58%; +} + +.oc-cave-luxury-gallery figure:nth-child(2) img { + object-position: center 52%; +} + +.oc-cave-luxury-gallery figure:nth-child(3) img { + object-position: center 58%; +} + +.oc-cave-luxury-detail .oc-cave-detail-flow figure img { + object-position: center 54%; +} + +@media (max-width: 720px) { + .oc-cave-luxury-detail .oc-cave-detail-hero > img { + object-position: 58% center; + } + + .oc-cave-luxury-detail .oc-cave-detail-shade { + background: linear-gradient(0deg, rgba(24, 18, 14, .93) 0%, rgba(36, 27, 20, .5) 64%, rgba(36, 27, 20, .08) 100%); + } + + .oc-cave-luxury-detail .oc-cave-detail-hero-copy h1 { + font-size: clamp(37px, 10.5vw, 50px); + line-height: .99; + } + + .oc-cave-luxury-gallery { + grid-template-columns: 1fr; + grid-template-rows: 460px 420px 460px; + gap: 10px; + padding-bottom: 88px; + } +} + +/* Mountain-view coffee keeps a grounded café palette and makes site authority more important than exclusivity claims. */ +.oc-wild-coffee-detail { + --oc-cave-ink: #283229; + --oc-cave-moss: #344438; + --oc-cave-sage: #c7b78e; + --oc-cave-paper: #f2efe5; + background: #f6f3eb; +} + +.oc-wild-coffee-detail .oc-cave-detail-hero > img { + object-position: center 48%; + filter: saturate(.78) contrast(.97) brightness(.77); +} + +.oc-wild-coffee-detail .oc-cave-detail-shade { + background: + linear-gradient(90deg, rgba(19, 27, 21, .9) 0%, rgba(27, 37, 29, .58) 47%, rgba(27, 37, 29, .07) 80%), + linear-gradient(0deg, rgba(20, 29, 22, .51) 0%, transparent 56%); +} + +.oc-wild-coffee-detail .oc-cave-detail-hero-copy { + max-width: 1100px; +} + +.oc-wild-coffee-detail .oc-cave-detail-hero-copy h1 { + max-width: 1030px; + font-size: clamp(48px, 5.35vw, 82px); + line-height: .96; +} + +.oc-wild-coffee-detail .oc-cave-detail-hero-copy p { + max-width: 760px; +} + +.oc-wild-coffee-detail .oc-cave-detail-levels { + background: #344438; +} + +.oc-wild-coffee-detail .oc-cave-detail-safety { + background: #e7e8df; +} + +.oc-wild-coffee-gallery { + display: grid; + grid-template-columns: repeat(3, minmax(0, 1fr)); + grid-template-rows: repeat(2, 315px); + gap: 12px; + padding-bottom: 145px; +} + +.oc-wild-coffee-gallery figure { + margin: 0; + overflow: hidden; + background: #ccd2c5; +} + +.oc-wild-coffee-gallery figure:first-child { + grid-row: 1 / 3; +} + +.oc-wild-coffee-gallery figure:nth-child(2) { + grid-column: 2 / 4; +} + +.oc-wild-coffee-gallery img { + width: 100%; + height: 100%; + object-fit: cover; + filter: saturate(.82) contrast(.97); + transition: transform .7s ease; +} + +.oc-wild-coffee-gallery figure:hover img { + transform: scale(1.018); +} + +.oc-wild-coffee-gallery figure:first-child img { + object-position: center 54%; +} + +.oc-wild-coffee-gallery figure:nth-child(2) img { + object-position: center 50%; +} + +.oc-wild-coffee-gallery figure:nth-child(3) img { + object-position: center 42%; +} + +.oc-wild-coffee-gallery figure:nth-child(4) img { + object-position: center 52%; +} + +.oc-wild-coffee-detail .oc-cave-detail-flow figure img { + object-position: center 58%; +} + +@media (max-width: 720px) { + .oc-wild-coffee-detail .oc-cave-detail-hero > img { + object-position: 54% center; + } + + .oc-wild-coffee-detail .oc-cave-detail-shade { + background: linear-gradient(0deg, rgba(19, 27, 21, .92) 0%, rgba(27, 37, 29, .48) 64%, rgba(27, 37, 29, .06) 100%); + } + + .oc-wild-coffee-detail .oc-cave-detail-hero-copy h1 { + font-size: clamp(40px, 11.2vw, 53px); + line-height: .98; + } + + .oc-wild-coffee-gallery { + grid-template-columns: 1fr; + grid-template-rows: 450px 420px 390px 450px; + gap: 10px; + padding-bottom: 88px; + } + + .oc-wild-coffee-gallery figure:first-child, + .oc-wild-coffee-gallery figure:nth-child(2) { + grid-column: auto; + grid-row: auto; + } +} + +/* Village immersion uses timber, indigo, and field tones while keeping consent and hosting evidence visible. */ +.oc-village-immersion-detail { + --oc-cave-ink: #2b2e2b; + --oc-cave-moss: #343d39; + --oc-cave-sage: #b9aa87; + --oc-cave-paper: #f1ede3; + background: #f5f1e9; +} + +.oc-village-immersion-detail .oc-cave-detail-hero > img { + object-position: center 48%; + filter: saturate(.68) contrast(.99) brightness(.68); +} + +.oc-village-immersion-detail .oc-cave-detail-shade { + background: + linear-gradient(90deg, rgba(24, 26, 25, .9) 0%, rgba(32, 34, 32, .6) 47%, rgba(32, 34, 32, .08) 81%), + linear-gradient(0deg, rgba(28, 27, 24, .5) 0%, transparent 56%); +} + +.oc-village-immersion-detail .oc-cave-detail-hero-copy { + max-width: 1160px; +} + +.oc-village-immersion-detail .oc-cave-detail-hero-copy h1 { + max-width: 1110px; + font-size: clamp(46px, 5.15vw, 80px); + line-height: .97; +} + +.oc-village-immersion-detail .oc-cave-detail-hero-copy p { + max-width: 780px; +} + +.oc-village-immersion-detail .oc-cave-detail-levels { + background: #343d39; +} + +.oc-village-immersion-detail .oc-cave-detail-safety { + background: #e9e3d8; +} + +.oc-village-immersion-gallery { + display: grid; + grid-template-columns: 1.04fr .96fr .96fr; + grid-template-rows: repeat(2, 315px); + gap: 12px; + padding-bottom: 145px; +} + +.oc-village-immersion-gallery figure { + position: relative; + margin: 0; + overflow: hidden; + background: #cac2b5; +} + +.oc-village-immersion-gallery figcaption { + position: absolute; + right: 0; + bottom: 0; + left: 0; + z-index: 1; + padding: 34px 18px 15px; + background: linear-gradient(0deg, rgba(26, 29, 27, .84), rgba(26, 29, 27, 0)); + color: rgba(255, 255, 255, .88); + font-size: 10px; + line-height: 1.55; + letter-spacing: .035em; +} + +.oc-village-immersion-gallery figure:first-child { + grid-row: 1 / 3; +} + +.oc-village-immersion-gallery figure:nth-child(2) { + grid-column: 2 / 4; +} + +.oc-village-immersion-gallery img { + width: 100%; + height: 100%; + object-fit: cover; + filter: saturate(.76) contrast(.98); + transition: transform .7s ease; +} + +.oc-village-immersion-gallery figure:hover img { + transform: scale(1.018); +} + +.oc-village-immersion-gallery figure:first-child img { + object-position: center 49%; +} + +.oc-village-immersion-gallery figure:nth-child(2) img { + object-position: center 55%; +} + +.oc-village-immersion-gallery figure:nth-child(3) img { + object-position: center 54%; +} + +.oc-village-immersion-gallery figure:nth-child(4) img { + object-position: center 61%; +} + +.oc-village-immersion-detail .oc-cave-detail-flow figure img { + object-position: center 52%; +} + +.oc-village-detail-source { + max-width: 940px; + margin: 34px auto 0; + padding-top: 22px; + border-top: 1px solid rgba(57, 52, 44, .16); + color: #756d62; + font-size: 10px; + line-height: 1.75; + text-align: center; +} + +@media (max-width: 720px) { + .oc-village-immersion-detail .oc-cave-detail-hero > img { + object-position: 51% center; + } + + .oc-village-immersion-detail .oc-cave-detail-shade { + background: linear-gradient(0deg, rgba(24, 26, 25, .94) 0%, rgba(32, 34, 32, .5) 65%, rgba(32, 34, 32, .07) 100%); + } + + .oc-village-immersion-detail .oc-cave-detail-hero-copy h1 { + font-size: clamp(37px, 10.3vw, 49px); + line-height: .99; + } + + .oc-village-immersion-gallery { + grid-template-columns: 1fr; + grid-template-rows: 470px 420px 430px 460px; + gap: 10px; + padding-bottom: 88px; + } + + .oc-village-immersion-gallery figure:first-child, + .oc-village-immersion-gallery figure:nth-child(2) { + grid-column: auto; + grid-row: auto; + } +} + +/* Festival detail keeps ceremonial colour restrained and foregrounds annual verification. */ +.oc-festival-detail { + --oc-cave-ink: #302720; + --oc-cave-moss: #49342d; + --oc-cave-sage: #c3a57d; + --oc-cave-paper: #f3eee4; + background: #f7f2e9; +} + +.oc-festival-detail .oc-cave-detail-hero > img { + object-position: center 42%; + filter: saturate(.66) contrast(1.02) brightness(.62); +} + +.oc-festival-detail .oc-cave-detail-shade { + background: + linear-gradient(90deg, rgba(35, 24, 20, .92) 0%, rgba(47, 31, 26, .64) 48%, rgba(47, 31, 26, .1) 82%), + linear-gradient(0deg, rgba(36, 24, 20, .56) 0%, transparent 58%); +} + +.oc-festival-detail .oc-cave-detail-hero-copy { + max-width: 1120px; +} + +.oc-festival-detail .oc-cave-detail-hero-copy h1 { + max-width: 1080px; + font-size: clamp(49px, 6vw, 92px); +} + +.oc-festival-detail .oc-cave-detail-levels { + background: #49342d; +} + +.oc-festival-detail .oc-cave-detail-level-grid { + grid-template-columns: repeat(2, minmax(0, 1fr)); +} + +.oc-festival-detail .oc-cave-detail-level-grid article { + min-height: 440px; + border-bottom: 1px solid rgba(255, 255, 255, .18); +} + +.oc-festival-detail .oc-cave-detail-level-grid article:nth-child(odd) { + border-left: 0; +} + +.oc-festival-detail .oc-cave-detail-level-grid h3 { + min-height: 76px; +} + +.oc-festival-detail .oc-cave-detail-safety { + background: #ece3d7; +} + +.oc-festival-gallery figure:first-child img { + object-position: center 34%; +} + +.oc-festival-gallery figure:nth-child(2) img { + object-position: center 48%; +} + +.oc-festival-gallery figure:nth-child(3) img, +.oc-festival-gallery figure:nth-child(4) img { + object-position: center 34%; +} + +.oc-festival-detail .oc-cave-detail-flow figure img { + object-position: center 28%; +} + +@media (max-width: 1024px) { + .oc-festival-detail .oc-cave-detail-level-grid { + grid-template-columns: 1fr; + } + + .oc-festival-detail .oc-cave-detail-level-grid article, + .oc-festival-detail .oc-cave-detail-level-grid article:nth-child(odd) { + min-height: 0; + border-left: 0; + } +} + +@media (max-width: 720px) { + .oc-festival-detail .oc-cave-detail-hero > img { + object-position: 47% center; + } + + .oc-festival-detail .oc-cave-detail-shade { + background: linear-gradient(0deg, rgba(35, 24, 20, .96) 0%, rgba(47, 31, 26, .48) 68%, rgba(47, 31, 26, .1) 100%); + } + + .oc-festival-detail .oc-cave-detail-hero-copy h1 { + font-size: clamp(40px, 11vw, 54px); + } +} + +/* Culinary detail uses warm clay and tea tones while keeping food and hosting checks explicit. */ +.oc-culinary-detail { + --oc-cave-ink: #302a24; + --oc-cave-moss: #443229; + --oc-cave-sage: #c59b68; + --oc-cave-paper: #f3eee5; + background: #f8f3ea; +} + +.oc-culinary-detail .oc-cave-detail-hero > img { + object-position: center 58%; + filter: saturate(.72) contrast(1.02) brightness(.62); +} + +.oc-culinary-detail .oc-cave-detail-shade { + background: + linear-gradient(90deg, rgba(38, 26, 20, .94) 0%, rgba(50, 35, 27, .68) 48%, rgba(50, 35, 27, .08) 84%), + linear-gradient(0deg, rgba(39, 26, 20, .5) 0%, transparent 58%); +} + +.oc-culinary-detail .oc-cave-detail-hero-copy { + max-width: 1160px; +} + +.oc-culinary-detail .oc-cave-detail-hero-copy h1 { + max-width: 1120px; + font-size: clamp(48px, 6vw, 90px); +} + +.oc-culinary-detail .oc-cave-detail-levels { + background: #443229; +} + +.oc-culinary-detail .oc-cave-detail-level-grid article { + min-height: 510px; +} + +.oc-culinary-detail .oc-cave-detail-safety { + background: #eee3d4; +} + +.oc-culinary-gallery figure:first-child img, +.oc-culinary-gallery figure:nth-child(2) img, +.oc-culinary-gallery figure:nth-child(3) img { + object-position: center 52%; +} + +.oc-culinary-gallery figure:nth-child(4) img, +.oc-culinary-detail .oc-cave-detail-flow figure img { + object-position: center 42%; +} + +.oc-culinary-street-food { + background: #e9ddcd; + padding: 135px 0 145px; +} + +.oc-culinary-street-food .oc-cave-detail-section-head { + max-width: 930px; +} + +.oc-culinary-street-food .oc-cave-detail-section-head > span { + color: #8b6748; +} + +.oc-culinary-street-food-grid { + border-bottom: 1px solid rgba(69, 48, 36, .16); + border-top: 1px solid rgba(69, 48, 36, .16); + display: grid; + grid-template-columns: repeat(2, minmax(0, 1fr)); + margin-top: 70px; +} + +.oc-culinary-street-food-grid article { + display: flex; + flex-direction: column; + min-height: 475px; + padding: 48px clamp(28px, 4.5vw, 64px) 44px; +} + +.oc-culinary-street-food-grid article:nth-child(even) { + border-left: 1px solid rgba(69, 48, 36, .16); +} + +.oc-culinary-street-food-grid article:nth-child(n+3) { + border-top: 1px solid rgba(69, 48, 36, .16); +} + +.oc-culinary-street-food-grid article:last-child { + grid-column: 1 / -1; + min-height: 390px; +} + +.oc-culinary-street-food-grid article > div { + align-items: center; + color: #806c5d; + display: flex; + font-size: 10px; + font-weight: 800; + gap: 18px; + letter-spacing: .08em; + text-transform: uppercase; +} + +.oc-culinary-street-food-grid article > div span { + color: #b07a51; +} + +.oc-culinary-street-food-grid h3 { + color: #342b25; + font-family: var(--oc-serif); + font-size: clamp(32px, 3.2vw, 48px); + font-weight: 400; + letter-spacing: -.035em; + line-height: 1.04; + margin: 44px 0 0; +} + +.oc-culinary-street-food-grid p { + color: #65594f; + font-size: 15px; + line-height: 1.72; + margin: 25px 0 0; +} + +.oc-culinary-street-food-grid small { + border-top: 1px solid rgba(69, 48, 36, .14); + color: #7a6657; + display: block; + font-size: 11px; + line-height: 1.6; + margin-top: auto; + padding-top: 23px; +} + +.oc-culinary-market-note { + align-items: start; + background: #443229; + color: #fff; + display: grid; + gap: clamp(38px, 7vw, 100px); + grid-template-columns: minmax(260px, .72fr) minmax(0, 1.28fr); + margin-top: 70px; + padding: clamp(42px, 5vw, 70px); +} + +.oc-culinary-market-note span { + color: #d0a87d; + display: block; + font-size: 10px; + font-weight: 800; + letter-spacing: .16em; + text-transform: uppercase; +} + +.oc-culinary-market-note h3 { + font-family: var(--oc-serif); + font-size: clamp(32px, 3vw, 46px); + font-weight: 400; + letter-spacing: -.035em; + line-height: 1.05; + margin: 24px 0 0; +} + +.oc-culinary-market-note p { + color: rgba(255, 255, 255, .7); + font-size: 15px; + line-height: 1.75; + margin: 0; +} + +@media (max-width: 900px) { + .oc-culinary-street-food-grid, + .oc-culinary-market-note { + grid-template-columns: 1fr; + } + + .oc-culinary-street-food-grid article, + .oc-culinary-street-food-grid article:last-child { + grid-column: auto; + min-height: 0; + } + + .oc-culinary-street-food-grid article:nth-child(even) { + border-left: 0; + } + + .oc-culinary-street-food-grid article:nth-child(n+2) { + border-top: 1px solid rgba(69, 48, 36, .16); + } +} + +@media (max-width: 720px) { + .oc-culinary-detail .oc-cave-detail-hero > img { + object-position: 58% center; + } + + .oc-culinary-detail .oc-cave-detail-shade { + background: linear-gradient(0deg, rgba(38, 26, 20, .97) 0%, rgba(50, 35, 27, .52) 70%, rgba(50, 35, 27, .1) 100%); + } + + .oc-culinary-detail .oc-cave-detail-hero-copy h1 { + font-size: clamp(38px, 10.5vw, 52px); + } + + .oc-culinary-street-food { + padding: 88px 0; + } + + .oc-culinary-street-food-grid { + margin-top: 48px; + } + + .oc-culinary-street-food-grid article { + padding: 40px 8px; + } + + .oc-culinary-street-food-grid h3 { + margin-top: 34px; + } + + .oc-culinary-street-food-grid small { + margin-top: 28px; + } + + .oc-culinary-market-note { + gap: 28px; + margin-top: 48px; + padding: 38px 24px 42px; + } +} + +/* Waterfall clusters use a cool mineral palette and foreground live access over fixed postcard promises. */ +.oc-iconic-waterfall-detail { + --oc-cave-ink: #20302e; + --oc-cave-moss: #24413d; + --oc-cave-sage: #9cc5bd; + --oc-cave-paper: #edf3f0; + background: #f2f6f3; +} + +.oc-iconic-waterfall-detail .oc-cave-detail-hero > img { + object-position: center 43%; + filter: saturate(.78) contrast(1.04) brightness(.64); +} + +.oc-iconic-waterfall-detail .oc-cave-detail-shade { + background: + linear-gradient(90deg, rgba(16, 31, 30, .94) 0%, rgba(22, 48, 45, .65) 50%, rgba(22, 48, 45, .08) 85%), + linear-gradient(0deg, rgba(14, 31, 29, .52) 0%, transparent 60%); +} + +.oc-iconic-waterfall-detail .oc-cave-detail-hero-copy { + max-width: 1180px; +} + +.oc-iconic-waterfall-detail .oc-cave-detail-hero-copy h1 { + max-width: 1140px; + font-size: clamp(48px, 6vw, 90px); +} + +.oc-iconic-waterfall-detail .oc-cave-detail-levels { + background: #24413d; +} + +.oc-iconic-waterfall-detail .oc-cave-detail-level-grid article { + min-height: 530px; +} + +.oc-iconic-waterfall-detail .oc-cave-detail-safety { + background: #e2ece8; +} + +.oc-iconic-waterfall-gallery figure:first-child img, +.oc-iconic-waterfall-gallery figure:nth-child(2) img { + object-position: center 40%; +} + +.oc-iconic-waterfall-gallery figure:nth-child(3) img { + object-position: center 48%; +} + +.oc-iconic-waterfall-gallery figure:nth-child(4) img, +.oc-iconic-waterfall-detail .oc-cave-detail-flow figure img { + object-position: center 35%; +} + +@media (max-width: 720px) { + .oc-iconic-waterfall-detail .oc-cave-detail-hero > img { + object-position: 52% center; + } + + .oc-iconic-waterfall-detail .oc-cave-detail-shade { + background: linear-gradient(0deg, rgba(16, 31, 30, .97) 0%, rgba(22, 48, 45, .5) 70%, rgba(22, 48, 45, .08) 100%); + } + + .oc-iconic-waterfall-detail .oc-cave-detail-hero-copy h1 { + font-size: clamp(38px, 10.5vw, 52px); + } +} + +/* Village comparison uses timber, indigo, and rice-field tones while separating public visits from community hosting. */ +.oc-indigenous-villages-detail { + --oc-cave-ink: #2f342d; + --oc-cave-moss: #344a40; + --oc-cave-sage: #b9b17f; + --oc-cave-paper: #f1efe7; + background: #f6f3ec; +} + +.oc-indigenous-villages-detail .oc-cave-detail-hero > img { + object-position: center 48%; + filter: saturate(.72) contrast(1.02) brightness(.63); +} + +.oc-indigenous-villages-detail .oc-cave-detail-shade { + background: + linear-gradient(90deg, rgba(22, 29, 25, .94) 0%, rgba(33, 50, 43, .65) 52%, rgba(34, 50, 43, .08) 85%), + linear-gradient(0deg, rgba(20, 28, 24, .52) 0%, transparent 60%); +} + +.oc-indigenous-villages-detail .oc-cave-detail-hero-copy { + max-width: 1180px; +} + +.oc-indigenous-villages-detail .oc-cave-detail-hero-copy h1 { + max-width: 1180px; + font-size: clamp(47px, 5.8vw, 88px); +} + +.oc-indigenous-villages-detail .oc-cave-detail-levels { + background: #344a40; +} + +.oc-indigenous-villages-detail .oc-cave-detail-level-grid { + grid-template-columns: repeat(2, minmax(0, 1fr)); +} + +.oc-indigenous-villages-detail .oc-cave-detail-level-grid article { + min-height: 510px; +} + +.oc-indigenous-villages-detail .oc-cave-detail-level-grid article:nth-child(3) { + border-top: 1px solid rgba(255, 255, 255, .18); + border-left: 0; +} + +.oc-indigenous-villages-detail .oc-cave-detail-level-grid article:nth-child(4) { + border-top: 1px solid rgba(255, 255, 255, .18); +} + +.oc-indigenous-villages-detail .oc-cave-detail-safety { + background: #e8e4d8; +} + +.oc-indigenous-villages-detail .oc-cave-detail-route-grid { + grid-template-columns: repeat(2, minmax(0, 1fr)); +} + +.oc-indigenous-villages-detail .oc-cave-detail-route-grid a:nth-child(3) { + border-top: 1px solid rgba(32, 49, 39, .16); + border-left: 0; +} + +.oc-indigenous-villages-detail .oc-cave-detail-route-grid a:nth-child(4) { + border-top: 1px solid rgba(32, 49, 39, .16); +} + +.oc-indigenous-villages-gallery figure:first-child img { + object-position: center 58%; +} + +.oc-indigenous-villages-gallery figure:nth-child(2) img { + object-position: center 47%; +} + +.oc-indigenous-villages-gallery figure:nth-child(3) img, +.oc-indigenous-villages-gallery figure:nth-child(4) img, +.oc-indigenous-villages-detail .oc-cave-detail-flow figure img { + object-position: center 44%; +} + +@media (max-width: 1024px) { + .oc-indigenous-villages-detail .oc-cave-detail-level-grid { + grid-template-columns: 1fr; + } + + .oc-indigenous-villages-detail .oc-cave-detail-level-grid article { + min-height: 0; + } + + .oc-indigenous-villages-detail .oc-cave-detail-level-grid article:nth-child(4) { + border-left: 0; + } +} + +@media (max-width: 720px) { + .oc-indigenous-villages-detail .oc-cave-detail-hero > img { + object-position: 50% center; + } + + .oc-indigenous-villages-detail .oc-cave-detail-shade { + background: linear-gradient(0deg, rgba(22, 29, 25, .97) 0%, rgba(33, 50, 43, .53) 70%, rgba(33, 50, 43, .08) 100%); + } + + .oc-indigenous-villages-detail .oc-cave-detail-hero-copy h1 { + font-size: clamp(37px, 10.2vw, 50px); + } + + .oc-indigenous-villages-detail .oc-cave-detail-route-grid { + grid-template-columns: 1fr; + } + + .oc-indigenous-villages-detail .oc-cave-detail-route-grid a:nth-child(4) { + border-left: 0; + } +} + +/* Karst glamping uses a dusk palette while making shelter and operations more prominent than star promises. */ +.oc-historic-towns-detail { + --oc-cave-ink: #332f2a; + --oc-cave-moss: #493b32; + --oc-cave-sage: #c4aa79; + --oc-cave-paper: #f1ece3; + background: #f6f1e9; +} + +.oc-historic-towns-detail .oc-cave-detail-hero > img { + object-position: center 42%; + filter: saturate(.64) contrast(1.04) brightness(.61); +} + +.oc-historic-towns-detail .oc-cave-detail-shade { + background: + linear-gradient(90deg, rgba(24, 21, 19, .95) 0%, rgba(53, 39, 31, .66) 52%, rgba(53, 39, 31, .08) 84%), + linear-gradient(0deg, rgba(27, 21, 18, .58) 0%, transparent 62%); +} + +.oc-historic-towns-detail .oc-cave-detail-hero-copy { + max-width: 1200px; +} + +.oc-historic-towns-detail .oc-cave-detail-hero-copy h1 { + max-width: 1180px; + font-size: clamp(46px, 5.7vw, 86px); +} + +.oc-historic-towns-detail .oc-cave-detail-levels { + background: #493b32; +} + +.oc-historic-towns-detail .oc-cave-detail-level-grid article { + min-height: 550px; +} + +.oc-historic-towns-detail .oc-cave-detail-safety { + background: #e9e0d3; +} + +.oc-historic-towns-gallery figure:first-child img { + object-position: center 50%; +} + +.oc-historic-towns-gallery figure:nth-child(2) img, +.oc-historic-towns-detail .oc-cave-detail-flow figure img { + object-position: center 44%; +} + +.oc-historic-towns-gallery figure:nth-child(3) img, +.oc-historic-towns-gallery figure:nth-child(4) img { + object-position: center 48%; +} + +@media (max-width: 720px) { + .oc-historic-towns-detail .oc-cave-detail-hero > img { + object-position: 48% center; + } + + .oc-historic-towns-detail .oc-cave-detail-shade { + background: linear-gradient(0deg, rgba(24, 21, 19, .97) 0%, rgba(53, 39, 31, .54) 70%, rgba(53, 39, 31, .08) 100%); + } + + .oc-historic-towns-detail .oc-cave-detail-hero-copy h1 { + font-size: clamp(37px, 10vw, 50px); + } +} + +/* Qingyan's battle page separates a live 2026 field product from the brief's unbuilt old-town roleplay. */ +.oc-qingyan-battle-detail { + --oc-cave-ink: #302b25; + --oc-cave-moss: #42362d; + --oc-cave-sage: #bd9d67; + --oc-cave-paper: #f1ece2; + background: #f5f1e8; +} + +.oc-qingyan-battle-detail .oc-cave-detail-hero > img { + object-position: center 43%; + filter: saturate(.58) contrast(1.05) brightness(.56); +} + +.oc-qingyan-battle-detail .oc-cave-detail-shade { + background: + linear-gradient(90deg, rgba(24, 21, 18, .96) 0%, rgba(49, 39, 31, .7) 54%, rgba(49, 39, 31, .1) 86%), + linear-gradient(0deg, rgba(23, 19, 16, .62) 0%, transparent 62%); +} + +.oc-qingyan-battle-detail .oc-cave-detail-hero-copy { + max-width: 1210px; +} + +.oc-qingyan-battle-detail .oc-cave-detail-hero-copy h1 { + max-width: 1200px; + font-size: clamp(45px, 5.45vw, 84px); + line-height: .96; +} + +.oc-qingyan-battle-detail .oc-cave-detail-hero-copy p { + max-width: 810px; +} + +.oc-qingyan-battle-detail .oc-cave-detail-levels { + background: #42362d; +} + +.oc-qingyan-battle-detail .oc-cave-detail-level-grid article { + min-height: 590px; +} + +.oc-qingyan-battle-detail .oc-cave-detail-safety { + background: #e9e0d2; +} + +.oc-qingyan-battle-context { + display: grid; + grid-template-columns: 1.08fr .92fr; + grid-template-rows: 680px; + gap: 12px; + padding-bottom: 145px; +} + +.oc-qingyan-battle-context figure { + background: #d8cdbf; + margin: 0; + overflow: hidden; + position: relative; +} + +.oc-qingyan-battle-context img { + display: block; + filter: saturate(.7) contrast(1.02); + height: 100%; + object-fit: cover; + transition: transform .7s ease; + width: 100%; +} + +.oc-qingyan-battle-context figure:first-child img { + object-position: center 35%; +} + +.oc-qingyan-battle-context figure:nth-child(2) img, +.oc-qingyan-battle-detail .oc-cave-detail-flow figure img { + object-position: center 30%; +} + +.oc-qingyan-battle-context figure:hover img { + transform: scale(1.018); +} + +.oc-qingyan-battle-context figcaption { + background: linear-gradient(0deg, rgba(21, 18, 15, .86), rgba(21, 18, 15, .02)); + bottom: 0; + color: rgba(255, 255, 255, .86); + font-size: 11px; + left: 0; + line-height: 1.55; + padding: 70px 26px 22px; + position: absolute; + right: 0; +} + +.oc-qingyan-battle-source { + border-top: 1px solid rgba(72, 55, 43, .17); + color: #75685e; + font-size: 10px; + line-height: 1.75; + margin: 34px auto 0; + max-width: 990px; + padding-top: 22px; + text-align: center; +} + +@media (max-width: 720px) { + .oc-qingyan-battle-detail .oc-cave-detail-hero > img { + object-position: 48% center; + } + + .oc-qingyan-battle-detail .oc-cave-detail-shade { + background: linear-gradient(0deg, rgba(24, 21, 18, .97) 0%, rgba(49, 39, 31, .58) 70%, rgba(49, 39, 31, .08) 100%); + } + + .oc-qingyan-battle-detail .oc-cave-detail-hero-copy h1 { + font-size: clamp(36px, 9.8vw, 49px); + } + + .oc-qingyan-battle-context { + grid-template-columns: 1fr; + grid-template-rows: 410px 430px; + gap: 10px; + padding-bottom: 88px; + } +} + +/* Loushan Pass pairs a vivid live show with a restrained evidence-first mountain route review. */ +.oc-loushanguan-detail { + --oc-cave-ink: #2f2a24; + --oc-cave-moss: #433229; + --oc-cave-sage: #c29a67; + --oc-cave-paper: #f2ede3; + background: #f6f1e8; +} + +.oc-loushanguan-detail .oc-cave-detail-hero > img { + object-position: center 26%; + filter: saturate(.64) contrast(1.08) brightness(.52); +} + +.oc-loushanguan-detail .oc-cave-detail-shade { + background: + linear-gradient(90deg, rgba(25, 20, 17, .97) 0%, rgba(55, 37, 29, .72) 54%, rgba(55, 37, 29, .1) 86%), + linear-gradient(0deg, rgba(25, 19, 16, .68) 0%, transparent 64%); +} + +.oc-loushanguan-detail .oc-cave-detail-hero-copy { + max-width: 1240px; +} + +.oc-loushanguan-detail .oc-cave-detail-hero-copy h1 { + max-width: 1210px; + font-size: clamp(45px, 5.35vw, 82px); + line-height: .96; +} + +.oc-loushanguan-detail .oc-cave-detail-hero-copy p { + max-width: 835px; +} + +.oc-loushanguan-detail .oc-cave-detail-levels { + background: #433229; +} + +.oc-loushanguan-detail .oc-cave-detail-level-grid article { + min-height: 605px; +} + +.oc-loushanguan-detail .oc-cave-detail-safety { + background: #e9dfd1; +} + +.oc-loushanguan-evidence { + display: grid; + grid-template-columns: minmax(0, 1.08fr) minmax(420px, .92fr); + min-height: 720px; + padding-bottom: 145px; +} + +.oc-loushanguan-evidence figure { + margin: 0; + min-height: 720px; + overflow: hidden; + position: relative; +} + +.oc-loushanguan-evidence figure img { + display: block; + filter: saturate(.68) contrast(1.04); + height: 100%; + object-fit: cover; + object-position: center 23%; + width: 100%; +} + +.oc-loushanguan-evidence figcaption { + background: linear-gradient(0deg, rgba(23, 18, 15, .9), rgba(23, 18, 15, .02)); + bottom: 0; + color: rgba(255, 255, 255, .86); + font-size: 11px; + left: 0; + line-height: 1.55; + padding: 80px 28px 24px; + position: absolute; + right: 0; +} + +.oc-loushanguan-evidence aside { + align-content: center; + background: #e8ddce; + display: grid; + padding: clamp(48px, 6.5vw, 98px); +} + +.oc-loushanguan-evidence aside > span { + color: #82684e; + font-size: 10px; + font-weight: 800; + letter-spacing: .18em; + margin-bottom: 25px; + text-transform: uppercase; +} + +.oc-loushanguan-evidence aside h2 { + color: #342b24; + font-family: var(--oc-serif); + font-size: clamp(35px, 3.8vw, 57px); + font-weight: 400; + letter-spacing: -.04em; + line-height: 1.03; + margin: 0; +} + +.oc-loushanguan-evidence aside p { + color: #665a50; + font-size: 15px; + line-height: 1.75; + margin: 30px 0 0; +} + +.oc-loushanguan-detail .oc-cave-detail-flow figure img { + object-position: center 24%; +} + +.oc-loushanguan-source { + border-top: 1px solid rgba(72, 51, 39, .17); + color: #75675d; + font-size: 10px; + line-height: 1.75; + margin: 34px auto 0; + max-width: 1000px; + padding-top: 22px; + text-align: center; +} + +@media (max-width: 720px) { + .oc-loushanguan-detail .oc-cave-detail-hero > img { + object-position: 38% 18%; + } + + .oc-loushanguan-detail .oc-cave-detail-shade { + background: linear-gradient(0deg, rgba(25, 20, 17, .98) 0%, rgba(55, 37, 29, .62) 72%, rgba(55, 37, 29, .12) 100%); + } + + .oc-loushanguan-detail .oc-cave-detail-hero-copy h1 { + font-size: clamp(35px, 9.55vw, 48px); + } + + .oc-loushanguan-evidence { + grid-template-columns: 1fr; + min-height: 0; + padding-bottom: 88px; + } + + .oc-loushanguan-evidence figure { + min-height: 520px; + } + + .oc-loushanguan-evidence aside { + padding: 56px 26px 62px; + } +} + +/* Karst glamping uses a dusk palette while making shelter and operations more prominent than star promises. */ +.oc-karst-glamping-detail { + --oc-cave-ink: #222c32; + --oc-cave-moss: #25343d; + --oc-cave-sage: #b9a979; + --oc-cave-paper: #edf0ed; + background: #f2f3f0; +} + +.oc-karst-glamping-detail .oc-cave-detail-hero > img { + object-position: center 55%; + filter: saturate(.7) contrast(1.02) brightness(.66); +} + +.oc-karst-glamping-detail .oc-cave-detail-shade { + background: + linear-gradient(90deg, rgba(13, 22, 28, .91) 0%, rgba(20, 31, 38, .62) 48%, rgba(20, 31, 38, .09) 82%), + linear-gradient(0deg, rgba(14, 25, 31, .57) 0%, transparent 58%); +} + +.oc-karst-glamping-detail .oc-cave-detail-hero-copy { + max-width: 1160px; +} + +.oc-karst-glamping-detail .oc-cave-detail-hero-copy h1 { + max-width: 1120px; + font-size: clamp(45px, 5.05vw, 78px); + line-height: .97; +} + +.oc-karst-glamping-detail .oc-cave-detail-hero-copy p { + max-width: 760px; +} + +.oc-karst-glamping-detail .oc-cave-detail-levels { + background: #25343d; +} + +.oc-karst-glamping-detail .oc-cave-detail-safety { + background: #e5e8e5; +} + +.oc-karst-glamping-gallery { + display: grid; + grid-template-columns: 1.02fr .98fr .98fr; + grid-template-rows: repeat(2, 315px); + gap: 12px; + padding-bottom: 145px; +} + +.oc-karst-glamping-gallery figure { + margin: 0; + overflow: hidden; + background: #bcc5c8; +} + +.oc-karst-glamping-gallery figure:first-child { + grid-row: 1 / 3; +} + +.oc-karst-glamping-gallery figure:nth-child(2) { + grid-column: 2 / 4; +} + +.oc-karst-glamping-gallery img { + width: 100%; + height: 100%; + object-fit: cover; + filter: saturate(.78) contrast(.98); + transition: transform .7s ease; +} + +.oc-karst-glamping-gallery figure:hover img { + transform: scale(1.018); +} + +.oc-karst-glamping-gallery figure:first-child img { + object-position: center 54%; +} + +.oc-karst-glamping-gallery figure:nth-child(2) img { + object-position: center 46%; +} + +.oc-karst-glamping-gallery figure:nth-child(3) img { + object-position: center 53%; +} + +.oc-karst-glamping-gallery figure:nth-child(4) img { + object-position: center 45%; +} + +.oc-karst-glamping-detail .oc-cave-detail-flow figure img { + object-position: center 54%; +} + +.oc-glamping-detail-source { + max-width: 940px; + margin: 34px auto 0; + padding-top: 22px; + border-top: 1px solid rgba(39, 53, 60, .16); + color: #68747a; + font-size: 10px; + line-height: 1.75; + text-align: center; +} + +@media (max-width: 720px) { + .oc-karst-glamping-detail .oc-cave-detail-hero > img { + object-position: 51% center; + } + + .oc-karst-glamping-detail .oc-cave-detail-shade { + background: linear-gradient(0deg, rgba(13, 22, 28, .95) 0%, rgba(20, 31, 38, .53) 66%, rgba(20, 31, 38, .08) 100%); + } + + .oc-karst-glamping-detail .oc-cave-detail-hero-copy h1 { + font-size: clamp(36px, 9.9vw, 48px); + line-height: .99; + } + + .oc-karst-glamping-gallery { + grid-template-columns: 1fr; + grid-template-rows: 470px 420px 430px 460px; + gap: 10px; + padding-bottom: 88px; + } + + .oc-karst-glamping-gallery figure:first-child, + .oc-karst-glamping-gallery figure:nth-child(2) { + grid-column: auto; + grid-row: auto; + } +} + +/* Heritage-outdoor pairings balance indigo craft detail with green field context and label concept imagery explicitly. */ +.oc-heritage-outdoor-detail { + --oc-cave-ink: #28302d; + --oc-cave-moss: #293a36; + --oc-cave-sage: #b8a273; + --oc-cave-paper: #f1eee6; + background: #f5f2eb; +} + +.oc-heritage-outdoor-detail .oc-cave-detail-hero > img { + object-position: center 58%; + filter: saturate(.72) contrast(.99) brightness(.66); +} + +.oc-heritage-outdoor-detail .oc-cave-detail-shade { + background: + linear-gradient(90deg, rgba(18, 28, 25, .91) 0%, rgba(27, 39, 35, .61) 47%, rgba(27, 39, 35, .08) 81%), + linear-gradient(0deg, rgba(20, 31, 27, .55) 0%, transparent 58%); +} + +.oc-heritage-outdoor-detail .oc-cave-detail-hero-copy { + max-width: 1160px; +} + +.oc-heritage-outdoor-detail .oc-cave-detail-hero-copy h1 { + max-width: 1120px; + font-size: clamp(45px, 5.05vw, 78px); + line-height: .97; +} + +.oc-heritage-outdoor-detail .oc-cave-detail-hero-copy p { + max-width: 790px; +} + +.oc-heritage-outdoor-detail .oc-cave-detail-levels { + background: #293a36; +} + +.oc-heritage-outdoor-detail .oc-cave-detail-safety { + background: #e9e5dc; +} + +.oc-heritage-outdoor-gallery { + display: grid; + grid-template-columns: 1.02fr .98fr .98fr; + grid-template-rows: repeat(2, 315px); + gap: 12px; + padding-bottom: 145px; +} + +.oc-heritage-outdoor-gallery figure { + position: relative; + margin: 0; + overflow: hidden; + background: #c8c3b8; +} + +.oc-heritage-outdoor-gallery figure:first-child { + grid-row: 1 / 3; +} + +.oc-heritage-outdoor-gallery figure:nth-child(2) { + grid-column: 2 / 4; +} + +.oc-heritage-outdoor-gallery img { + width: 100%; + height: 100%; + object-fit: cover; + filter: saturate(.78) contrast(.98); + transition: transform .7s ease; +} + +.oc-heritage-outdoor-gallery figure:hover img { + transform: scale(1.018); +} + +.oc-heritage-outdoor-gallery figure:first-child img { + object-position: center 59%; +} + +.oc-heritage-outdoor-gallery figure:nth-child(2) img { + object-position: center 52%; +} + +.oc-heritage-outdoor-gallery figure:nth-child(3) img { + object-position: center 48%; +} + +.oc-heritage-outdoor-gallery figure:nth-child(4) img { + object-position: center 57%; +} + +.oc-heritage-outdoor-gallery figcaption { + position: absolute; + right: 14px; + bottom: 14px; + left: 14px; + padding: 11px 13px; + background: rgba(25, 31, 34, .78); + color: rgba(255, 255, 255, .86); + font-size: 9px; + font-weight: 700; + line-height: 1.4; + letter-spacing: .08em; + text-transform: uppercase; + backdrop-filter: blur(7px); +} + +.oc-heritage-outdoor-detail .oc-cave-detail-flow figure img { + object-position: center 53%; +} + +.oc-heritage-outdoor-source { + max-width: 950px; + margin: 34px auto 0; + padding-top: 22px; + border-top: 1px solid rgba(45, 54, 50, .16); + color: #716d65; + font-size: 10px; + line-height: 1.75; + text-align: center; +} + +@media (max-width: 720px) { + .oc-heritage-outdoor-detail .oc-cave-detail-hero > img { + object-position: 53% center; + } + + .oc-heritage-outdoor-detail .oc-cave-detail-shade { + background: linear-gradient(0deg, rgba(18, 28, 25, .95) 0%, rgba(27, 39, 35, .53) 66%, rgba(27, 39, 35, .08) 100%); + } + + .oc-heritage-outdoor-detail .oc-cave-detail-hero-copy h1 { + font-size: clamp(36px, 9.8vw, 48px); + line-height: .99; + } + + .oc-heritage-outdoor-gallery { + grid-template-columns: 1fr; + grid-template-rows: 470px 420px 450px 470px; + gap: 10px; + padding-bottom: 88px; + } + + .oc-heritage-outdoor-gallery figure:first-child, + .oc-heritage-outdoor-gallery figure:nth-child(2) { + grid-column: auto; + grid-row: auto; + } +} + +/* Miao craft detail keeps the proven information architecture while shifting the visual language to indigo, cloth, and studio light. */ +.oc-miao-craft-detail { + --oc-cave-ink: #27302d; + --oc-cave-moss: #29444a; + --oc-cave-sage: #c8ae76; + --oc-cave-paper: #f2eee5; + background: #f7f3eb; +} + +.oc-miao-craft-detail .oc-cave-detail-hero > img { + object-position: center 49%; + filter: saturate(.7) contrast(.98) brightness(.64); +} + +.oc-miao-craft-detail .oc-cave-detail-shade { + background: + linear-gradient(90deg, rgba(20, 30, 30, .93) 0%, rgba(26, 44, 46, .67) 47%, rgba(26, 44, 46, .1) 82%), + linear-gradient(0deg, rgba(20, 30, 30, .54) 0%, transparent 59%); +} + +.oc-miao-craft-detail .oc-cave-detail-hero-copy { + max-width: 1060px; +} + +.oc-miao-craft-detail .oc-cave-detail-hero-copy h1 { + max-width: 1010px; + font-size: clamp(48px, 5.7vw, 86px); + line-height: .96; +} + +.oc-miao-craft-detail .oc-cave-detail-hero-copy p { + max-width: 760px; +} + +.oc-miao-craft-detail .oc-cave-detail-levels { + background: #29444a; +} + +.oc-miao-craft-detail .oc-cave-detail-safety { + background: #ebe6dc; +} + +.oc-miao-craft-gallery figure:first-child img { + object-position: center 42%; +} + +.oc-miao-craft-gallery figure:nth-child(2) img { + object-position: center 55%; +} + +.oc-miao-craft-gallery figure:nth-child(3) img { + object-position: center 43%; +} + +.oc-miao-craft-gallery figure:nth-child(4) img { + object-position: center 50%; +} + +.oc-miao-craft-detail .oc-cave-detail-flow figure img { + object-position: center 42%; +} + +@media (max-width: 720px) { + .oc-miao-craft-detail .oc-cave-detail-hero > img { + object-position: 52% center; + } + + .oc-miao-craft-detail .oc-cave-detail-shade { + background: linear-gradient(0deg, rgba(19, 31, 32, .96) 0%, rgba(26, 44, 46, .58) 68%, rgba(26, 44, 46, .08) 100%); + } + + .oc-miao-craft-detail .oc-cave-detail-hero-copy h1 { + font-size: clamp(38px, 10.2vw, 52px); + line-height: .99; + } +} + +/* Dong craft detail uses dark timber, mist green, and muted indigo while keeping every pictured place explicitly provisional. */ +.oc-dong-craft-detail { + --oc-cave-ink: #292f2b; + --oc-cave-moss: #2f3d37; + --oc-cave-sage: #b7a675; + --oc-cave-paper: #f0ede5; + background: #f5f2eb; +} + +.oc-dong-craft-detail .oc-cave-detail-hero > img { + object-position: center 52%; + filter: saturate(.67) contrast(.99) brightness(.63); +} + +.oc-dong-craft-detail .oc-cave-detail-shade { + background: + linear-gradient(90deg, rgba(18, 28, 24, .93) 0%, rgba(28, 43, 36, .68) 48%, rgba(28, 43, 36, .08) 82%), + linear-gradient(0deg, rgba(17, 28, 23, .57) 0%, transparent 60%); +} + +.oc-dong-craft-detail .oc-cave-detail-hero-copy { + max-width: 1120px; +} + +.oc-dong-craft-detail .oc-cave-detail-hero-copy h1 { + max-width: 1100px; + font-size: clamp(43px, 5.05vw, 76px); + line-height: .97; +} + +.oc-dong-craft-detail .oc-cave-detail-hero-copy p { + max-width: 820px; +} + +.oc-dong-craft-detail .oc-cave-detail-levels { + background: #2f3d37; +} + +.oc-dong-craft-detail .oc-cave-detail-safety { + background: #e9e5dc; +} + +.oc-dong-craft-gallery figure:first-child img { + object-position: center 54%; +} + +.oc-dong-craft-gallery figure:nth-child(2) img { + object-position: center 48%; +} + +.oc-dong-craft-gallery figure:nth-child(3) img { + object-position: center 45%; +} + +.oc-dong-craft-gallery figure:nth-child(4) img { + object-position: center 51%; +} + +.oc-dong-craft-detail .oc-cave-detail-flow figure img { + object-position: center 49%; +} + +@media (max-width: 720px) { + .oc-dong-craft-detail .oc-cave-detail-hero > img { + object-position: 55% center; + } + + .oc-dong-craft-detail .oc-cave-detail-shade { + background: linear-gradient(0deg, rgba(18, 29, 24, .96) 0%, rgba(30, 45, 38, .6) 69%, rgba(30, 45, 38, .08) 100%); + } + + .oc-dong-craft-detail .oc-cave-detail-hero-copy h1 { + font-size: clamp(34px, 9.2vw, 46px); + line-height: 1; + } +} + +/* Shui horsetail embroidery detail uses a quiet silk-and-earth palette while explicitly treating the available photography as general craft reference. */ +.oc-shui-embroidery-detail { + --oc-cave-ink: #332e31; + --oc-cave-moss: #45383d; + --oc-cave-sage: #b89c72; + --oc-cave-paper: #f1ece4; + background: #f6f2eb; +} + +.oc-shui-embroidery-detail .oc-cave-detail-hero > img { + object-position: center 55%; + filter: saturate(.58) contrast(.97) brightness(.61); +} + +.oc-shui-embroidery-detail .oc-cave-detail-shade { + background: + linear-gradient(90deg, rgba(31, 24, 28, .94) 0%, rgba(58, 45, 51, .69) 47%, rgba(58, 45, 51, .08) 82%), + linear-gradient(0deg, rgba(34, 26, 30, .57) 0%, transparent 60%); +} + +.oc-shui-embroidery-detail .oc-cave-detail-hero-copy { + max-width: 1060px; +} + +.oc-shui-embroidery-detail .oc-cave-detail-hero-copy h1 { + max-width: 1040px; + font-size: clamp(47px, 5.45vw, 82px); + line-height: .96; +} + +.oc-shui-embroidery-detail .oc-cave-detail-hero-copy p { + max-width: 770px; +} + +.oc-shui-embroidery-detail .oc-cave-detail-levels { + background: #45383d; +} + +.oc-shui-embroidery-detail .oc-cave-detail-safety { + background: #eae3da; +} + +.oc-shui-embroidery-gallery { + grid-template-columns: 1.08fr .92fr; + grid-template-rows: 590px; +} + +.oc-shui-embroidery-gallery figure:first-child, +.oc-shui-embroidery-gallery figure:nth-child(2) { + grid-column: auto; + grid-row: auto; +} + +.oc-shui-embroidery-gallery figure:first-child img { + object-position: center 43%; +} + +.oc-shui-embroidery-gallery figure:nth-child(2) img { + object-position: center 52%; +} + +.oc-shui-embroidery-detail .oc-cave-detail-flow figure img { + object-position: center 43%; +} + +@media (max-width: 720px) { + .oc-shui-embroidery-detail .oc-cave-detail-hero > img { + object-position: 47% center; + } + + .oc-shui-embroidery-detail .oc-cave-detail-shade { + background: linear-gradient(0deg, rgba(32, 24, 29, .96) 0%, rgba(61, 47, 54, .61) 69%, rgba(61, 47, 54, .08) 100%); + } + + .oc-shui-embroidery-detail .oc-cave-detail-hero-copy h1 { + font-size: clamp(37px, 9.8vw, 49px); + line-height: .99; + } + + .oc-shui-embroidery-gallery { + grid-template-columns: 1fr; + grid-template-rows: 470px 500px; + gap: 10px; + padding-bottom: 88px; + } +} + +/* Buyi craft detail pairs stone grey, muted indigo, and warm fibre tones while keeping all available imagery explicitly provisional. */ +.oc-buyi-craft-detail { + --oc-cave-ink: #303235; + --oc-cave-moss: #3c4547; + --oc-cave-sage: #b6a075; + --oc-cave-paper: #f0ede7; + background: #f5f2ec; +} + +.oc-buyi-craft-detail .oc-cave-detail-hero > img { + object-position: center 48%; + filter: saturate(.55) contrast(.98) brightness(.6); +} + +.oc-buyi-craft-detail .oc-cave-detail-shade { + background: + linear-gradient(90deg, rgba(25, 29, 31, .94) 0%, rgba(46, 56, 59, .7) 48%, rgba(46, 56, 59, .08) 82%), + linear-gradient(0deg, rgba(28, 32, 34, .58) 0%, transparent 60%); +} + +.oc-buyi-craft-detail .oc-cave-detail-hero-copy { + max-width: 1080px; +} + +.oc-buyi-craft-detail .oc-cave-detail-hero-copy h1 { + max-width: 1040px; + font-size: clamp(45px, 5.25vw, 80px); + line-height: .97; +} + +.oc-buyi-craft-detail .oc-cave-detail-hero-copy p { + max-width: 780px; +} + +.oc-buyi-craft-detail .oc-cave-detail-levels { + background: #3c4547; +} + +.oc-buyi-craft-detail .oc-cave-detail-safety { + background: #e7e4de; +} + +.oc-buyi-craft-gallery figure:first-child img { + object-position: center 51%; +} + +.oc-buyi-craft-gallery figure:nth-child(2) img { + object-position: center 48%; +} + +.oc-buyi-craft-gallery figure:nth-child(3) img { + object-position: center 52%; +} + +.oc-buyi-craft-gallery figure:nth-child(4) img { + object-position: center 43%; +} + +.oc-buyi-craft-detail .oc-cave-detail-flow figure img { + object-position: center 48%; +} + +@media (max-width: 720px) { + .oc-buyi-craft-detail .oc-cave-detail-hero > img { + object-position: 53% center; + } + + .oc-buyi-craft-detail .oc-cave-detail-shade { + background: linear-gradient(0deg, rgba(25, 29, 31, .96) 0%, rgba(47, 57, 60, .62) 69%, rgba(47, 57, 60, .08) 100%); + } + + .oc-buyi-craft-detail .oc-cave-detail-hero-copy h1 { + font-size: clamp(35px, 9.25vw, 47px); + line-height: 1; + } +} + +/* Signature Experiences archive — curated series instead of a flat filter wall. */ +.oc-experience-editorial { + background: #f2f0e9; +} + +.oc-experience-editorial .oc-menu-page-hero { + padding-bottom: 118px; +} + +.oc-experience-series-nav { + position: relative; + z-index: 3; + display: grid; + grid-template-columns: repeat(3, minmax(0, 1fr)); + gap: 18px; + margin-top: -54px; + padding-bottom: 112px; +} + +.oc-experience-series-nav > a { + position: relative; + min-height: 310px; + display: grid; + grid-template-columns: 44px minmax(0, 1fr) 24px; + gap: 18px; + align-items: end; + overflow: hidden; + padding: 30px; + color: #fff; +} + +.oc-experience-series-nav > a::after { + content: ''; + position: absolute; + inset: 0; + background: linear-gradient(180deg, rgba(18, 35, 24, 0.04) 20%, rgba(17, 31, 22, 0.9) 100%); +} + +.oc-experience-series-nav img { + position: absolute; + inset: 0; + width: 100%; + height: 100%; + object-fit: cover; + filter: saturate(0.76) contrast(0.96); + transition: transform 0.7s ease; +} + +.oc-experience-series-nav > a:hover img { + transform: scale(1.025); +} + +.oc-experience-series-nav > a > span, +.oc-experience-series-nav > a > div, +.oc-experience-series-nav > a > svg { + position: relative; + z-index: 1; +} + +.oc-experience-series-nav > a > span { + color: rgba(255, 255, 255, 0.7); + font-size: 10px; + font-weight: 700; + letter-spacing: 0.12em; +} + +.oc-experience-series-nav b, +.oc-experience-series-nav small { + display: block; +} + +.oc-experience-series-nav b { + color: #fff; + font-family: Georgia, 'Times New Roman', serif; + font-size: clamp(23px, 2.2vw, 32px); + font-weight: 400; + line-height: 1.2; +} + +.oc-experience-series-nav small { + margin-top: 8px; + color: rgba(255, 255, 255, 0.68); + font-size: 11px; + line-height: 1.5; +} + +.oc-experience-series-nav svg { + align-self: center; + color: #fff; +} + +.oc-experience-series-head { + display: grid; + grid-template-columns: minmax(0, 1.15fr) minmax(280px, 0.7fr); + gap: 72px; + align-items: end; + margin-bottom: 54px; +} + +.oc-experience-series-head > div { + display: grid; + gap: 16px; +} + +.oc-experience-series-head span { + color: #78857b; + font-size: 9px; + font-weight: 700; + letter-spacing: 0.14em; + text-transform: uppercase; +} + +.oc-experience-series-head h2 { + max-width: 720px; + color: #304037; + font-family: Georgia, 'Times New Roman', serif; + font-size: clamp(34px, 4.2vw, 58px); + font-weight: 400; + line-height: 1.08; +} + +.oc-experience-series-head > p { + color: #667069; + font-size: 13px; + line-height: 1.75; +} + +.oc-experience-outdoor { + padding: 118px 0 124px; + background: #172a1e; +} + +.oc-experience-outdoor .oc-experience-series-head span, +.oc-experience-outdoor .oc-experience-series-head > p { + color: rgba(229, 238, 225, 0.62); +} + +.oc-experience-outdoor .oc-experience-series-head h2 { + color: #f0f4ec; +} + +.oc-experience-outdoor-grid { + display: grid; + grid-template-columns: repeat(6, minmax(0, 1fr)); + gap: 18px; +} + +.oc-experience-outdoor-grid article { + min-width: 0; + grid-column: span 2; + display: grid; + grid-template-rows: 260px minmax(0, 1fr); + background: #23362a; +} + +.oc-experience-outdoor-grid article.is-featured { + grid-column: 1 / -1; + grid-template-columns: minmax(0, 1.28fr) minmax(330px, 0.72fr); + grid-template-rows: minmax(440px, auto); +} + +.oc-experience-card-media { + display: block; + min-height: 0; + overflow: hidden; +} + +.oc-experience-card-media img { + width: 100%; + height: 100%; + object-fit: cover; + filter: saturate(0.7) contrast(1.02); + transition: transform 0.7s ease; +} + +.oc-experience-card-media:hover img { + transform: scale(1.025); +} + +.oc-experience-card-copy { + display: flex; + flex-direction: column; + min-width: 0; + padding: 28px 26px 30px; +} + +.oc-experience-card-copy > span { + color: #a9c19f; + font-size: 9px; + font-weight: 700; + letter-spacing: 0.12em; +} + +.oc-experience-card-copy > small { + margin-top: 20px; + color: rgba(232, 240, 227, 0.48); + font-size: 9px; + line-height: 1.5; + text-transform: uppercase; +} + +.oc-experience-card-copy h3 { + margin-top: 18px; + color: #f1f4ed; + font-family: Georgia, 'Times New Roman', serif; + font-size: 25px; + font-weight: 400; + line-height: 1.25; +} + +.oc-experience-card-copy h4 { + margin-top: 10px; + color: #a9bca6; + font-size: 11px; + font-weight: 500; + line-height: 1.5; +} + +.oc-experience-card-copy p { + margin-top: 17px; + color: rgba(232, 240, 227, 0.67); + font-size: 12px; + line-height: 1.7; +} + +.oc-experience-card-copy > a { + width: fit-content; + display: inline-flex; + align-items: center; + gap: 8px; + margin-top: auto; + padding-top: 28px; + color: #dce9d7; + font-size: 10px; + font-weight: 700; + letter-spacing: 0.08em; + text-transform: uppercase; +} + +.oc-experience-verification-note { + display: grid; + grid-template-columns: 48px minmax(0, 1fr); + gap: 24px; + margin-top: 56px; + padding: 34px 36px; + border: 1px solid rgba(225, 238, 219, 0.17); + color: #e7eee3; +} + +.oc-experience-verification-note > svg { + color: #aac3a1; +} + +.oc-experience-verification-note span { + color: #a9c19f; + font-size: 9px; + font-weight: 700; + letter-spacing: 0.13em; + text-transform: uppercase; +} + +.oc-experience-verification-note h3 { + margin-top: 12px; + font-family: Georgia, 'Times New Roman', serif; + font-size: 23px; + font-weight: 400; +} + +.oc-experience-verification-note p { + max-width: 880px; + margin-top: 10px; + color: rgba(232, 240, 227, 0.6); + font-size: 11px; + line-height: 1.66; +} + +.oc-experience-verification-note a { + width: fit-content; + display: inline-flex; + align-items: center; + gap: 8px; + margin-top: 18px; + color: #dce9d7; + font-size: 10px; + font-weight: 700; + letter-spacing: .08em; + text-transform: uppercase; +} + +.oc-experience-local { + padding-top: 122px; + padding-bottom: 126px; +} + +.oc-experience-local-grid { + display: grid; + grid-template-columns: repeat(12, minmax(0, 1fr)); + gap: 18px; +} + +.oc-experience-local-grid article { + min-width: 0; + grid-column: span 5; + display: grid; + grid-template-rows: 330px minmax(0, 1fr); + background: #e8e2d6; +} + +.oc-experience-local-grid article.is-wide { + grid-column: span 7; +} + +.oc-experience-local-grid article:last-child { + grid-column: 1 / -1; + grid-template-columns: minmax(0, 1.2fr) minmax(330px, 0.8fr); + grid-template-rows: minmax(390px, auto); +} + +.oc-experience-local-grid article > img { + width: 100%; + height: 100%; + object-fit: cover; + filter: saturate(0.76) contrast(0.96); +} + +.oc-experience-local-grid article > div { + display: flex; + flex-direction: column; + padding: 28px 27px 30px; +} + +.oc-experience-local-grid article span { + color: #7a806f; + font-size: 9px; + font-weight: 700; + letter-spacing: 0.12em; +} + +.oc-experience-local-grid article small { + margin-top: 20px; + color: #828177; + font-size: 9px; + line-height: 1.5; + text-transform: uppercase; +} + +.oc-experience-local-grid article h3 { + margin-top: 18px; + color: #38443b; + font-family: Georgia, 'Times New Roman', serif; + font-size: 25px; + font-weight: 400; + line-height: 1.25; +} + +.oc-experience-local-grid article p { + margin-top: 16px; + color: #66685f; + font-size: 12px; + line-height: 1.7; +} + +.oc-experience-local-grid article a { + width: fit-content; + display: inline-flex; + align-items: center; + gap: 8px; + margin-top: auto; + padding-top: 26px; + color: #3d5b45; + font-size: 10px; + font-weight: 700; + letter-spacing: 0.07em; + text-transform: uppercase; +} + +.oc-experience-landscapes { + border-top: 1px solid rgba(38, 64, 57, .12); + background: #e5ece7; +} + +.oc-experience-landscapes .oc-experience-local-grid article { + background: #d7e2dc; +} + +.oc-experience-landscapes .oc-experience-local-grid article > img { + object-position: center 42%; +} + +.oc-experience-route-pairing { + padding: 104px 0 112px; + background: #dfe5db; +} + +.oc-experience-pairing-head { + display: grid; + grid-template-columns: minmax(180px, 0.45fr) minmax(0, 1.5fr); + gap: 46px; + align-items: end; + margin-bottom: 45px; +} + +.oc-experience-pairing-head span { + color: #748078; + font-size: 9px; + font-weight: 700; + letter-spacing: 0.13em; + text-transform: uppercase; +} + +.oc-experience-pairing-head h2 { + color: #35443a; + font-family: Georgia, 'Times New Roman', serif; + font-size: clamp(31px, 3.5vw, 48px); + font-weight: 400; + line-height: 1.15; +} + +.oc-experience-pairing-grid { + display: grid; + grid-template-columns: repeat(3, minmax(0, 1fr)); + border-top: 1px solid rgba(48, 68, 55, 0.22); + border-left: 1px solid rgba(48, 68, 55, 0.15); +} + +.oc-experience-pairing-grid a { + min-height: 235px; + display: grid; + grid-template-rows: auto auto minmax(0, 1fr) auto; + padding: 26px 24px 28px; + border-right: 1px solid rgba(48, 68, 55, 0.15); + border-bottom: 1px solid rgba(48, 68, 55, 0.15); + color: #334238; +} + +.oc-experience-pairing-grid a > span { + color: #78867b; + font-size: 9px; + font-weight: 700; + letter-spacing: 0.1em; +} + +.oc-experience-pairing-grid h3 { + margin-top: 24px; + font-family: Georgia, 'Times New Roman', serif; + font-size: 22px; + font-weight: 400; +} + +.oc-experience-pairing-grid p { + margin-top: 13px; + color: #667069; + font-size: 11px; + line-height: 1.65; +} + +.oc-experience-pairing-grid svg { + margin-top: 20px; +} + +@media (max-width: 900px) { + .oc-experience-series-head { + grid-template-columns: 1fr; + gap: 24px; + } + + .oc-experience-outdoor-grid article, + .oc-experience-outdoor-grid article.is-featured { + grid-column: span 3; + grid-template-columns: 1fr; + grid-template-rows: 290px minmax(0, 1fr); + } + + .oc-experience-local-grid article, + .oc-experience-local-grid article.is-wide { + grid-column: span 6; + } + + .oc-experience-local-grid article:last-child { + grid-column: 1 / -1; + } +} + +@media (max-width: 640px) { + .oc-experience-editorial .oc-menu-page-hero { + padding-bottom: 88px; + } + + .oc-experience-series-nav { + grid-template-columns: 1fr; + margin-top: -30px; + padding-bottom: 76px; + } + + .oc-experience-series-nav > a { + min-height: 245px; + grid-template-columns: 28px minmax(0, 1fr) 20px; + gap: 12px; + padding: 24px 20px; + } + + .oc-experience-outdoor, + .oc-experience-local { + padding-top: 78px; + padding-bottom: 82px; + } + + .oc-experience-series-head { + margin-bottom: 36px; + } + + .oc-experience-outdoor-grid, + .oc-experience-local-grid, + .oc-experience-pairing-grid { + grid-template-columns: 1fr; + } + + .oc-experience-outdoor-grid article, + .oc-experience-outdoor-grid article.is-featured, + .oc-experience-local-grid article, + .oc-experience-local-grid article.is-wide, + .oc-experience-local-grid article:last-child { + grid-column: auto; + grid-template-columns: 1fr; + grid-template-rows: 245px minmax(0, 1fr); + } + + .oc-experience-verification-note { + grid-template-columns: 1fr; + padding: 28px 24px; + } + + .oc-experience-route-pairing { + padding: 76px 0 82px; + } + + .oc-experience-pairing-head { + grid-template-columns: 1fr; + gap: 16px; + margin-bottom: 32px; + } + + .oc-experience-pairing-grid a { + min-height: 0; + } +} + .oc-site a { color: inherit; text-decoration: none; @@ -461,7 +5134,7 @@ a.oc-route-service-panel, .oc-home-safari-image, .oc-info-band-image, -.oc-experience-band > img, +.oc-experience-band-media img, .oc-special-menu-image img, .oc-safari-card-image img, .oc-archive-card-image > img, @@ -478,7 +5151,7 @@ a.oc-route-service-panel, .oc-home-safari:hover .oc-home-safari-image, .oc-info-band:hover .oc-info-band-image, -.oc-experience-band:hover > img, +.oc-experience-band:hover .oc-experience-band-media img, .oc-special-menu-card:hover .oc-special-menu-image img, .oc-safari-card:hover .oc-safari-card-image img, .oc-archive-card:hover .oc-archive-card-image > img, @@ -921,17 +5594,15 @@ a.oc-route-service-panel, .oc-home-hero { position: relative; - height: 80vh; + height: calc(100svh - 91px); min-height: 720px; - background-position: center; - background-size: cover; display: grid; - align-items: end; - text-align: center; - color: #fff; + grid-template-rows: minmax(420px, 59%) minmax(300px, 41%); + overflow: hidden; + background: #f2f0e8; + color: #20241f; } -.oc-home-hero::after, .oc-image-hero::after { content: ''; position: absolute; @@ -940,6 +5611,29 @@ a.oc-route-service-panel, pointer-events: none; } +.oc-hero-media { + grid-row: 1; + width: 100%; + height: 100%; + min-height: 0; + object-fit: cover; + object-position: center 52%; + background-color: #dfe3dd; + filter: saturate(0.7) contrast(0.93) brightness(1.04); + animation: oc-hero-image-in 700ms ease both; +} + +@keyframes oc-hero-image-in { + from { + opacity: 0.65; + transform: scale(1.012); + } + to { + opacity: 1; + transform: scale(1); + } +} + .oc-awards { position: absolute; top: 62px; @@ -958,26 +5652,51 @@ a.oc-route-service-panel, .oc-hero-dots { position: absolute; - top: 76px; - left: 54px; + right: clamp(44px, 5vw, 76px); + bottom: 60px; z-index: 1; display: flex; align-items: center; - gap: 10px; + gap: 16px; } -.oc-hero-dots button { +.oc-hero-dot { width: 10px; height: 10px; - border: 1px solid rgba(255, 255, 255, 0.86); + padding: 0; + border: 1px solid #667668; border-radius: 999px; background: transparent; cursor: pointer; + transition: background-color 180ms ease, border-color 180ms ease, transform 180ms ease; } -.oc-hero-dots button.is-active { - width: 30px; - background: #fff; +.oc-hero-dot.is-active { + background: #48624c; + border-color: #48624c; +} + +.oc-hero-dot:hover { + transform: scale(1.18); +} + +.oc-hero-dot:focus-visible, +.oc-hero-playback:focus-visible { + outline: 2px solid #48624c; + outline-offset: 4px; +} + +.oc-hero-playback { + width: 28px; + height: 28px; + display: grid; + place-items: center; + margin-left: 4px; + padding: 0; + border: 0; + background: transparent; + color: #48624c; + cursor: pointer; } .oc-trip { @@ -992,30 +5711,243 @@ a.oc-route-service-panel, .oc-hero-copy { position: relative; z-index: 1; - padding: 0 24px 88px; + grid-row: 2; + display: grid; + align-content: start; + justify-items: start; + padding: 32px clamp(44px, 5vw, 76px) 38px; + background: #f2f0e8; + color: #20241f; + text-align: left; } .oc-hero-copy p { - font-size: 16px; - line-height: 28.8px; - letter-spacing: 1px; - margin-bottom: 19px; - opacity: 0.9; + margin-bottom: 18px; + color: #48624c; + font-size: 14px; + font-weight: 500; + line-height: 1.5; + letter-spacing: 0.08em; } .oc-hero-copy h1 { - font-size: 50px; - line-height: 60px; - text-shadow: 0 3px 16px rgba(0, 0, 0, 0.22); + max-width: min(1000px, calc(100% - 180px)); + margin-bottom: 16px; + color: #20241f; + font-size: clamp(46px, 3.9vw, 60px); + line-height: 1.16; + letter-spacing: 0.01em; + text-wrap: balance; +} + +.oc-hero-copy p.oc-hero-summary { margin-bottom: 26px; + color: #3f4740; + font-size: 17px; + font-weight: 400; + line-height: 1.65; + letter-spacing: 0.02em; } .oc-hero-copy .oc-orange-btn { - min-width: 168px; - height: 45px; + min-width: 176px; + height: 48px; + display: inline-flex; + align-items: center; + justify-content: center; + gap: 12px; + padding: 0 24px; + background: #48624c; + box-shadow: none; font-size: 16px; } +.oc-hero-copy .oc-orange-btn:hover { + background: #394f3d; + box-shadow: none; +} + +.oc-home-trust { + border-top: 1px solid #e2e3dc; + border-bottom: 1px solid #e2e3dc; + background: #faf9f4; +} + +.oc-home-trust-grid { + display: grid; + grid-template-columns: repeat(4, minmax(0, 1fr)); + padding-top: 28px; + padding-bottom: 28px; +} + +.oc-home-trust-item { + min-width: 0; + display: grid; + grid-template-columns: auto minmax(0, 1fr); + gap: 14px; + align-items: start; + padding: 0 26px; + color: #48624c; +} + +.oc-home-trust-item:first-child { + padding-left: 0; +} + +.oc-home-trust-item:last-child { + padding-right: 0; +} + +.oc-home-trust-item + .oc-home-trust-item { + border-left: 1px solid #dedfd7; +} + +.oc-home-trust-item strong, +.oc-home-trust-item span { + display: block; +} + +.oc-home-trust-item strong { + margin-bottom: 6px; + color: #243128; + font-family: Georgia, 'Times New Roman', serif; + font-size: 17px; + font-weight: 500; + line-height: 1.25; +} + +.oc-home-trust-item span { + color: #69716a; + font-size: 12px; + line-height: 1.55; +} + +.oc-home-brand-story { + padding: 112px 0 104px; + background: #f2f0e9; +} + +.oc-brand-story-layout { + display: grid; + grid-template-columns: minmax(0, 0.92fr) minmax(0, 1.08fr); + gap: clamp(64px, 8vw, 112px); + align-items: center; +} + +.oc-brand-story-media { + position: relative; + aspect-ratio: 4 / 5; + margin: 0; + overflow: hidden; + background: #d8dbd2; +} + +.oc-brand-story-media::after { + content: ''; + position: absolute; + inset: 0; + border: 1px solid rgba(37, 49, 40, 0.1); + pointer-events: none; +} + +.oc-brand-story-media img { + width: 100%; + height: 100%; + display: block; + object-fit: cover; + object-position: center; + filter: saturate(0.72) contrast(0.94); +} + +.oc-brand-story-copy { + max-width: 570px; +} + +.oc-brand-eyebrow { + display: inline-flex; + align-items: center; + gap: 14px; + margin-bottom: 28px; + color: #55705b; + font-size: 12px; + font-weight: 700; + letter-spacing: 0.18em; + text-transform: uppercase; +} + +.oc-brand-eyebrow::before { + content: ''; + width: 44px; + height: 1px; + background: #718275; +} + +.oc-brand-story-copy h2 { + max-width: 560px; + color: #263229; + font-family: Georgia, 'Times New Roman', serif; + font-size: clamp(48px, 4.4vw, 66px); + line-height: 1.08; + letter-spacing: -0.035em; + text-wrap: balance; +} + +.oc-brand-story-copy > p { + max-width: 540px; + margin-top: 34px; + color: #5c645e; + font-size: 17px; + line-height: 1.82; +} + +.oc-brand-story-copy blockquote { + margin: 38px 0 0; + padding: 0 0 0 24px; + border-left: 1px solid #6f8573; + color: #354a3a; + font-family: Georgia, 'Times New Roman', serif; + font-size: 22px; + font-style: italic; + line-height: 1.65; +} + +.oc-brand-values { + display: grid; + grid-template-columns: repeat(5, minmax(0, 1fr)); + gap: 28px; + margin-top: 88px; +} + +.oc-brand-value { + min-width: 0; + padding-top: 20px; + border-top: 1px solid rgba(37, 49, 40, 0.25); +} + +.oc-brand-value > span { + display: block; + margin-bottom: 24px; + color: #628069; + font-size: 11px; + font-weight: 700; + letter-spacing: 0.16em; +} + +.oc-brand-value h3 { + min-height: 52px; + color: #2b392f; + font-family: Georgia, 'Times New Roman', serif; + font-size: 19px; + line-height: 1.35; +} + +.oc-brand-value p { + margin-top: 14px; + color: #687069; + font-size: 13px; + line-height: 1.65; +} + .oc-plan-panel { min-height: 275px; display: grid; @@ -1203,13 +6135,72 @@ a.oc-route-service-panel, } .oc-home-experiences { - margin-top: 60px; + margin-top: 104px; min-height: 0; } +.oc-home-experiences .oc-section-title { + max-width: 820px; + margin: 0 0 48px; + text-align: left; +} + +.oc-home-experiences .oc-section-title h2 { + color: #28362d; + font-family: Georgia, 'Times New Roman', serif; + font-size: clamp(48px, 5vw, 66px); + line-height: 1.08; + letter-spacing: -0.035em; + text-wrap: balance; +} + +.oc-home-experiences .oc-section-title p { + max-width: 700px; + margin: 24px 0 0; + color: #626c65; + font-size: 16px; + line-height: 1.75; +} + .oc-home-safaris-section { margin-top: 120px; + position: relative; + isolation: isolate; min-height: 0; + padding: 108px 0 104px; +} + +.oc-home-safaris-section::before { + content: ''; + position: absolute; + inset: 0 50%; + z-index: -1; + width: 100vw; + transform: translateX(-50%); + background: #203529; +} + +.oc-home-safaris-section .oc-section-title { + max-width: 820px; + margin: 0 0 48px; + text-align: left; +} + +.oc-home-safaris-section .oc-section-title h2 { + color: #f2f1e9; + font-family: Georgia, 'Times New Roman', serif; + font-size: clamp(48px, 5vw, 66px); + line-height: 1.08; + letter-spacing: -0.035em; + text-wrap: balance; +} + +.oc-home-safaris-section .oc-section-title p { + max-width: 710px; + margin: 24px 0 0; + color: rgba(239, 242, 235, 0.72); + font-size: 16px; + line-height: 1.75; } .oc-section-title { @@ -1298,154 +6289,386 @@ a.oc-route-service-panel, .oc-experience-stack { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); - gap: 16px; + gap: 20px; } .oc-experience-band { - min-height: 520px; + min-height: 720px; display: grid; - grid-template-rows: 300px minmax(220px, 1fr); - text-align: center; - color: #fff; + grid-template-rows: 448px minmax(272px, 1fr); + text-align: left; + color: #2c3930; + background: #ecebe5; + border: 1px solid rgba(39, 52, 43, 0.1); overflow: hidden; - border-radius: 10px; + border-radius: 0; + box-shadow: none; } .oc-experience-band.tan { - background: #9dbf73; + background: #edece5; } .oc-experience-band.clay { - background: #48a850; + background: #ebe9e2; } .oc-experience-band.charcoal { - background: #193523; + background: #e8e9e3; +} + +.oc-experience-band-media { + min-width: 0; + overflow: hidden; + background: #d8dcd3; } .oc-experience-band img { width: 100%; - height: 300px; + height: 100%; + display: block; object-fit: cover; + filter: saturate(0.78) contrast(0.95); } .oc-experience-band-content { - display: grid; - align-content: center; - justify-items: center; - gap: 24px; - padding: 28px 28px 30px; + min-width: 0; + display: flex; + flex-direction: column; + align-items: flex-start; + padding: 26px 28px 28px; } -.oc-experience-band span, -.oc-experience-band small { - color: #f4fbef; - font-size: 16px; - font-weight: 400; - line-height: 24px; - letter-spacing: 1.5px; +.oc-experience-band-meta { + width: 100%; + display: flex; + justify-content: space-between; + gap: 18px; + margin-bottom: 24px; + color: #607466; +} + +.oc-experience-band-meta span { + color: inherit; + font-size: 10px; + font-weight: 700; + line-height: 1.35; + letter-spacing: 0.12em; text-transform: uppercase; } +.oc-experience-band-meta span:last-child { + text-align: right; +} + .oc-experience-band h3 { - max-width: 320px; - color: #fff; - font-size: 36px; - line-height: 43.2px; + max-width: 300px; + color: #2b382f; + font-family: Georgia, 'Times New Roman', serif; + font-size: 31px; + line-height: 1.18; + letter-spacing: -0.02em; +} + +.oc-experience-band p { + margin-top: 16px; + color: #68716a; + font-size: 13px; + line-height: 1.65; } .oc-experience-band small { + width: 100%; display: inline-flex; align-items: center; + justify-content: space-between; gap: 16px; + margin-top: auto; + padding-top: 20px; + border-top: 1px solid rgba(39, 52, 43, 0.16); + color: #38513f; + font-size: 10px; + font-weight: 700; + line-height: 1.3; + letter-spacing: 0.12em; + text-transform: uppercase; } .oc-home-safaris { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); - gap: 32px; + gap: 20px; } .oc-home-safari { position: relative; - min-height: 560px; + min-height: 820px; display: flex; flex-direction: column; - background: var(--oc-panel); - border-radius: 4px; + background: #f0efe8; + border: 1px solid rgba(239, 242, 235, 0.14); + border-radius: 0; padding: 0; overflow: hidden; + box-shadow: none; +} + +.oc-home-safari-media { + position: relative; + height: 290px; + overflow: hidden; + background: #cfd5cd; } .oc-home-safari-image { width: 100%; - height: 200px; + height: 100%; + display: block; object-fit: cover; + filter: saturate(0.76) contrast(0.95); +} + +.oc-home-safari-media > span { + position: absolute; + left: 18px; + bottom: 16px; + min-width: 38px; + height: 38px; + display: inline-flex; + align-items: center; + justify-content: center; + background: rgba(242, 241, 233, 0.92); + color: #2d4534; + font-size: 10px; + font-weight: 700; + letter-spacing: 0.12em; } .oc-home-safari-body { flex: 1; display: flex; flex-direction: column; - padding: 24px 20px 27px; + padding: 26px 28px 28px; } .oc-home-safari::after { - content: 'English'; - position: absolute; - top: 13px; - right: 18px; - background: #9fbf79; - color: #fff; - padding: 6px 10px; - font-size: 10px; + display: none; } html[data-oc-language='zh'] .oc-home-safari::after { - content: '英语'; + display: none; } -.oc-home-safari span { - color: #6a766b; - font-size: 12px; +.oc-home-safari .oc-home-safari-meta { + color: #667269; + font-size: 10px; font-weight: 700; + line-height: 1.45; + letter-spacing: 0.08em; + text-transform: uppercase; } .oc-home-safari h3 { - margin: 18px 0 12px; - font-family: 'Tenor Sans', Georgia, serif; - color: #223127; - font-size: 18px; - font-weight: 600; - line-height: 25.2px; -} - -.oc-home-safari b { - display: block; - border-top: 1px solid #c4d4bc; - border-bottom: 1px solid #c4d4bc; - color: #243328; - font-size: 11px; - padding: 9px 0; + margin: 20px 0 0; + color: #27362d; + font-family: Georgia, 'Times New Roman', serif; + font-size: 31px; + font-weight: 400; + line-height: 1.18; + letter-spacing: -0.02em; } .oc-home-safari p { - color: #5e6c61; - font-size: 11px; + margin: 16px 0 0; + color: #626d65; + font-size: 13px; + line-height: 1.65; +} + +.oc-home-safari-highlights { + display: grid; + gap: 0; + margin: 24px 0 28px; + padding: 0; + list-style: none; + border-top: 1px solid rgba(39, 54, 45, 0.16); +} + +.oc-home-safari-highlights li { + position: relative; + padding: 12px 0 12px 18px; + border-bottom: 1px solid rgba(39, 54, 45, 0.12); + color: #445248; + font-size: 12px; line-height: 1.5; - margin: 12px 0 18px; +} + +.oc-home-safari-highlights li::before { + content: ''; + position: absolute; + top: 19px; + left: 1px; + width: 5px; + height: 5px; + border-radius: 50%; + background: #728676; +} + +.oc-home-safari-footer { + display: grid; + gap: 18px; + margin-top: auto; +} + +.oc-home-safari-footer b { + color: #516057; + font-size: 11px; + font-weight: 600; + line-height: 1.4; } .oc-home-safari .oc-card-action { + width: 100%; display: flex; align-items: center; - justify-content: center; - height: 31px; - margin-top: auto; - border: 1px solid var(--oc-clay); - color: var(--oc-clay-dark); + justify-content: space-between; + height: auto; + margin: 0; + padding-top: 17px; + border: 0; + border-top: 1px solid rgba(39, 54, 45, 0.2); + color: #314c39; font-size: 10px; - font-weight: 800; + font-weight: 700; + letter-spacing: 0.1em; + text-transform: uppercase; +} + +.oc-home-safaris-section .oc-center { + text-align: center; + margin-top: 42px; +} + +.oc-home-safaris-section .oc-center .oc-clay-btn { + border: 1px solid rgba(239, 242, 235, 0.54); + background: transparent; + color: #f2f1e9; + box-shadow: none; +} + +.oc-home-safaris-section .oc-center .oc-clay-btn:hover { + border-color: #f2f1e9; + background: #f2f1e9; + color: #203529; +} + +.oc-home-team { + margin-top: 124px; + min-height: 0; +} + +.oc-home-team-layout { + display: grid; + grid-template-columns: minmax(0, 1.04fr) minmax(0, 0.96fr); + gap: clamp(62px, 7vw, 98px); + align-items: center; +} + +.oc-home-team-media { + position: relative; + min-height: 720px; +} + +.oc-home-team-media img { + display: block; + object-fit: cover; + filter: saturate(0.76) contrast(0.95); +} + +.oc-home-team-main-image { + width: 88%; + height: 520px; + object-position: center; +} + +.oc-home-team-field-image { + position: absolute; + right: 0; + bottom: 0; + width: 68%; + height: 300px; + border: 12px solid var(--oc-bg); + object-position: center; +} + +.oc-home-team-copy { + min-width: 0; +} + +.oc-home-team-copy h2 { + color: #29372e; + font-family: Georgia, 'Times New Roman', serif; + font-size: clamp(46px, 4.4vw, 62px); + line-height: 1.08; + letter-spacing: -0.035em; + text-wrap: balance; +} + +.oc-home-team-intro { + margin-top: 28px; + color: #626d65; + font-size: 16px; + line-height: 1.78; +} + +.oc-home-team-services { + margin-top: 42px; + border-top: 1px solid rgba(39, 54, 45, 0.22); +} + +.oc-home-team-service { + display: grid; + grid-template-columns: 40px minmax(0, 1fr); + gap: 14px; + padding: 22px 0; + border-bottom: 1px solid rgba(39, 54, 45, 0.16); +} + +.oc-home-team-service > span { + padding-top: 4px; + color: #67806d; + font-size: 10px; + font-weight: 700; + letter-spacing: 0.12em; +} + +.oc-home-team-service h3 { + color: #304036; + font-family: Georgia, 'Times New Roman', serif; + font-size: 20px; + line-height: 1.35; +} + +.oc-home-team-service p { + margin-top: 8px; + color: #6b746d; + font-size: 13px; + line-height: 1.65; +} + +.oc-home-team-cta { + min-width: 218px; + min-height: 48px; + display: inline-flex; + align-items: center; + justify-content: center; + gap: 12px; + margin-top: 34px; + padding: 0 22px; + color: #38523e; + font-size: 12px; + font-weight: 700; + letter-spacing: 0.06em; text-transform: uppercase; } @@ -1541,86 +6764,314 @@ html[data-oc-language='zh'] .oc-home-safari::after { } .oc-live { - width: min(100%, 1440px); + width: min(1116px, calc(100% - 120px)); text-align: left; min-height: 0; - padding-bottom: 26px; - overflow: hidden; + margin-top: 118px; + padding-bottom: 84px; +} + +.oc-live-heading { + max-width: 760px; + margin-bottom: 48px; } .oc-live h2 { - color: var(--oc-clay); - font-size: 48px; - line-height: 62.4px; - margin: 0 0 28px; - text-align: center; + color: #29372e; + font-family: Georgia, 'Times New Roman', serif; + font-size: clamp(48px, 5vw, 66px); + line-height: 1.08; + letter-spacing: -0.035em; + text-wrap: balance; } -.oc-live-carousel { - overflow: hidden; - width: 100%; - -webkit-mask-image: linear-gradient(90deg, transparent 0, #000 5%, #000 95%, transparent 100%); - mask-image: linear-gradient(90deg, transparent 0, #000 5%, #000 95%, transparent 100%); +.oc-live-heading > p { + max-width: 680px; + margin-top: 24px; + color: #626d65; + font-size: 16px; + line-height: 1.75; } -.oc-live-track { - display: flex; - width: max-content; - animation: oc-live-scroll 44s linear infinite; +.oc-live-grid { + display: grid; + grid-template-columns: repeat(3, minmax(0, 1fr)); + grid-auto-rows: 255px; + gap: 18px; } -.oc-live-carousel:hover .oc-live-track { - animation-play-state: paused; -} - -.oc-live-set { - display: flex; - flex: 0 0 auto; - gap: 14px; - padding-right: 14px; -} - -.oc-live-slide { - flex: 0 0 292px; - width: 292px; +.oc-live-photo { + position: relative; + min-width: 0; margin: 0; - border-radius: 6px; overflow: hidden; - background: var(--oc-panel); - box-shadow: 0 14px 28px rgba(24, 50, 34, 0.12); + background: #d8dcd3; } -.oc-live-slide img { +.oc-live-photo:first-child { + grid-column: span 2; + grid-row: span 2; +} + +.oc-live-photo img { width: 100%; - height: 214px; - object-fit: cover; + height: 100%; display: block; + object-fit: cover; + filter: saturate(0.78) contrast(0.95); + transition: transform 0.4s ease, filter 0.4s ease; } -@keyframes oc-live-scroll { - from { - transform: translateX(0); - } +.oc-live-photo:hover img { + transform: scale(1.025); + filter: saturate(0.92) contrast(0.98); +} - to { - transform: translateX(-50%); - } +.oc-live-photo figcaption { + position: absolute; + right: 0; + bottom: 0; + left: 0; + display: flex; + align-items: center; + gap: 12px; + padding: 28px 18px 16px; + background: linear-gradient(180deg, transparent, rgba(20, 31, 24, 0.72)); + color: #f7f5ef; + font-size: 12px; + line-height: 1.4; +} + +.oc-live-photo figcaption span { + color: rgba(247, 245, 239, 0.66); + font-size: 9px; + font-weight: 700; + letter-spacing: 0.12em; } @media (prefers-reduced-motion: reduce) { - .oc-live-carousel { - overflow-x: auto; - -webkit-mask-image: none; - mask-image: none; + .oc-live-photo img { + transition: none; } +} - .oc-live-track { - animation: none; - } +.oc-home-comparison { + padding: 108px 0 112px; + background: #ebe9e1; +} - .oc-live-set[aria-hidden='true'] { - display: none; - } +.oc-comparison-heading { + max-width: 790px; + margin-bottom: 48px; +} + +.oc-comparison-heading h2 { + color: #29372e; + font-family: Georgia, 'Times New Roman', serif; + font-size: clamp(48px, 5vw, 66px); + line-height: 1.08; + letter-spacing: -0.035em; + text-wrap: balance; +} + +.oc-comparison-heading > p { + max-width: 680px; + margin-top: 24px; + color: #626d65; + font-size: 16px; + line-height: 1.75; +} + +.oc-comparison-scroll { + overflow-x: auto; + border-top: 1px solid rgba(39, 54, 45, 0.28); + border-bottom: 1px solid rgba(39, 54, 45, 0.28); + scrollbar-color: #708176 transparent; + scrollbar-width: thin; +} + +.oc-comparison-scroll:focus-visible { + outline: 3px solid rgba(72, 168, 80, 0.44); + outline-offset: 5px; +} + +.oc-comparison-table { + width: 100%; + min-width: 980px; + border-collapse: collapse; + table-layout: fixed; +} + +.oc-comparison-table th, +.oc-comparison-table td { + padding: 22px 20px; + border-right: 1px solid rgba(39, 54, 45, 0.13); + border-bottom: 1px solid rgba(39, 54, 45, 0.13); + color: #566159; + font-size: 13px; + font-weight: 400; + line-height: 1.55; + text-align: left; + vertical-align: top; +} + +.oc-comparison-table th:last-child, +.oc-comparison-table td:last-child { + border-right: 0; +} + +.oc-comparison-table tbody tr:last-child th, +.oc-comparison-table tbody tr:last-child td { + border-bottom: 0; +} + +.oc-comparison-table thead th { + padding-top: 19px; + padding-bottom: 19px; + color: #33433a; + font-size: 11px; + font-weight: 700; + letter-spacing: 0.08em; + text-transform: uppercase; + vertical-align: middle; +} + +.oc-comparison-table thead th:first-child, +.oc-comparison-table tbody th { + width: 150px; + color: #33433a; + font-size: 11px; + font-weight: 700; + letter-spacing: 0.06em; + text-transform: uppercase; +} + +.oc-comparison-table .is-wanderq { + background: rgba(212, 226, 207, 0.6); + color: #2f4736; +} + +.oc-comparison-table thead .is-wanderq { + color: #2c5837; +} + +.oc-comparison-note { + max-width: 820px; + margin-top: 22px; + color: #717971; + font-size: 11px; + line-height: 1.6; +} + +.oc-home-final-cta { + position: relative; + overflow: hidden; + padding: 116px 0 120px; + background: #183222; + color: #f3f5ed; +} + +.oc-home-final-cta::before { + content: ''; + position: absolute; + top: -280px; + right: -170px; + width: 680px; + height: 680px; + border: 1px solid rgba(217, 234, 211, 0.12); + border-radius: 50%; + box-shadow: + 0 0 0 72px rgba(217, 234, 211, 0.025), + 0 0 0 144px rgba(217, 234, 211, 0.018); + pointer-events: none; +} + +.oc-home-final-cta-layout { + position: relative; + z-index: 1; + display: grid; + grid-template-columns: minmax(0, 1.05fr) minmax(360px, 0.78fr); + gap: clamp(64px, 8vw, 116px); + align-items: center; +} + +.oc-home-final-cta-copy { + max-width: 690px; +} + +.oc-home-final-eyebrow, +.oc-home-inquiry-prompts-label { + color: #b7d3af; + font-size: 11px; + font-weight: 700; + letter-spacing: 0.13em; + text-transform: uppercase; +} + +.oc-home-final-cta h2 { + max-width: 720px; + margin-top: 22px; + color: #f7f5ef; + font-family: Georgia, 'Times New Roman', serif; + font-size: clamp(48px, 5vw, 68px); + font-weight: 400; + line-height: 1.06; + letter-spacing: -0.035em; + text-wrap: balance; +} + +.oc-home-final-cta-copy > p { + max-width: 650px; + margin-top: 28px; + color: rgba(239, 245, 235, 0.72); + font-size: 15px; + line-height: 1.78; +} + +.oc-home-final-cta-button { + min-width: 258px; + margin-top: 36px; + gap: 12px; +} + +.oc-home-inquiry-prompts { + border-top: 1px solid rgba(217, 234, 211, 0.32); +} + +.oc-home-inquiry-prompts-label { + display: block; + padding: 18px 0 20px; +} + +.oc-home-inquiry-prompt { + display: grid; + grid-template-columns: 40px minmax(0, 1fr); + gap: 15px; + padding: 22px 0; + border-top: 1px solid rgba(217, 234, 211, 0.16); +} + +.oc-home-inquiry-prompt > span { + padding-top: 4px; + color: rgba(183, 211, 175, 0.72); + font-size: 10px; + font-weight: 700; + letter-spacing: 0.12em; +} + +.oc-home-inquiry-prompt h3 { + color: #f1f5ec; + font-family: Georgia, 'Times New Roman', serif; + font-size: 19px; + font-weight: 400; + line-height: 1.35; +} + +.oc-home-inquiry-prompt p { + margin-top: 7px; + color: rgba(239, 245, 235, 0.64); + font-size: 12px; + line-height: 1.62; } .oc-breadcrumb { @@ -2411,6 +7862,356 @@ html[data-oc-language='zh'] .oc-home-safari::after { padding: 0 0 72px; } +.oc-transport-editorial { + position: relative; + z-index: 1; + display: grid; + grid-template-columns: minmax(0, 0.54fr) minmax(360px, 0.46fr); + gap: clamp(42px, 6vw, 96px); + align-items: center; + padding: 52px 0 108px; +} + +.oc-transport-editorial-copy > span, +.oc-transport-section-head > span { + color: var(--oc-clay-dark); + font-size: 11px; + font-weight: 800; + letter-spacing: 0.14em; + text-transform: uppercase; +} + +.oc-transport-editorial-copy h1, +.oc-transport-section-head h2 { + color: var(--oc-ink); + font-family: Georgia, 'Times New Roman', serif; + font-size: clamp(40px, 4.4vw, 66px); + font-weight: 400; + line-height: 1.04; + letter-spacing: -0.035em; + text-wrap: balance; +} + +.oc-transport-editorial-copy h1 { + max-width: 850px; + margin-top: 20px; +} + +.oc-transport-editorial-copy > p, +.oc-transport-section-head > p { + color: var(--oc-muted); + font-size: 16px; + line-height: 1.78; +} + +.oc-transport-editorial-copy > p { + max-width: 720px; + margin-top: 26px; +} + +.oc-transport-editorial-signals { + display: flex; + flex-wrap: wrap; + gap: 12px 22px; + margin-top: 32px; + padding-top: 24px; + border-top: 1px solid rgba(36, 51, 40, 0.14); +} + +.oc-transport-editorial-signals span { + display: inline-flex; + align-items: center; + gap: 7px; + color: #405645; + font-size: 13px; + font-weight: 700; +} + +.oc-transport-editorial-signals svg { + color: var(--oc-logo-green); +} + +.oc-transport-editorial-media { + position: relative; + margin: 0; + padding: 0 0 24px 24px; +} + +.oc-transport-editorial-media::before { + content: ''; + position: absolute; + inset: 44px 28px 0 0; + border: 1px solid rgba(51, 88, 60, 0.25); +} + +.oc-transport-editorial-media img { + position: relative; + z-index: 1; + width: 100%; + height: clamp(460px, 47vw, 680px); + object-fit: cover; + object-position: center 44%; +} + +.oc-transport-editorial-media figcaption { + position: relative; + z-index: 2; + max-width: 420px; + margin: -30px 0 0 auto; + padding: 15px 18px; + background: #f4f8ef; + color: #677368; + font-size: 11px; + line-height: 1.55; +} + +.oc-transport-services { + position: relative; + z-index: 1; + padding: 0 0 110px; +} + +.oc-transport-section-head { + display: grid; + grid-template-columns: minmax(0, 0.64fr) minmax(280px, 0.36fr); + gap: 20px 64px; + align-items: end; + padding-bottom: 40px; + border-bottom: 1px solid rgba(36, 51, 40, 0.16); +} + +.oc-transport-section-head > span { + grid-column: 1 / -1; +} + +.oc-transport-section-head h2 { + font-size: clamp(36px, 3.8vw, 56px); +} + +.oc-transport-section-head.is-compact { + display: block; + padding-bottom: 32px; +} + +.oc-transport-section-head.is-compact h2 { + max-width: 900px; + margin-top: 14px; +} + +.oc-transport-section-head.is-compact > p { + max-width: 780px; + margin-top: 18px; +} + +.oc-transport-service-grid { + display: grid; + grid-template-columns: repeat(2, minmax(0, 1fr)); +} + +.oc-transport-service-grid article { + display: grid; + grid-template-columns: 58px minmax(0, 1fr); + gap: 15px 24px; + align-content: start; + min-height: 310px; + padding: 42px 46px 38px 0; + border-bottom: 1px solid rgba(36, 51, 40, 0.16); +} + +.oc-transport-service-grid article:nth-child(odd) { + padding-right: 52px; + border-right: 1px solid rgba(36, 51, 40, 0.16); +} + +.oc-transport-service-grid article:nth-child(even) { + padding-left: 52px; +} + +.oc-transport-service-grid article > span { + grid-row: 1 / span 3; + color: rgba(63, 86, 66, 0.42); + font-family: Georgia, 'Times New Roman', serif; + font-size: 30px; +} + +.oc-transport-service-grid h3, +.oc-transport-standard-grid h3 { + color: var(--oc-ink); + font-family: Georgia, 'Times New Roman', serif; + font-size: 27px; + font-weight: 400; + line-height: 1.18; +} + +.oc-transport-service-grid p, +.oc-transport-standard-grid p { + color: var(--oc-muted); + font-size: 14px; + line-height: 1.72; +} + +.oc-transport-service-grid small { + align-self: end; + color: var(--oc-clay-dark); + font-size: 11px; + font-weight: 800; + letter-spacing: 0.045em; + text-transform: uppercase; +} + +.oc-transport-fleet { + position: relative; + z-index: 1; + padding-bottom: 108px; +} + +.oc-transport-fleet .oc-transport-grid { + padding: 36px 0 0; +} + +.oc-transport-standards { + position: relative; + z-index: 1; + padding: 104px 0 96px; + background: #203328; +} + +.oc-transport-section-head.is-light { + border-color: rgba(220, 233, 216, 0.2); +} + +.oc-transport-section-head.is-light > span { + color: #a8c69f; +} + +.oc-transport-section-head.is-light h2 { + color: #f5f4eb; +} + +.oc-transport-standard-grid { + display: grid; + grid-template-columns: repeat(5, minmax(0, 1fr)); + border-bottom: 1px solid rgba(220, 233, 216, 0.2); +} + +.oc-transport-standard-grid article { + min-height: 310px; + padding: 34px 27px 32px; + border-left: 1px solid rgba(220, 233, 216, 0.2); +} + +.oc-transport-standard-grid article:last-child { + border-right: 1px solid rgba(220, 233, 216, 0.2); +} + +.oc-transport-standard-grid article > span { + display: block; + color: #8fb488; + font-size: 11px; + font-weight: 800; + letter-spacing: 0.12em; +} + +.oc-transport-standard-grid h3 { + min-height: 74px; + margin-top: 28px; + color: #f5f4eb; + font-size: 22px; +} + +.oc-transport-standard-grid p { + margin-top: 18px; + color: rgba(239, 245, 235, 0.68); + font-size: 13px; +} + +.oc-transport-promise-strip { + display: flex; + flex-wrap: wrap; + gap: 12px 28px; + align-items: center; + padding-top: 30px; + color: rgba(239, 245, 235, 0.72); + font-size: 12px; +} + +.oc-transport-promise-strip strong { + margin-right: auto; + color: #f5f4eb; + font-family: Georgia, 'Times New Roman', serif; + font-size: 18px; + font-weight: 400; +} + +.oc-transport-promise-strip span::before { + content: '✓'; + margin-right: 7px; + color: #95bd8d; +} + +.oc-transport-dispatch { + position: relative; + z-index: 1; + display: grid; + grid-template-columns: minmax(360px, 0.47fr) minmax(0, 0.53fr); + gap: clamp(42px, 6vw, 92px); + align-items: stretch; + padding: 110px 0; +} + +.oc-transport-dispatch figure { + min-height: 680px; + margin: 0; + overflow: hidden; +} + +.oc-transport-dispatch figure img { + width: 100%; + height: 100%; + object-fit: cover; +} + +.oc-transport-dispatch > div { + align-self: center; +} + +.oc-transport-dispatch ol { + display: grid; + margin: 6px 0 0; + padding: 0; + list-style: none; +} + +.oc-transport-dispatch li { + display: grid; + grid-template-columns: 42px minmax(0, 1fr); + gap: 18px; + align-items: center; + padding: 18px 0; + border-bottom: 1px solid rgba(36, 51, 40, 0.14); +} + +.oc-transport-dispatch li span { + color: var(--oc-clay-dark); + font-size: 11px; + font-weight: 800; +} + +.oc-transport-dispatch li p { + color: var(--oc-ink); + font-size: 15px; + line-height: 1.5; +} + +.oc-transport-dispatch-note { + margin-top: 26px; + padding: 18px 20px; + background: #e7eee1; + color: #5d6c60; + font-size: 12px; + line-height: 1.65; +} + .oc-transport-card { display: grid; grid-template-columns: 210px minmax(0, 1fr); @@ -2456,6 +8257,327 @@ html[data-oc-language='zh'] .oc-home-safari::after { color: var(--oc-ink); } +.oc-hotel-editorial { + position: relative; + z-index: 1; + display: grid; + grid-template-columns: minmax(0, 0.59fr) minmax(320px, 0.41fr); + gap: clamp(46px, 7vw, 112px); + align-items: end; + padding: 48px 0 112px; +} + +.oc-hotel-editorial > div:first-child > span, +.oc-hotel-route-links header > span, +.oc-hotel-booking-checks > div > span { + color: var(--oc-clay-dark); + font-size: 11px; + font-weight: 800; + letter-spacing: 0.14em; + text-transform: uppercase; +} + +.oc-hotel-editorial h1, +.oc-hotel-group h2, +.oc-hotel-route-links h2, +.oc-hotel-booking-checks h2 { + color: var(--oc-ink); + font-family: Georgia, 'Times New Roman', serif; + font-weight: 400; + letter-spacing: -0.035em; + text-wrap: balance; +} + +.oc-hotel-editorial h1 { + max-width: 900px; + margin-top: 20px; + font-size: clamp(43px, 5vw, 74px); + line-height: 1.02; +} + +.oc-hotel-editorial > div:last-child > p { + color: var(--oc-muted); + font-size: 15px; + line-height: 1.78; +} + +.oc-hotel-editorial-tags { + display: flex; + flex-wrap: wrap; + gap: 8px; + margin-top: 24px; +} + +.oc-hotel-editorial-tags span { + padding: 8px 11px; + border: 1px solid rgba(56, 86, 62, 0.18); + color: #52634f; + font-size: 11px; + font-weight: 700; +} + +.oc-hotel-groups { + position: relative; + z-index: 1; +} + +.oc-hotel-group { + padding-bottom: 112px; +} + +.oc-hotel-group > header { + display: grid; + grid-template-columns: 72px minmax(0, 1fr); + gap: 26px; + align-items: start; + padding-bottom: 34px; + border-bottom: 1px solid rgba(36, 51, 40, 0.16); +} + +.oc-hotel-group > header > span { + color: rgba(63, 86, 66, 0.4); + font-family: Georgia, 'Times New Roman', serif; + font-size: 33px; + line-height: 1; +} + +.oc-hotel-group h2 { + font-size: clamp(37px, 4vw, 58px); + line-height: 1.04; +} + +.oc-hotel-group header p { + max-width: 820px; + margin-top: 16px; + color: var(--oc-muted); + font-size: 14px; + line-height: 1.72; +} + +.oc-hotel-candidate-grid { + display: grid; + grid-template-columns: repeat(2, minmax(0, 1fr)); +} + +.oc-hotel-group:nth-child(2) .oc-hotel-candidate-grid { + grid-template-columns: repeat(3, minmax(0, 1fr)); +} + +.oc-hotel-candidate { + display: grid; + grid-template-rows: auto auto auto minmax(0, 1fr) auto auto; + min-height: 480px; + padding: 36px 42px 38px; + border-bottom: 1px solid rgba(36, 51, 40, 0.16); + border-left: 1px solid rgba(36, 51, 40, 0.16); +} + +.oc-hotel-candidate:last-child { + border-right: 1px solid rgba(36, 51, 40, 0.16); +} + +.oc-hotel-candidate-topline { + display: flex; + justify-content: space-between; + gap: 16px; + color: var(--oc-clay-dark); + font-size: 10px; + font-weight: 800; + letter-spacing: 0.08em; + text-transform: uppercase; +} + +.oc-hotel-candidate-topline b { + color: #6f7d70; + font-size: inherit; +} + +.oc-hotel-candidate h3 { + max-width: 540px; + margin-top: 34px; + color: var(--oc-ink); + font-family: Georgia, 'Times New Roman', serif; + font-size: clamp(26px, 2.3vw, 35px); + font-weight: 400; + line-height: 1.12; +} + +.oc-hotel-candidate-location { + display: flex; + align-items: center; + gap: 7px; + margin-top: 15px; + color: #637166; + font-size: 12px; + font-weight: 700; +} + +.oc-hotel-candidate-location svg { + flex: 0 0 auto; + color: var(--oc-logo-green); +} + +.oc-hotel-candidate > p:not(.oc-hotel-candidate-location) { + margin-top: 22px; + color: var(--oc-muted); + font-size: 14px; + line-height: 1.72; +} + +.oc-hotel-candidate dl { + display: grid; + gap: 9px; + margin: 26px 0 0; + padding-top: 20px; + border-top: 1px solid rgba(36, 51, 40, 0.12); +} + +.oc-hotel-candidate dl div { + display: grid; + grid-template-columns: 58px minmax(0, 1fr); + gap: 12px; +} + +.oc-hotel-candidate dt { + color: var(--oc-clay-dark); + font-size: 10px; + font-weight: 800; + text-transform: uppercase; +} + +.oc-hotel-candidate dd { + margin: 0; + color: #667368; + font-size: 11px; + line-height: 1.55; +} + +.oc-hotel-candidate > a { + display: inline-flex; + align-items: center; + gap: 7px; + width: fit-content; + margin-top: 28px; + color: var(--oc-ink); + font-size: 11px; + font-weight: 800; + letter-spacing: 0.06em; + text-transform: uppercase; +} + +.oc-hotel-route-links { + position: relative; + z-index: 1; + padding: 108px 0 102px; + background: #203328; +} + +.oc-hotel-route-links .oc-container-wide { + display: grid; + grid-template-columns: minmax(310px, 0.36fr) minmax(0, 0.64fr); + gap: clamp(44px, 7vw, 112px); +} + +.oc-hotel-route-links header > span { + color: #9abf92; +} + +.oc-hotel-route-links h2 { + margin-top: 18px; + color: #f5f4eb; + font-size: clamp(38px, 4.2vw, 59px); + line-height: 1.06; +} + +.oc-hotel-route-links .oc-container-wide > div { + border-top: 1px solid rgba(220, 233, 216, 0.2); +} + +.oc-hotel-route-links article { + display: grid; + grid-template-columns: 42px minmax(170px, 0.35fr) minmax(170px, 0.35fr) minmax(220px, 0.3fr); + gap: 18px; + align-items: center; + padding: 24px 0; + border-bottom: 1px solid rgba(220, 233, 216, 0.2); +} + +.oc-hotel-route-links article > span { + color: #8fb488; + font-size: 10px; + font-weight: 800; +} + +.oc-hotel-route-links h3 { + color: #f5f4eb; + font-family: Georgia, 'Times New Roman', serif; + font-size: 19px; + font-weight: 400; +} + +.oc-hotel-route-links article b { + color: #bad0b6; + font-size: 11px; + line-height: 1.5; +} + +.oc-hotel-route-links article p { + color: rgba(239, 245, 235, 0.62); + font-size: 11px; + line-height: 1.58; +} + +.oc-hotel-booking-checks { + position: relative; + z-index: 1; + display: grid; + grid-template-columns: minmax(320px, 0.43fr) minmax(0, 0.57fr); + gap: clamp(48px, 7vw, 108px); + padding: 112px 0; +} + +.oc-hotel-booking-checks h2 { + max-width: 620px; + margin-top: 18px; + font-size: clamp(39px, 4.4vw, 62px); + line-height: 1.05; +} + +.oc-hotel-booking-checks > div > p { + max-width: 600px; + margin-top: 25px; + color: var(--oc-muted); + font-size: 14px; + line-height: 1.75; +} + +.oc-hotel-booking-checks ol { + margin: 0; + padding: 0; + border-top: 1px solid rgba(36, 51, 40, 0.16); + list-style: none; +} + +.oc-hotel-booking-checks li { + display: grid; + grid-template-columns: 42px minmax(0, 1fr); + gap: 18px; + padding: 21px 0; + border-bottom: 1px solid rgba(36, 51, 40, 0.16); +} + +.oc-hotel-booking-checks li span { + color: var(--oc-clay-dark); + font-size: 10px; + font-weight: 800; +} + +.oc-hotel-booking-checks li p { + color: var(--oc-ink); + font-size: 14px; + line-height: 1.55; +} + .oc-archive-layout.is-collective { padding-bottom: 105px; } @@ -2496,7 +8618,7 @@ html[data-oc-language='zh'] .oc-home-safari::after { gap: clamp(18px, 2.4vw, 30px); width: min(1116px, calc(100% - 80px)); margin: 0 auto; - padding: 22px 0 26px; + padding: 28px 0 30px; border-top: 1px solid rgba(74, 110, 70, 0.24); color: #6a756d; font-size: 13px; @@ -2507,7 +8629,7 @@ html[data-oc-language='zh'] .oc-home-safari::after { } .oc-footer-legal-logo img { - width: 92px; + width: 104px; height: auto; object-fit: contain; } @@ -2676,13 +8798,17 @@ html[data-oc-language='zh'] .oc-home-safari::after { } .oc-tabs { + box-sizing: border-box; + max-width: 100%; min-height: 72px; background: #183222; color: #dcebd5; display: flex; align-items: center; - justify-content: center; - gap: 54px; + justify-content: safe center; + gap: clamp(18px, 2.8vw, 54px); + overflow-x: auto; + overflow-y: hidden; padding: 0 24px; position: sticky; top: 84px; @@ -4988,6 +11114,13 @@ body.oc-lightbox-open { color: #a43d30; } +.oc-form-status a { + color: inherit; + text-decoration: underline; + text-decoration-thickness: 1px; + text-underline-offset: 3px; +} + .oc-inquiry-success-layer { position: fixed; inset: 0; @@ -5534,16 +11667,51 @@ body.oc-lightbox-open { min-height: 560px; } + .oc-home-hero { + height: auto; + min-height: 670px; + grid-template-rows: minmax(300px, 43vh) minmax(370px, auto); + } + + .oc-hero-media { + object-position: center; + } + + .oc-home-trust-grid { + grid-template-columns: repeat(2, minmax(0, 1fr)); + row-gap: 24px; + } + + .oc-home-trust-item:nth-child(odd) { + padding-left: 0; + border-left: 0; + } + + .oc-home-trust-item:nth-child(even) { + padding-right: 0; + } + .oc-awards, .oc-trip { display: none; } .oc-hero-dots { - top: 70px; + top: auto; + right: auto; + bottom: 30px; left: 24px; } + .oc-hero-copy { + padding: 34px 24px 82px; + } + + .oc-hero-copy h1 { + max-width: 700px; + font-size: clamp(38px, 7vw, 48px); + } + .oc-plan-panel, .oc-detail-overview, .oc-detail-strip, @@ -6098,7 +12266,61 @@ body.oc-lightbox-open { @media (max-width: 540px) { .oc-home-hero { - min-height: 515px; + min-height: 650px; + grid-template-rows: minmax(270px, 40vh) minmax(380px, auto); + } + + .oc-hero-copy { + padding: 30px 20px 76px; + } + + .oc-hero-copy p { + margin-bottom: 14px; + font-size: 13px; + } + + .oc-hero-copy h1 { + max-width: 100%; + margin-bottom: 14px; + font-size: 36px; + line-height: 1.18; + } + + .oc-hero-copy p.oc-hero-summary { + margin-bottom: 24px; + font-size: 15px; + } + + .oc-hero-copy .oc-orange-btn { + min-width: 154px; + height: 46px; + font-size: 15px; + } + + .oc-hero-dots { + bottom: 26px; + left: 20px; + gap: 14px; + } + + .oc-home-trust-grid { + grid-template-columns: 1fr; + gap: 0; + padding-top: 8px; + padding-bottom: 8px; + } + + .oc-home-trust-item, + .oc-home-trust-item:first-child, + .oc-home-trust-item:last-child, + .oc-home-trust-item:nth-child(even), + .oc-home-trust-item:nth-child(odd) { + padding: 18px 0; + border-left: 0; + } + + .oc-home-trust-item + .oc-home-trust-item { + border-top: 1px solid #dedfd7; } .oc-footer-legal { @@ -6391,6 +12613,46 @@ body.oc-lightbox-open { } @media (max-width: 980px) { + .oc-hotel-editorial, + .oc-hotel-route-links .oc-container-wide, + .oc-hotel-booking-checks { + grid-template-columns: 1fr; + } + + .oc-hotel-group:nth-child(2) .oc-hotel-candidate-grid { + grid-template-columns: repeat(2, minmax(0, 1fr)); + } + + .oc-hotel-route-links article { + grid-template-columns: 42px minmax(170px, 0.35fr) minmax(170px, 0.35fr) minmax(0, 0.3fr); + } + + .oc-transport-editorial, + .oc-transport-dispatch { + grid-template-columns: 1fr; + } + + .oc-transport-editorial-media { + width: min(720px, 100%); + justify-self: end; + } + + .oc-transport-section-head { + grid-template-columns: 1fr; + } + + .oc-transport-standard-grid { + grid-template-columns: repeat(2, minmax(0, 1fr)); + } + + .oc-transport-standard-grid article:nth-child(even) { + border-right: 1px solid rgba(220, 233, 216, 0.2); + } + + .oc-transport-dispatch figure { + min-height: 540px; + } + .oc-food-intro, .oc-transport-intro { grid-template-columns: 1fr; @@ -6406,6 +12668,248 @@ body.oc-lightbox-open { } @media (max-width: 640px) { + .oc-hotel-editorial { + gap: 26px; + padding: 36px 0 74px; + } + + .oc-hotel-editorial h1, + .oc-hotel-group h2, + .oc-hotel-route-links h2, + .oc-hotel-booking-checks h2 { + font-size: 32px; + line-height: 1.08; + } + + .oc-hotel-editorial > div:last-child > p, + .oc-hotel-group header p, + .oc-hotel-booking-checks > div > p { + font-size: 12px; + line-height: 1.62; + } + + .oc-hotel-group { + padding-bottom: 72px; + } + + .oc-hotel-group > header { + grid-template-columns: 42px minmax(0, 1fr); + gap: 12px; + padding-bottom: 24px; + } + + .oc-hotel-group > header > span { + font-size: 22px; + } + + .oc-hotel-candidate-grid, + .oc-hotel-group:nth-child(2) .oc-hotel-candidate-grid { + grid-template-columns: 1fr; + } + + .oc-hotel-candidate, + .oc-hotel-candidate:last-child { + min-height: 0; + padding: 28px 0; + border-right: 0; + border-left: 0; + } + + .oc-hotel-candidate h3 { + margin-top: 24px; + font-size: 26px; + } + + .oc-hotel-candidate > p:not(.oc-hotel-candidate-location) { + margin-top: 17px; + font-size: 12px; + line-height: 1.62; + } + + .oc-hotel-route-links { + padding: 72px 0 66px; + } + + .oc-hotel-route-links .oc-container-wide { + gap: 34px; + } + + .oc-hotel-route-links article { + grid-template-columns: 28px minmax(0, 1fr); + gap: 8px 12px; + align-items: start; + padding: 20px 0; + } + + .oc-hotel-route-links article > span { + grid-row: 1 / span 3; + } + + .oc-hotel-route-links h3, + .oc-hotel-route-links article b, + .oc-hotel-route-links article p { + grid-column: 2; + } + + .oc-hotel-route-links h3 { + font-size: 18px; + } + + .oc-hotel-booking-checks { + gap: 34px; + padding: 72px 0; + } + + .oc-hotel-booking-checks li { + grid-template-columns: 30px minmax(0, 1fr); + gap: 10px; + padding: 16px 0; + } + + .oc-hotel-booking-checks li p { + font-size: 12px; + } + + .oc-transport-editorial { + gap: 34px; + padding: 36px 0 72px; + } + + .oc-transport-editorial-copy h1, + .oc-transport-section-head h2 { + font-size: 32px; + line-height: 1.09; + } + + .oc-transport-editorial-copy > p, + .oc-transport-section-head > p { + font-size: 13px; + line-height: 1.62; + } + + .oc-transport-editorial-signals { + display: grid; + gap: 10px; + margin-top: 24px; + padding-top: 20px; + } + + .oc-transport-editorial-media { + padding: 0 0 15px 14px; + } + + .oc-transport-editorial-media img { + height: 420px; + } + + .oc-transport-editorial-media figcaption { + margin-top: -18px; + padding: 11px 13px; + font-size: 9px; + } + + .oc-transport-services, + .oc-transport-fleet { + padding-bottom: 72px; + } + + .oc-transport-section-head { + gap: 14px; + padding-bottom: 24px; + } + + .oc-transport-service-grid { + grid-template-columns: 1fr; + } + + .oc-transport-service-grid article, + .oc-transport-service-grid article:nth-child(odd), + .oc-transport-service-grid article:nth-child(even) { + grid-template-columns: 38px minmax(0, 1fr); + min-height: 0; + padding: 28px 0; + border-right: 0; + } + + .oc-transport-service-grid article > span { + font-size: 21px; + } + + .oc-transport-service-grid h3 { + font-size: 22px; + } + + .oc-transport-service-grid p { + font-size: 12px; + line-height: 1.58; + } + + .oc-transport-service-grid small { + font-size: 9px; + line-height: 1.45; + } + + .oc-transport-fleet .oc-transport-grid { + padding-top: 24px; + } + + .oc-transport-standards { + padding: 72px 0 64px; + } + + .oc-transport-standard-grid { + grid-template-columns: 1fr; + } + + .oc-transport-standard-grid article, + .oc-transport-standard-grid article:nth-child(even), + .oc-transport-standard-grid article:last-child { + min-height: 0; + padding: 28px 0; + border-right: 0; + border-left: 0; + border-bottom: 1px solid rgba(220, 233, 216, 0.2); + } + + .oc-transport-standard-grid h3 { + min-height: 0; + margin-top: 14px; + font-size: 21px; + } + + .oc-transport-standard-grid p { + margin-top: 10px; + font-size: 12px; + } + + .oc-transport-promise-strip { + display: grid; + gap: 10px; + } + + .oc-transport-promise-strip strong { + margin-bottom: 6px; + } + + .oc-transport-dispatch { + gap: 36px; + padding: 72px 0; + } + + .oc-transport-dispatch figure { + min-height: 440px; + } + + .oc-transport-dispatch li { + grid-template-columns: 32px minmax(0, 1fr); + gap: 12px; + padding: 14px 0; + } + + .oc-transport-dispatch li p { + font-size: 12px; + } + .oc-about-page { padding-bottom: 54px; } @@ -6864,3 +13368,2507 @@ body.oc-lightbox-open { gap: 6px; } } + +@media (max-width: 980px) { + .oc-home-brand-story { + padding: 88px 0 82px; + } + + .oc-brand-story-layout { + grid-template-columns: minmax(0, 0.9fr) minmax(0, 1.1fr); + gap: 46px; + } + + .oc-brand-story-copy h2 { + font-size: clamp(40px, 5.5vw, 52px); + } + + .oc-brand-story-copy > p { + margin-top: 26px; + font-size: 15px; + } + + .oc-brand-story-copy blockquote { + margin-top: 28px; + font-size: 19px; + } + + .oc-brand-values { + grid-template-columns: repeat(3, minmax(0, 1fr)); + row-gap: 42px; + margin-top: 68px; + } +} + +@media (max-width: 640px) { + .oc-home-brand-story { + padding: 64px 0 66px; + } + + .oc-brand-story-layout { + grid-template-columns: 1fr; + gap: 42px; + } + + .oc-brand-story-media { + aspect-ratio: 4 / 4.8; + } + + .oc-brand-eyebrow { + margin-bottom: 22px; + } + + .oc-brand-story-copy h2 { + font-size: 38px; + line-height: 1.12; + } + + .oc-brand-story-copy > p { + font-size: 15px; + line-height: 1.72; + } + + .oc-brand-story-copy blockquote { + padding-left: 18px; + font-size: 18px; + line-height: 1.6; + } + + .oc-brand-values { + grid-template-columns: 1fr; + gap: 0; + margin-top: 56px; + } + + .oc-brand-value { + display: grid; + grid-template-columns: 42px minmax(0, 1fr); + column-gap: 10px; + padding: 22px 0; + } + + .oc-brand-value > span { + grid-row: 1 / span 2; + margin: 4px 0 0; + } + + .oc-brand-value h3 { + min-height: 0; + font-size: 18px; + } + + .oc-brand-value p { + margin-top: 8px; + } +} + +@media (max-width: 980px) { + .oc-home-experiences { + margin-top: 86px; + } + + .oc-home-experiences .oc-section-title h2 { + font-size: 52px; + } + + .oc-experience-band { + min-height: 660px; + grid-template-rows: 380px minmax(280px, 1fr); + } + + .oc-experience-band-content { + padding: 24px 22px 25px; + } + + .oc-experience-band h3 { + font-size: 27px; + } +} + +@media (max-width: 820px) { + .oc-home-experiences .oc-section-title { + margin-bottom: 38px; + } + + .oc-experience-stack { + grid-template-columns: 1fr; + gap: 24px; + } + + .oc-experience-band, + .oc-experience-band.tan, + .oc-experience-band.clay, + .oc-experience-band.charcoal { + min-height: 390px; + display: grid; + grid-template-columns: minmax(0, 0.86fr) minmax(0, 1.14fr); + grid-template-rows: 1fr; + } + + .oc-experience-band-media, + .oc-experience-band img { + width: 100%; + height: 100%; + min-height: 390px; + } + + .oc-experience-band-content { + min-width: 0; + align-items: flex-start; + justify-items: initial; + padding: 34px 32px 30px; + } + + .oc-experience-band-meta { + margin-bottom: 28px; + } + + .oc-experience-band p { + font-size: 14px; + } +} + +@media (max-width: 640px) { + .oc-home-experiences { + margin-top: 68px; + } + + .oc-home-experiences .oc-section-title h2 { + font-size: 38px; + line-height: 1.12; + } + + .oc-home-experiences .oc-section-title p { + margin-top: 18px; + font-size: 14px; + line-height: 1.65; + } + + .oc-experience-band, + .oc-experience-band.tan, + .oc-experience-band.clay, + .oc-experience-band.charcoal { + min-height: 0; + display: grid; + grid-template-columns: 1fr; + grid-template-rows: auto auto; + text-align: left; + } + + .oc-experience-band-media { + aspect-ratio: 4 / 4.6; + min-height: 0; + } + + .oc-experience-band img { + width: 100%; + height: 100%; + min-height: 0; + } + + .oc-experience-band-content { + min-height: 286px; + padding: 24px 22px 24px; + } + + .oc-experience-band-meta { + margin-bottom: 22px; + } + + .oc-experience-band-meta span { + font-size: 9px; + } + + .oc-experience-band h3 { + margin: 0; + font-size: 28px; + line-height: 1.18; + } + + .oc-experience-band p { + margin-top: 14px; + font-size: 13px; + } + + .oc-experience-band small { + font-size: 9px; + } +} + +@media (max-width: 980px) { + .oc-home-safaris-section { + padding: 90px 0 88px; + } + + .oc-home-safaris-section .oc-section-title h2 { + font-size: 52px; + } + + .oc-home-safaris { + gap: 16px; + } + + .oc-home-safari { + min-height: 790px; + } + + .oc-home-safari-body { + padding: 24px 21px 24px; + } + + .oc-home-safari h3 { + font-size: 27px; + } +} + +@media (max-width: 820px) { + .oc-home-safaris { + grid-template-columns: 1fr; + gap: 24px; + } + + .oc-home-safari { + min-height: 560px; + display: grid; + grid-template-columns: minmax(0, 0.82fr) minmax(0, 1.18fr); + } + + .oc-home-safari-media, + .oc-home-safari-image { + width: 100%; + height: 100%; + min-height: 560px; + } + + .oc-home-safari-body { + min-width: 0; + padding: 34px 32px 30px; + } + + .oc-home-safari p { + font-size: 14px; + } + + .oc-home-safari-highlights li { + font-size: 13px; + } +} + +@media (max-width: 640px) { + .oc-home-safaris-section { + margin-top: 84px; + padding: 68px 0 70px; + } + + .oc-home-safaris-section .oc-section-title { + margin-bottom: 38px; + } + + .oc-home-safaris-section .oc-section-title h2 { + font-size: 38px; + line-height: 1.12; + } + + .oc-home-safaris-section .oc-section-title p { + margin-top: 18px; + font-size: 14px; + line-height: 1.65; + } + + .oc-home-safari { + min-height: 0; + display: grid; + grid-template-columns: 1fr; + grid-template-rows: auto auto; + } + + .oc-home-safari-media { + aspect-ratio: 4 / 3.35; + height: auto; + min-height: 0; + } + + .oc-home-safari-image { + width: 100%; + height: 100%; + min-height: 0; + } + + .oc-home-safari-body { + min-width: 0; + padding: 25px 22px 24px; + } + + .oc-home-safari .oc-home-safari-meta { + font-size: 9px; + line-height: 1.5; + } + + .oc-home-safari h3 { + margin: 18px 0 0; + font-size: 29px; + line-height: 1.18; + } + + .oc-home-safari p { + display: block; + margin-top: 14px; + overflow: visible; + font-size: 13px; + line-height: 1.65; + -webkit-line-clamp: unset; + line-clamp: unset; + } + + .oc-home-safari-highlights { + margin: 22px 0 26px; + } + + .oc-home-safari-highlights li { + padding-top: 11px; + padding-bottom: 11px; + font-size: 12px; + } + + .oc-home-safari-highlights li::before { + top: 18px; + } + + .oc-home-safari-footer b { + margin: 0; + padding: 0; + border: 0; + font-size: 10px; + } + + .oc-home-safari .oc-card-action { + justify-content: space-between; + margin: 0; + padding-top: 16px; + border-top: 1px solid rgba(39, 54, 45, 0.2); + } +} + +@media (max-width: 980px) { + .oc-home-team-layout { + gap: 48px; + } + + .oc-home-team-media { + min-height: 650px; + } + + .oc-home-team-main-image { + height: 470px; + } + + .oc-home-team-field-image { + height: 260px; + } + + .oc-home-team-copy h2 { + font-size: 48px; + } +} + +@media (max-width: 820px) { + .oc-home-team { + margin-top: 98px; + } + + .oc-home-team-layout { + grid-template-columns: 1fr; + gap: 58px; + } + + .oc-home-team-media { + min-height: 680px; + } + + .oc-home-team-main-image { + height: 520px; + } + + .oc-home-team-field-image { + width: 62%; + height: 270px; + } + + .oc-home-team-copy { + max-width: 650px; + } +} + +@media (max-width: 640px) { + .oc-home-team { + margin-top: 76px; + } + + .oc-home-team-layout { + gap: 46px; + } + + .oc-home-team-media { + min-height: 448px; + } + + .oc-home-team-main-image { + width: 100%; + height: 320px; + } + + .oc-home-team-field-image { + width: 70%; + height: 190px; + border-width: 8px; + } + + .oc-home-team-copy h2 { + font-size: 38px; + line-height: 1.12; + } + + .oc-home-team-intro { + margin-top: 22px; + font-size: 14px; + line-height: 1.7; + } + + .oc-home-team-services { + margin-top: 34px; + } + + .oc-home-team-service { + grid-template-columns: 34px minmax(0, 1fr); + gap: 10px; + padding: 20px 0; + } + + .oc-home-team-service h3 { + font-size: 18px; + } + + .oc-home-team-service p { + font-size: 12px; + } + + .oc-home-team-cta { + width: 100%; + margin-top: 28px; + } +} + +@media (max-width: 820px) { + .oc-live { + margin-top: 94px; + padding-bottom: 72px; + } + + .oc-live h2 { + font-size: 50px; + } + + .oc-live-grid { + grid-template-columns: repeat(2, minmax(0, 1fr)); + grid-auto-rows: 250px; + } + + .oc-live-photo:first-child { + grid-column: span 2; + grid-row: span 2; + } +} + +@media (max-width: 540px) { + .oc-live { + width: min(100% - 32px, 700px); + margin-top: 76px; + padding-bottom: 58px; + } + + .oc-live-heading { + margin-bottom: 34px; + } + + .oc-live h2 { + font-size: 38px; + line-height: 1.12; + } + + .oc-live-heading > p { + margin-top: 18px; + font-size: 14px; + line-height: 1.65; + } + + .oc-live-grid { + grid-template-columns: 1fr; + grid-auto-rows: 300px; + gap: 14px; + } + + .oc-live-photo:first-child { + grid-column: span 1; + grid-row: span 1; + } + + .oc-live-photo figcaption { + padding: 28px 15px 14px; + font-size: 11px; + } +} + +@media (max-width: 820px) { + .oc-home-comparison { + padding: 88px 0 92px; + } + + .oc-comparison-heading h2 { + font-size: 50px; + } + + .oc-comparison-table { + min-width: 900px; + } + + .oc-comparison-table thead th:first-child, + .oc-comparison-table tbody th { + position: sticky; + left: 0; + z-index: 2; + background: #ebe9e1; + box-shadow: 12px 0 18px rgba(36, 51, 40, 0.06); + } + + .oc-comparison-table thead th:first-child { + z-index: 3; + } + + .oc-home-final-cta { + padding: 92px 0 96px; + } + + .oc-home-final-cta-layout { + grid-template-columns: 1fr; + gap: 58px; + } + + .oc-home-final-cta-copy { + max-width: 680px; + } + + .oc-home-inquiry-prompts { + max-width: 680px; + } +} + +@media (max-width: 540px) { + .oc-home-comparison { + padding: 70px 0 74px; + } + + .oc-comparison-heading { + margin-bottom: 36px; + } + + .oc-comparison-heading h2 { + font-size: 38px; + line-height: 1.12; + } + + .oc-comparison-heading > p { + margin-top: 18px; + font-size: 14px; + line-height: 1.65; + } + + .oc-comparison-table { + min-width: 820px; + } + + .oc-comparison-table th, + .oc-comparison-table td { + padding: 18px 15px; + font-size: 12px; + } + + .oc-comparison-table thead th:first-child, + .oc-comparison-table tbody th { + width: 112px; + font-size: 10px; + } + + .oc-home-final-cta { + padding: 72px 0 76px; + } + + .oc-home-final-cta::before { + top: -210px; + right: -300px; + width: 560px; + height: 560px; + } + + .oc-home-final-cta-layout { + gap: 48px; + } + + .oc-home-final-cta h2 { + margin-top: 18px; + font-size: 38px; + line-height: 1.12; + } + + .oc-home-final-cta-copy > p { + margin-top: 20px; + font-size: 14px; + line-height: 1.68; + } + + .oc-home-final-cta-button { + width: 100%; + min-width: 0; + margin-top: 30px; + padding-right: 18px; + padding-left: 18px; + } + + .oc-home-inquiry-prompt { + grid-template-columns: 34px minmax(0, 1fr); + gap: 10px; + padding: 20px 0; + } + + .oc-home-inquiry-prompt h3 { + font-size: 18px; + } +} + +/* Route archive — three editorial starting points from the customer route brief. */ +.oc-routes-editorial { + position: relative; + z-index: 1; + padding: 70px 0 112px; +} + +.oc-routes-editorial-heading { + max-width: 820px; + margin-bottom: 58px; +} + +.oc-routes-editorial-heading h2 { + color: #29372e; + font-family: Georgia, 'Times New Roman', serif; + font-size: clamp(48px, 5vw, 66px); + font-weight: 400; + line-height: 1.08; + letter-spacing: -0.035em; + text-wrap: balance; +} + +.oc-routes-editorial-heading > p { + max-width: 700px; + margin-top: 24px; + color: #626d65; + font-size: 16px; + line-height: 1.76; +} + +.oc-routes-editorial .oc-safari-grid { + display: grid; + grid-template-columns: 1fr; + gap: 28px; +} + +.oc-routes-editorial .oc-safari-card { + display: grid; + grid-template-columns: minmax(340px, 0.88fr) minmax(0, 1.12fr); + width: 100%; + max-width: none; + min-height: 590px; + overflow: hidden; + border: 1px solid rgba(39, 54, 45, 0.14); + border-radius: 0; + background: #f0efe8; + color: #29372e; + box-shadow: none; +} + +.oc-routes-editorial .oc-safari-card:nth-child(even) { + grid-template-columns: minmax(0, 1.12fr) minmax(340px, 0.88fr); +} + +.oc-routes-editorial .oc-safari-card:nth-child(even) .oc-safari-card-image { + order: 2; +} + +.oc-routes-editorial .oc-safari-card-image { + height: 100%; + min-height: 590px; + overflow: hidden; +} + +.oc-routes-editorial .oc-safari-card-image::after { + content: ''; + position: absolute; + inset: 0; + background: linear-gradient(180deg, rgba(24, 50, 34, 0.02), rgba(24, 50, 34, 0.18)); + pointer-events: none; +} + +.oc-routes-editorial .oc-safari-card-image img { + width: 100%; + height: 100%; + display: block; + object-fit: cover; + filter: saturate(0.74) contrast(0.95); + transition: transform 0.45s ease, filter 0.45s ease; +} + +.oc-routes-editorial .oc-safari-card:hover .oc-safari-card-image img, +.oc-routes-editorial .oc-safari-card:focus-visible .oc-safari-card-image img { + transform: scale(1.025); + filter: saturate(0.88) contrast(0.98); +} + +.oc-routes-editorial .oc-safari-card-image > span { + top: 22px; + left: 22px; + z-index: 2; + min-width: 42px; + height: 42px; + display: inline-flex; + align-items: center; + justify-content: center; + padding: 0; + background: rgba(242, 241, 233, 0.9); + color: #2d4534; + font-size: 10px; + font-weight: 700; + letter-spacing: 0.12em; +} + +.oc-routes-editorial .oc-safari-card-body { + min-height: 0; + display: flex; + flex-direction: column; + gap: 0; + padding: clamp(38px, 5vw, 64px); +} + +.oc-routes-editorial .oc-safari-card-body > p:first-child, +.oc-routes-editorial .oc-safari-card-kicker { + margin: 0; + color: #667269; + font-size: 10px; + font-weight: 700; + line-height: 1.45; + letter-spacing: 0.1em; + text-transform: uppercase; +} + +.oc-routes-editorial .oc-safari-card-body h3 { + max-width: 650px; + margin: 18px 0 0; + color: #27362d; + font-family: Georgia, 'Times New Roman', serif; + font-size: clamp(36px, 3.7vw, 50px); + font-weight: 400; + line-height: 1.08; + letter-spacing: -0.03em; + text-wrap: balance; +} + +.oc-routes-editorial .oc-safari-card-summary { + max-width: 660px; + margin-top: 20px; + color: #626d65; + font-size: 14px; + line-height: 1.72; +} + +.oc-safari-card-route-line { + margin-top: 18px; + padding-left: 15px; + border-left: 1px solid #738679; + color: #425148; + font-size: 12px; + line-height: 1.62; +} + +.oc-safari-card-decision { + display: grid; + grid-template-columns: 0.72fr 0.72fr 1.56fr; + margin-top: 28px; + border-top: 1px solid rgba(39, 54, 45, 0.16); + border-bottom: 1px solid rgba(39, 54, 45, 0.16); +} + +.oc-safari-card-decision > div { + min-width: 0; + padding: 15px 14px 16px 0; +} + +.oc-safari-card-decision > div + div { + padding-left: 14px; + border-left: 1px solid rgba(39, 54, 45, 0.12); +} + +.oc-safari-card-decision span, +.oc-safari-card-highlights > span { + display: block; + color: #728077; + font-size: 9px; + font-weight: 700; + letter-spacing: 0.1em; + text-transform: uppercase; +} + +.oc-safari-card-decision strong { + display: block; + margin-top: 6px; + color: #37483d; + font-size: 11px; + font-weight: 600; + line-height: 1.45; +} + +.oc-safari-card-highlights { + margin-top: 24px; +} + +.oc-safari-card-highlights ol { + display: grid; + grid-template-columns: repeat(3, minmax(0, 1fr)); + gap: 12px; + margin: 13px 0 0; + padding: 0; + list-style: none; + counter-reset: route-highlight; +} + +.oc-safari-card-highlights li { + position: relative; + min-width: 0; + padding: 10px 0 0 24px; + border-top: 1px solid rgba(39, 54, 45, 0.14); + color: #3e4c43; + font-size: 11px; + line-height: 1.5; + counter-increment: route-highlight; +} + +.oc-safari-card-highlights li::before { + content: counter(route-highlight, decimal-leading-zero); + position: absolute; + top: 11px; + left: 0; + color: #738679; + font-size: 8px; + font-weight: 700; + letter-spacing: 0.08em; +} + +.oc-routes-editorial .oc-safari-card-body > .oc-card-action { + width: 100%; + display: flex; + align-items: center; + justify-content: space-between; + gap: 12px; + margin-top: auto; + padding-top: 25px; + border-top: 1px solid rgba(39, 54, 45, 0.2); + color: #31503a; + font-size: 10px; + font-weight: 700; + letter-spacing: 0.11em; + text-transform: uppercase; +} + +@media (prefers-reduced-motion: reduce) { + .oc-routes-editorial .oc-safari-card-image img { + transition: none; + } +} + +@media (max-width: 900px) { + .oc-routes-editorial { + padding-top: 54px; + padding-bottom: 92px; + } + + .oc-routes-editorial .oc-safari-card, + .oc-routes-editorial .oc-safari-card:nth-child(even) { + grid-template-columns: 1fr; + min-height: 0; + } + + .oc-routes-editorial .oc-safari-card:nth-child(even) .oc-safari-card-image { + order: 0; + } + + .oc-routes-editorial .oc-safari-card-image { + height: 370px; + min-height: 0; + } + + .oc-routes-editorial .oc-safari-card-body { + padding: 42px; + } +} + +@media (max-width: 540px) { + .oc-routes-editorial { + width: min(100% - 32px, 700px); + padding: 42px 0 72px; + } + + .oc-routes-editorial-heading { + margin-bottom: 36px; + } + + .oc-routes-editorial-heading h2 { + font-size: 38px; + line-height: 1.12; + } + + .oc-routes-editorial-heading > p { + margin-top: 18px; + font-size: 14px; + line-height: 1.68; + } + + .oc-routes-editorial .oc-safari-grid { + display: grid; + grid-template-columns: 1fr; + gap: 18px; + } + + .oc-routes-editorial .oc-safari-card, + .oc-routes-editorial .oc-safari-card:nth-child(even) { + display: grid; + grid-template-columns: 1fr; + grid-template-rows: auto auto; + width: 100%; + min-height: 0; + text-align: left; + } + + .oc-routes-editorial .oc-safari-card-image { + width: 100%; + height: 255px; + min-height: 255px; + } + + .oc-routes-editorial .oc-safari-card-body { + min-height: 0; + display: flex; + padding: 27px 22px 24px; + } + + .oc-routes-editorial .oc-safari-card-body h3 { + margin-top: 13px; + font-size: 30px; + line-height: 1.1; + } + + .oc-routes-editorial .oc-safari-card-summary { + display: block; + margin-top: 16px; + font-size: 13px; + line-height: 1.64; + -webkit-line-clamp: unset; + line-clamp: unset; + } + + .oc-safari-card-route-line { + margin-top: 15px; + font-size: 11px; + } + + .oc-safari-card-decision { + grid-template-columns: repeat(2, minmax(0, 1fr)); + margin-top: 22px; + } + + .oc-safari-card-decision > div:nth-child(3) { + grid-column: 1 / -1; + padding-left: 0; + border-top: 1px solid rgba(39, 54, 45, 0.12); + border-left: 0; + } + + .oc-safari-card-highlights ol { + grid-template-columns: 1fr; + gap: 0; + } + + .oc-safari-card-highlights li { + padding-top: 11px; + padding-bottom: 11px; + } + + .oc-routes-editorial .oc-safari-card-body > .oc-card-action { + margin-top: 22px; + padding-top: 18px; + } +} + +/* Classic Panorama detail — route brief implementation. */ +.is-classic-panorama .oc-route-summary, +.is-outdoor-adventure .oc-route-summary, +.is-balanced-discovery .oc-route-summary { + padding-top: 52px; + padding-bottom: 92px; +} + +.oc-classic-fact-grid { + display: grid; + grid-template-columns: repeat(3, minmax(0, 1fr)); + margin: 34px 0 28px; + border-top: 1px solid rgba(39, 54, 45, 0.2); + border-bottom: 1px solid rgba(39, 54, 45, 0.2); +} + +.oc-classic-fact-grid > div { + min-width: 0; + padding: 18px 16px 18px 0; +} + +.oc-classic-fact-grid > div:not(:nth-child(3n + 1)) { + padding-left: 16px; + border-left: 1px solid rgba(39, 54, 45, 0.12); +} + +.oc-classic-fact-grid > div:nth-child(n + 4) { + border-top: 1px solid rgba(39, 54, 45, 0.12); +} + +.oc-classic-fact-grid dt { + color: #718077; + font-size: 9px; + font-weight: 700; + letter-spacing: 0.11em; + text-transform: uppercase; +} + +.oc-classic-fact-grid dd { + margin: 7px 0 0; + color: #34473a; + font-size: 12px; + font-weight: 600; + line-height: 1.52; +} + +.oc-classic-why { + padding: 110px 0 118px; + border-top: 1px solid rgba(39, 54, 45, 0.14); +} + +.oc-classic-why .oc-route-section-head { + margin-bottom: 52px; +} + +.oc-classic-why .oc-route-section-head > div, +.oc-classic-practical .oc-route-section-head > div { + display: grid; + gap: 14px; +} + +.oc-classic-why-grid { + display: grid; + grid-template-columns: repeat(3, minmax(0, 1fr)); + gap: 18px; +} + +.oc-classic-why-grid article { + min-width: 0; + background: #efeee7; +} + +.oc-classic-why-grid img { + width: 100%; + height: 320px; + display: block; + object-fit: cover; + filter: saturate(0.76) contrast(0.95); +} + +.oc-classic-why-grid article > div { + min-height: 230px; + padding: 28px 26px 30px; +} + +.oc-classic-why-grid article span { + color: #718077; + font-size: 9px; + font-weight: 700; + letter-spacing: 0.12em; +} + +.oc-classic-why-grid h3 { + margin-top: 16px; + color: #2f4035; + font-family: Georgia, 'Times New Roman', serif; + font-size: 24px; + font-weight: 400; + line-height: 1.3; +} + +.oc-classic-why-grid p { + margin-top: 14px; + color: #626d65; + font-size: 13px; + line-height: 1.68; +} + +.is-classic-panorama .oc-route-flow, +.is-outdoor-adventure .oc-route-flow, +.is-balanced-discovery .oc-route-flow { + padding-top: 110px; + border-top: 1px solid rgba(39, 54, 45, 0.14); +} + +.oc-route-flow figure.oc-classic-route-map { + background: #183222; +} + +.oc-classic-route-map-head { + display: grid; + gap: 8px; + padding: 24px 24px 20px; + border-bottom: 1px solid rgba(255, 255, 255, 0.14); +} + +.oc-classic-route-map-head span { + color: #b7d3af; + font-size: 10px; + font-weight: 700; + letter-spacing: 0.13em; + text-transform: uppercase; +} + +.oc-classic-route-map-head strong { + color: #f1f5ec; + font-family: Georgia, 'Times New Roman', serif; + font-size: 22px; + font-weight: 400; + line-height: 1.3; +} + +.oc-classic-route-map ol { + margin: 0; + padding: 10px 24px 16px; + list-style: none; +} + +.oc-classic-route-map li { + position: relative; + display: grid; + grid-template-columns: 36px minmax(0, 1fr); + gap: 12px; + align-items: start; + padding: 16px 0; +} + +.oc-classic-route-map li:not(:last-child)::after { + content: ''; + position: absolute; + top: 44px; + bottom: -4px; + left: 16px; + width: 1px; + background: rgba(183, 211, 175, 0.26); +} + +.oc-classic-route-map li > span { + position: relative; + z-index: 1; + width: 33px; + height: 33px; + display: inline-grid; + place-items: center; + border: 1px solid rgba(183, 211, 175, 0.42); + border-radius: 50%; + background: #183222; + color: #d9ead3; + font-size: 8px; + font-weight: 700; + letter-spacing: 0.08em; +} + +.oc-classic-route-map li b, +.oc-classic-route-map li small { + display: block; +} + +.oc-classic-route-map li b { + color: #f1f5ec; + font-family: Georgia, 'Times New Roman', serif; + font-size: 17px; + font-weight: 400; + line-height: 1.3; +} + +.oc-classic-route-map li small { + margin-top: 4px; + color: rgba(239, 245, 235, 0.62); + font-size: 10px; + line-height: 1.45; +} + +.oc-route-day-schedule { + display: grid; + grid-template-columns: repeat(2, minmax(0, 1fr)); + gap: 0; + margin: 18px 0 14px; + border-top: 1px solid rgba(39, 54, 45, 0.14); + border-bottom: 1px solid rgba(39, 54, 45, 0.14); +} + +.oc-route-day-schedule > div { + display: grid; + grid-template-columns: 62px minmax(0, 1fr); + gap: 10px; + padding: 11px 12px 11px 0; +} + +.oc-route-day-schedule > div:nth-child(even) { + padding-right: 0; + padding-left: 12px; + border-left: 1px solid rgba(39, 54, 45, 0.1); +} + +.oc-route-day-schedule > div:nth-child(n + 3) { + border-top: 1px solid rgba(39, 54, 45, 0.1); +} + +.oc-route-day-schedule dt { + color: #708077; + font-size: 9px; + font-weight: 700; + letter-spacing: 0.08em; + text-transform: uppercase; +} + +.oc-route-day-schedule dd { + margin: 0; + color: #526159; + font-size: 11px; + line-height: 1.55; +} + +.oc-classic-practical { + margin-bottom: 96px; + padding: 104px 0 110px; + background: #ebe9e1; +} + +.oc-classic-practical .oc-route-section-head { + margin-bottom: 48px; +} + +.oc-classic-practical-grid { + display: grid; + grid-template-columns: repeat(3, minmax(0, 1fr)); + border-top: 1px solid rgba(39, 54, 45, 0.2); + border-left: 1px solid rgba(39, 54, 45, 0.14); +} + +.oc-classic-practical-grid article { + min-height: 210px; + padding: 26px 24px 28px; + border-right: 1px solid rgba(39, 54, 45, 0.14); + border-bottom: 1px solid rgba(39, 54, 45, 0.14); +} + +.oc-classic-practical-grid article > span { + color: #718077; + font-size: 9px; + font-weight: 700; + letter-spacing: 0.12em; +} + +.oc-classic-practical-grid h3 { + margin-top: 22px; + color: #304036; + font-family: Georgia, 'Times New Roman', serif; + font-size: 21px; + font-weight: 400; + line-height: 1.32; +} + +.oc-classic-practical-grid p { + margin-top: 13px; + color: #626d65; + font-size: 12px; + line-height: 1.68; +} + +/* Karst Outdoor detail — graded adventure and operating gates. */ +.is-outdoor-adventure .oc-detail-strip img, +.is-outdoor-adventure .oc-classic-why-grid img { + filter: saturate(0.72) contrast(0.98); +} + +.oc-outdoor-why { + background: #f5f3ed; +} + +.oc-outdoor-grades { + padding: 112px 0 120px; + background: #1a2e22; + color: #edf2e9; +} + +.oc-outdoor-grades .oc-route-section-head { + margin-bottom: 54px; +} + +.oc-outdoor-grades .oc-route-section-head > div { + display: grid; + gap: 14px; +} + +.oc-outdoor-grades .oc-route-section-head span, +.oc-outdoor-grades .oc-route-section-head > p { + color: rgba(232, 241, 229, 0.64); +} + +.oc-outdoor-grades .oc-route-section-head h2 { + color: #f2f5ee; +} + +.oc-outdoor-grade-grid { + display: grid; + grid-template-columns: repeat(3, minmax(0, 1fr)); + border-top: 1px solid rgba(226, 239, 220, 0.2); + border-left: 1px solid rgba(226, 239, 220, 0.14); +} + +.oc-outdoor-grade-grid article { + min-height: 310px; + padding: 30px 28px 32px; + border-right: 1px solid rgba(226, 239, 220, 0.14); + border-bottom: 1px solid rgba(226, 239, 220, 0.14); +} + +.oc-outdoor-grade-grid article > span { + color: #a9c69f; + font-size: 9px; + font-weight: 700; + letter-spacing: 0.12em; + text-transform: uppercase; +} + +.oc-outdoor-grade-grid h3 { + margin-top: 28px; + color: #f1f5ed; + font-family: Georgia, 'Times New Roman', serif; + font-size: 24px; + font-weight: 400; + line-height: 1.3; +} + +.oc-outdoor-grade-grid p { + margin-top: 17px; + color: rgba(235, 242, 231, 0.74); + font-size: 13px; + line-height: 1.7; +} + +.oc-outdoor-grade-grid small { + display: block; + margin-top: 28px; + padding-top: 20px; + border-top: 1px solid rgba(226, 239, 220, 0.13); + color: rgba(235, 242, 231, 0.52); + font-size: 10px; + line-height: 1.65; +} + +.oc-outdoor-gate { + display: grid; + grid-template-columns: minmax(250px, 0.72fr) minmax(0, 1.5fr); + gap: 54px; + margin-top: 56px; + padding-top: 48px; + border-top: 1px solid rgba(226, 239, 220, 0.22); +} + +.oc-outdoor-gate-intro > span { + color: #b7d3ad; + font-size: 10px; + font-weight: 700; + letter-spacing: 0.15em; +} + +.oc-outdoor-gate-intro h3 { + margin-top: 18px; + color: #f1f5ed; + font-family: Georgia, 'Times New Roman', serif; + font-size: 28px; + font-weight: 400; + line-height: 1.28; +} + +.oc-outdoor-gate-intro p { + margin-top: 17px; + color: rgba(235, 242, 231, 0.62); + font-size: 12px; + line-height: 1.7; +} + +.oc-outdoor-gate ol { + display: grid; + grid-template-columns: repeat(2, minmax(0, 1fr)); + margin: 0; + padding: 0; + list-style: none; + border-top: 1px solid rgba(226, 239, 220, 0.16); + border-left: 1px solid rgba(226, 239, 220, 0.12); +} + +.oc-outdoor-gate li { + display: grid; + grid-template-columns: 28px minmax(0, 1fr); + gap: 13px; + padding: 22px 20px; + border-right: 1px solid rgba(226, 239, 220, 0.12); + border-bottom: 1px solid rgba(226, 239, 220, 0.12); +} + +.oc-outdoor-gate li > span { + color: #9fbb96; + font-size: 9px; + font-weight: 700; + letter-spacing: 0.08em; +} + +.oc-outdoor-gate li b { + color: #eff4eb; + font-family: Georgia, 'Times New Roman', serif; + font-size: 16px; + font-weight: 400; +} + +.oc-outdoor-gate li p { + margin-top: 8px; + color: rgba(235, 242, 231, 0.58); + font-size: 10px; + line-height: 1.62; +} + +.is-outdoor-adventure .oc-route-flow figure.oc-classic-route-map { + background: #14281d; +} + +.is-outdoor-adventure .oc-classic-route-map li > span { + background: #14281d; +} + +.oc-outdoor-practical { + background: #e7ebe3; +} + +/* Balanced Discovery detail — village depth, local-led days and visible flexibility. */ +.is-balanced-discovery .oc-detail-strip img, +.is-balanced-discovery .oc-classic-why-grid img { + filter: saturate(0.78) contrast(0.96); +} + +.oc-balanced-why { + background: #f6f0e6; +} + +.oc-balanced-framework { + padding: 112px 0 120px; + background: #eee6d8; +} + +.oc-balanced-framework .oc-route-section-head { + margin-bottom: 54px; +} + +.oc-balanced-framework .oc-route-section-head > div { + display: grid; + gap: 14px; +} + +.oc-balanced-layer-grid { + display: grid; + grid-template-columns: repeat(3, minmax(0, 1fr)); + gap: 18px; +} + +.oc-balanced-layer-grid article { + min-height: 300px; + padding: 30px 28px 32px; + background: #faf7f0; + border-top: 3px solid #64765d; +} + +.oc-balanced-layer-grid article:nth-child(2) { + border-top-color: #9a7754; +} + +.oc-balanced-layer-grid article:nth-child(3) { + border-top-color: #768b81; +} + +.oc-balanced-layer-grid article > span { + color: #7b7b6d; + font-size: 9px; + font-weight: 700; + letter-spacing: 0.13em; + text-transform: uppercase; +} + +.oc-balanced-layer-grid h3 { + margin-top: 30px; + color: #3b463d; + font-family: Georgia, 'Times New Roman', serif; + font-size: 24px; + font-weight: 400; + line-height: 1.32; +} + +.oc-balanced-layer-grid p { + margin-top: 18px; + color: #66685f; + font-size: 13px; + line-height: 1.72; +} + +.oc-balanced-flex { + display: grid; + grid-template-columns: minmax(250px, 0.78fr) minmax(0, 1.5fr); + gap: 56px; + margin-top: 54px; + padding: 48px 42px; + background: #34463a; +} + +.oc-balanced-flex > div > span { + color: #bdcdb7; + font-size: 9px; + font-weight: 700; + letter-spacing: 0.14em; + text-transform: uppercase; +} + +.oc-balanced-flex > div > h3 { + margin-top: 19px; + color: #f1f2ec; + font-family: Georgia, 'Times New Roman', serif; + font-size: 27px; + font-weight: 400; + line-height: 1.3; +} + +.oc-balanced-flex dl { + margin: 0; + border-top: 1px solid rgba(236, 241, 233, 0.18); +} + +.oc-balanced-flex dl > div { + display: grid; + grid-template-columns: 130px minmax(0, 1fr); + gap: 20px; + padding: 17px 0; + border-bottom: 1px solid rgba(236, 241, 233, 0.14); +} + +.oc-balanced-flex dt { + color: #b9cbb4; + font-size: 9px; + font-weight: 700; + letter-spacing: 0.08em; + text-transform: uppercase; +} + +.oc-balanced-flex dd { + margin: 0; + color: rgba(240, 244, 237, 0.76); + font-size: 11px; + line-height: 1.65; +} + +.is-balanced-discovery .oc-route-flow figure.oc-classic-route-map { + background: #3d493d; +} + +.is-balanced-discovery .oc-classic-route-map li > span { + background: #3d493d; +} + +.oc-balanced-practical { + background: #eee9df; +} + +@media (max-width: 900px) { + .oc-classic-fact-grid, + .oc-classic-why-grid, + .oc-classic-practical-grid { + grid-template-columns: repeat(2, minmax(0, 1fr)); + } + + .oc-classic-fact-grid > div:not(:nth-child(3n + 1)) { + padding-left: 0; + border-left: 0; + } + + .oc-classic-fact-grid > div:nth-child(even) { + padding-left: 16px; + border-left: 1px solid rgba(39, 54, 45, 0.12); + } + + .oc-classic-fact-grid > div:nth-child(n + 3) { + border-top: 1px solid rgba(39, 54, 45, 0.12); + } + + .oc-classic-why-grid article:last-child { + grid-column: 1 / -1; + } + + .oc-outdoor-grade-grid { + grid-template-columns: repeat(2, minmax(0, 1fr)); + } + + .oc-outdoor-grade-grid article:last-child { + grid-column: 1 / -1; + } + + .oc-outdoor-gate { + grid-template-columns: 1fr; + } + + .oc-balanced-layer-grid { + grid-template-columns: repeat(2, minmax(0, 1fr)); + } + + .oc-balanced-layer-grid article:last-child { + grid-column: 1 / -1; + } + + .oc-balanced-flex { + grid-template-columns: 1fr; + } +} + +@media (max-width: 540px) { + .is-classic-panorama .oc-route-summary, + .is-outdoor-adventure .oc-route-summary, + .is-balanced-discovery .oc-route-summary { + padding-top: 40px; + padding-bottom: 68px; + } + + .oc-classic-fact-grid { + grid-template-columns: 1fr; + margin-top: 26px; + } + + .oc-classic-fact-grid > div, + .oc-classic-fact-grid > div:nth-child(even) { + padding: 14px 0; + border-top: 1px solid rgba(39, 54, 45, 0.1); + border-left: 0; + } + + .oc-classic-fact-grid > div:first-child { + border-top: 0; + } + + .oc-classic-why { + padding: 76px 0 80px; + } + + .oc-classic-why .oc-route-section-head, + .oc-classic-practical .oc-route-section-head { + margin-bottom: 34px; + } + + .oc-classic-why-grid, + .oc-classic-practical-grid { + grid-template-columns: 1fr; + } + + .oc-classic-why-grid article:last-child { + grid-column: auto; + } + + .oc-classic-why-grid img { + height: 260px; + } + + .oc-classic-why-grid article > div { + min-height: 0; + padding: 24px 22px 27px; + } + + .is-classic-panorama .oc-route-flow, + .is-outdoor-adventure .oc-route-flow, + .is-balanced-discovery .oc-route-flow { + padding-top: 74px; + } + + .oc-route-day-schedule { + grid-template-columns: 1fr; + } + + .oc-route-day-schedule > div, + .oc-route-day-schedule > div:nth-child(even) { + grid-template-columns: 54px minmax(0, 1fr); + padding: 10px 0; + border-top: 1px solid rgba(39, 54, 45, 0.1); + border-left: 0; + } + + .oc-route-day-schedule > div:first-child { + border-top: 0; + } + + .oc-classic-practical { + margin-bottom: 72px; + padding: 74px 0 78px; + } + + .oc-classic-practical-grid article { + min-height: 0; + padding: 24px 22px 26px; + } + + .oc-outdoor-grades { + padding: 76px 0 82px; + } + + .oc-outdoor-grades .oc-route-section-head { + margin-bottom: 36px; + } + + .oc-outdoor-grade-grid, + .oc-outdoor-gate ol { + grid-template-columns: 1fr; + } + + .oc-outdoor-grade-grid article, + .oc-outdoor-grade-grid article:last-child { + min-height: 0; + grid-column: auto; + padding: 25px 22px 27px; + } + + .oc-outdoor-gate { + gap: 32px; + margin-top: 42px; + padding-top: 38px; + } + + .oc-balanced-framework { + padding: 76px 0 82px; + } + + .oc-balanced-framework .oc-route-section-head { + margin-bottom: 36px; + } + + .oc-balanced-layer-grid { + grid-template-columns: 1fr; + } + + .oc-balanced-layer-grid article, + .oc-balanced-layer-grid article:last-child { + min-height: 0; + grid-column: auto; + padding: 25px 22px 27px; + } + + .oc-balanced-flex { + gap: 30px; + margin-top: 38px; + padding: 32px 24px; + } + + .oc-balanced-flex dl > div { + grid-template-columns: 1fr; + gap: 7px; + } +} + +/* Culture / living heritage landing */ +.oc-culture-page { + --culture-ink: #1f3028; + --culture-muted: #657069; + --culture-blue: #294f59; + --culture-paper: #f5f2e9; + --culture-line: rgba(31, 48, 40, 0.16); + overflow: clip; + color: var(--culture-ink); + background: var(--culture-paper); +} + +.oc-culture-hero { + display: grid; + grid-template-columns: minmax(0, 0.94fr) minmax(480px, 1.06fr); + min-height: min(820px, calc(100vh - 30px)); + background: #ecebe3; +} + +.oc-culture-hero-copy { + display: flex; + flex-direction: column; + justify-content: center; + padding: 82px clamp(42px, 5.2vw, 92px) 64px max(28px, calc((100vw - 1320px) / 2)); +} + +.oc-culture-hero-copy .oc-breadcrumb { + margin: 0 0 50px; +} + +.oc-culture-kicker, +.oc-culture-intro-copy > span, +.oc-culture-village-grid > div > span, +.oc-culture-section-head > span { + color: #527064; + font-size: 0.72rem; + font-weight: 700; + letter-spacing: 0.18em; + text-transform: uppercase; +} + +.oc-culture-hero-copy h1 { + max-width: 780px; + margin: 20px 0 24px; + font-size: clamp(2.9rem, 5vw, 5.8rem); + font-weight: 430; + line-height: 0.98; + letter-spacing: -0.055em; +} + +.oc-culture-hero-copy h1 em { + display: block; + margin-top: 0.12em; + color: var(--culture-blue); + font-family: Georgia, 'Times New Roman', serif; + font-weight: 400; +} + +.oc-culture-hero-copy > p { + max-width: 670px; + margin: 0; + color: #4e5d55; + font-size: clamp(1rem, 1.25vw, 1.18rem); + line-height: 1.78; +} + +.oc-culture-hero-actions { + display: flex; + align-items: center; + gap: 24px; + margin-top: 34px; +} + +.oc-culture-hero-actions a { + color: var(--culture-ink); + font-size: 0.8rem; + font-weight: 700; + letter-spacing: 0.07em; + text-transform: uppercase; +} + +.oc-culture-hero-actions .oc-culture-primary { + display: inline-flex; + align-items: center; + gap: 15px; + min-height: 50px; + padding: 0 20px; + color: #fff; + background: var(--culture-blue); +} + +.oc-culture-hero-actions svg, +.oc-culture-card-link svg, +.oc-culture-village-grid > div > a svg { + width: 17px; + height: 17px; + flex: 0 0 auto; +} + +.oc-culture-hero-facts { + display: grid; + grid-template-columns: 0.75fr 0.75fr 1.5fr; + gap: 22px; + margin: 52px 0 0; + padding-top: 22px; + border-top: 1px solid var(--culture-line); +} + +.oc-culture-hero-facts > div { + display: grid; + gap: 6px; +} + +.oc-culture-hero-facts dt { + color: var(--culture-blue); + font-family: Georgia, 'Times New Roman', serif; + font-size: 1.65rem; +} + +.oc-culture-hero-facts dd { + margin: 0; + color: var(--culture-muted); + font-size: 0.76rem; + line-height: 1.45; +} + +.oc-culture-hero-media { + position: relative; + min-height: 720px; + overflow: hidden; + background: #d6d8d0; +} + +.oc-culture-hero-media > img { + width: 100%; + height: 100%; + object-fit: cover; + object-position: 50% 50%; + filter: saturate(0.76) contrast(0.96); +} + +.oc-culture-hero-media > figure { + position: absolute; + right: clamp(22px, 3.5vw, 54px); + bottom: clamp(22px, 3.5vw, 54px); + width: min(31%, 235px); + margin: 0; + padding: 8px; + color: #fff; + background: rgba(23, 39, 33, 0.88); +} + +.oc-culture-hero-media > figure img { + display: block; + width: 100%; + aspect-ratio: 0.78; + object-fit: cover; + filter: saturate(0.8); +} + +.oc-culture-hero-media figcaption, +.oc-culture-intro-image figcaption, +.oc-culture-village figure figcaption { + font-size: 0.67rem; + line-height: 1.5; +} + +.oc-culture-hero-media figcaption { + padding: 9px 4px 2px; + color: rgba(255, 255, 255, 0.72); +} + +.oc-culture-subnav { + position: sticky; + z-index: 8; + top: 74px; + display: grid; + grid-template-columns: repeat(3, 1fr); + border-top: 1px solid rgba(255, 255, 255, 0.08); + border-bottom: 1px solid rgba(255, 255, 255, 0.1); + background: rgba(31, 48, 40, 0.96); + backdrop-filter: blur(12px); +} + +.oc-culture-subnav a { + padding: 18px 22px; + border-left: 1px solid rgba(255, 255, 255, 0.12); + color: rgba(255, 255, 255, 0.82); + font-size: 0.72rem; + font-weight: 700; + letter-spacing: 0.08em; + text-align: center; + text-transform: uppercase; +} + +.oc-culture-subnav a:first-child { + border-left: 0; +} + +.oc-culture-intro { + display: grid; + grid-template-columns: minmax(0, 1fr) minmax(340px, 0.62fr); + gap: clamp(54px, 8vw, 126px); + align-items: end; + padding-top: 122px; + padding-bottom: 84px; +} + +.oc-culture-intro-copy h2, +.oc-culture-village-grid h2, +.oc-culture-section-head h2 { + margin: 18px 0 24px; + font-family: Georgia, 'Times New Roman', serif; + font-size: clamp(2.25rem, 4.2vw, 4.7rem); + font-weight: 400; + line-height: 1.05; + letter-spacing: -0.042em; +} + +.oc-culture-intro-copy p, +.oc-culture-village-grid > div > p { + max-width: 760px; + margin: 0; + color: var(--culture-muted); + font-size: 1rem; + line-height: 1.82; +} + +.oc-culture-intro-image { + margin: 0; +} + +.oc-culture-intro-image img { + display: block; + width: 100%; + aspect-ratio: 0.8; + object-fit: cover; + filter: saturate(0.76); +} + +.oc-culture-intro-image figcaption { + padding-top: 12px; + color: #7d827e; +} + +.oc-culture-crafts { + display: grid; + grid-template-columns: repeat(2, minmax(0, 1fr)); + padding-bottom: 126px; + border-top: 1px solid var(--culture-line); + border-left: 1px solid var(--culture-line); +} + +.oc-culture-craft-card { + display: flex; + min-height: 390px; + flex-direction: column; + padding: clamp(30px, 4vw, 58px); + border-right: 1px solid var(--culture-line); + border-bottom: 1px solid var(--culture-line); + color: var(--culture-ink); + transition: color 180ms ease, background 180ms ease; +} + +.oc-culture-craft-card:hover { + color: #fff; + background: var(--culture-blue); +} + +.oc-culture-craft-card > div { + display: flex; + align-items: center; + justify-content: space-between; + gap: 16px; +} + +.oc-culture-craft-card > div > span { + color: #6a8076; + font-family: Georgia, 'Times New Roman', serif; + font-size: 1.55rem; +} + +.oc-culture-craft-card > div > small { + color: #7d8580; + font-size: 0.66rem; + font-weight: 700; + letter-spacing: 0.08em; + text-transform: uppercase; +} + +.oc-culture-craft-card h3 { + max-width: 580px; + margin: 62px 0 12px; + font-family: Georgia, 'Times New Roman', serif; + font-size: clamp(1.8rem, 3vw, 3.1rem); + font-weight: 400; + line-height: 1.08; + letter-spacing: -0.035em; +} + +.oc-culture-craft-card > strong { + color: #607068; + font-size: 0.72rem; + font-weight: 700; + letter-spacing: 0.04em; +} + +.oc-culture-craft-card > p { + max-width: 650px; + margin: 22px 0 30px; + color: var(--culture-muted); + font-size: 0.9rem; + line-height: 1.72; +} + +.oc-culture-card-link { + display: inline-flex; + align-items: center; + gap: 12px; + margin-top: auto; + color: var(--culture-blue); + font-size: 0.72rem; + font-weight: 700; + letter-spacing: 0.08em; + text-transform: uppercase; +} + +.oc-culture-craft-card:hover :is(div > span, div > small, strong, p, .oc-culture-card-link) { + color: rgba(255, 255, 255, 0.82); +} + +.oc-culture-village { + padding: 116px 0; + color: #f4f0e5; + background: #20332c; +} + +.oc-culture-village-grid { + display: grid; + grid-template-columns: minmax(360px, 0.92fr) minmax(0, 1.08fr); + gap: clamp(54px, 8vw, 126px); + align-items: center; +} + +.oc-culture-village figure { + margin: 0; +} + +.oc-culture-village figure img { + display: block; + width: 100%; + aspect-ratio: 0.9; + object-fit: cover; + filter: saturate(0.74) brightness(0.92); +} + +.oc-culture-village figure figcaption { + padding-top: 12px; + color: rgba(255, 255, 255, 0.48); +} + +.oc-culture-village-grid > div > span { + color: #a9c1b5; +} + +.oc-culture-village-grid h2 { + color: #f5f1e7; +} + +.oc-culture-village-grid > div > p { + color: rgba(255, 255, 255, 0.68); +} + +.oc-culture-village-grid ul { + display: grid; + gap: 13px; + margin: 32px 0 36px; + padding: 0; + list-style: none; +} + +.oc-culture-village-grid li { + display: flex; + align-items: center; + gap: 12px; + color: rgba(255, 255, 255, 0.82); + font-size: 0.86rem; +} + +.oc-culture-village-grid li svg { + width: 18px; + height: 18px; + color: #9dbaa9; +} + +.oc-culture-village-grid > div > a { + display: inline-flex; + align-items: center; + gap: 13px; + color: #f5f1e7; + font-size: 0.75rem; + font-weight: 700; + letter-spacing: 0.08em; + text-transform: uppercase; +} + +.oc-culture-village-actions { + display: flex; + flex-wrap: wrap; + gap: 18px 30px; +} + +.oc-culture-village-actions > a { + display: inline-flex; + align-items: center; + gap: 13px; + color: #f5f1e7; + font-size: 0.75rem; + font-weight: 700; + letter-spacing: 0.08em; + text-transform: uppercase; +} + +.oc-culture-village-actions > a:last-child { + color: rgba(245, 241, 231, .68); +} + +.oc-culture-festival { + border-top: 1px solid rgba(255, 255, 255, .12); + background: #4a332b; +} + +.oc-culture-festival .oc-culture-village-grid { + grid-template-columns: minmax(0, 1.08fr) minmax(360px, .92fr); +} + +.oc-culture-festival figure img { + object-position: center 36%; +} + +.oc-culture-culinary { + border-top: 1px solid rgba(255, 255, 255, .12); + background: #5a4537; +} + +.oc-culture-culinary figure img { + object-position: center 42%; +} + +.oc-culture-principles { + padding-top: 122px; + padding-bottom: 126px; +} + +.oc-culture-section-head { + display: grid; + grid-template-columns: 0.36fr 1fr; + gap: 42px; + align-items: start; + margin-bottom: 62px; +} + +.oc-culture-section-head h2 { + max-width: 980px; + margin: 0; +} + +.oc-culture-principle-grid { + display: grid; + grid-template-columns: repeat(4, minmax(0, 1fr)); + border-top: 1px solid var(--culture-line); + border-left: 1px solid var(--culture-line); +} + +.oc-culture-principle-grid article { + min-height: 278px; + padding: 30px 27px; + border-right: 1px solid var(--culture-line); + border-bottom: 1px solid var(--culture-line); +} + +.oc-culture-principle-grid article > span { + color: #789087; + font-family: Georgia, 'Times New Roman', serif; + font-size: 1.15rem; +} + +.oc-culture-principle-grid h3 { + margin: 52px 0 18px; + font-family: Georgia, 'Times New Roman', serif; + font-size: 1.55rem; + font-weight: 400; +} + +.oc-culture-principle-grid p { + margin: 0; + color: var(--culture-muted); + font-size: 0.84rem; + line-height: 1.68; +} + +.oc-culture-page > .oc-menu-bottom-prompt { + margin-bottom: 110px; + border-top-color: var(--culture-line); +} + +@media (max-width: 1080px) { + .oc-culture-hero { + grid-template-columns: 1fr 0.9fr; + } + + .oc-culture-hero-copy { + padding-left: 34px; + } + + .oc-culture-hero-facts { + grid-template-columns: repeat(2, 1fr); + } + + .oc-culture-hero-facts > div:last-child { + grid-column: 1 / -1; + } + + .oc-culture-principle-grid { + grid-template-columns: repeat(2, minmax(0, 1fr)); + } +} + +@media (max-width: 760px) { + .oc-culture-hero { + display: flex; + min-height: 0; + flex-direction: column-reverse; + } + + .oc-culture-hero-media { + min-height: 480px; + } + + .oc-culture-hero-media > img { + object-position: 50% 47%; + } + + .oc-culture-hero-media > figure { + right: 14px; + bottom: 14px; + width: 31%; + padding: 5px; + } + + .oc-culture-hero-media figcaption { + display: none; + } + + .oc-culture-hero-copy { + padding: 42px 20px 52px; + } + + .oc-culture-hero-copy .oc-breadcrumb { + margin-bottom: 34px; + } + + .oc-culture-hero-copy h1 { + margin-top: 16px; + font-size: clamp(2.55rem, 12vw, 4rem); + } + + .oc-culture-hero-actions { + align-items: stretch; + flex-direction: column; + gap: 18px; + } + + .oc-culture-hero-actions .oc-culture-primary { + justify-content: space-between; + } + + .oc-culture-hero-facts { + grid-template-columns: repeat(2, 1fr); + gap: 18px; + margin-top: 38px; + } + + .oc-culture-subnav { + top: 66px; + display: flex; + overflow-x: auto; + } + + .oc-culture-subnav a { + min-width: max-content; + flex: 1 0 auto; + padding: 15px 18px; + } + + .oc-culture-intro { + grid-template-columns: 1fr; + gap: 42px; + padding-top: 78px; + padding-bottom: 58px; + } + + .oc-culture-intro-copy h2, + .oc-culture-village-grid h2, + .oc-culture-section-head h2 { + font-size: clamp(2.05rem, 10vw, 3.2rem); + } + + .oc-culture-intro-image { + width: 78%; + margin-left: auto; + } + + .oc-culture-crafts { + grid-template-columns: 1fr; + padding-bottom: 78px; + } + + .oc-culture-craft-card { + min-height: 0; + padding: 28px 22px 30px; + } + + .oc-culture-craft-card h3 { + margin-top: 46px; + } + + .oc-culture-card-link { + margin-top: 10px; + } + + .oc-culture-village { + padding: 78px 0; + } + + .oc-culture-village-grid { + grid-template-columns: 1fr; + gap: 46px; + } + + .oc-culture-festival .oc-culture-village-grid { + grid-template-columns: 1fr; + } + + .oc-culture-village figure { + width: calc(100% - 32px); + } + + .oc-culture-principles { + padding-top: 78px; + padding-bottom: 82px; + } + + .oc-culture-section-head { + grid-template-columns: 1fr; + gap: 22px; + margin-bottom: 42px; + } + + .oc-culture-principle-grid { + grid-template-columns: 1fr; + } + + .oc-culture-principle-grid article { + min-height: 0; + padding: 26px 22px 29px; + } + + .oc-culture-principle-grid h3 { + margin-top: 34px; + } + + .oc-culture-page > .oc-menu-bottom-prompt { + margin-bottom: 72px; + } +} diff --git a/src/TravelSite.tsx b/src/TravelSite.tsx index 643e8c9..7a495e9 100644 --- a/src/TravelSite.tsx +++ b/src/TravelSite.tsx @@ -1,13 +1,19 @@ -import { Children, cloneElement, createContext, isValidElement, useContext, useEffect, useMemo, useRef, useState, type CSSProperties, type FormEvent, type ReactElement, type ReactNode } from 'react'; +import { createContext, useContext, useEffect, useMemo, useRef, useState, type CSSProperties, type FormEvent, type ReactNode } from 'react'; import { gsap } from 'gsap'; +import { ScrollTrigger } from 'gsap/ScrollTrigger'; import { useGSAP } from '@gsap/react'; import { ArrowLeft, ArrowRight, CheckCircle, + Globe, + Headset, List, MagnifyingGlass, + MapPin, + PauseCircle, PlayCircle, + UsersThree, X, } from '@phosphor-icons/react'; import { @@ -24,21 +30,21 @@ import { guizhouFoodCards, guizhouImages, guizhouSafariCards, - guizhouTransportCards, } from './guizhouContent'; import { experienceEnglish, foodEnglish, hotelEnglish, safariEnglish, - transportEnglish, } from './guizhouEnContent'; import { pickText, translateUi, type SiteLanguage } from './i18n'; import { createInquiry } from './api'; import type { CmsContent, Destination, DetailContentBlock, Product, ProductRoutePlan } from './cms'; import './TravelSite.css'; +import './TravelSiteRefinements.css'; +import './TravelSiteAtlas.css'; -gsap.registerPlugin(useGSAP); +gsap.registerPlugin(useGSAP, ScrollTrigger); function asset(source: string) { return source; @@ -52,7 +58,7 @@ function applySiteLanguage(_root: Element, _language: SiteLanguage) { const bg = (source: string) => ({ backgroundImage: `url(${asset(source)})` }); const moduleHeroBg = (source: string) => ({ '--oc-module-hero-image': `url(${asset(source)})` }) as CSSProperties; -const languageStorageKey = 'wanqu-travel-language'; +const languageStorageKey = 'wanqu-travel-language-en-default-v1'; const videoSourcePattern = /\.(mp4|webm|ogv|ogg|mov)(?:[?#].*)?$/i; function isVideoSource(source: string) { @@ -118,10 +124,23 @@ type MegaMenu = { type DetailIconSize = 'tab' | 'amenity' | 'live'; -type FilterSelections = Record; type SafariRouteHighlight = { title: string; copy: string; image: string }; -type SafariRouteDay = { day: string; title: string; place: string; copy: string; meta: string[] }; -type RouteDetailPillarId = 'route-flow' | 'route-stay' | 'route-food' | 'route-transport'; +type SafariRouteDay = { + day: string; + title: string; + place: string; + copy: string; + meta: string[]; + schedule?: { + morning: string; + afternoon: string; + evening: string; + drive: string; + meals: string; + stay: string; + }; +}; +type RouteDetailPillarId = 'route-flow' | 'route-stay' | 'route-food'; type RouteDetailPillar = { id: RouteDetailPillarId; label: string; @@ -133,7 +152,7 @@ type RouteDetailPillar = { href?: string; actionLabel?: string; }; -type SafariRoutePlans = Partial>>; +type SafariRoutePlans = Partial>>; type SafariCardItem = { slug: string; aliases?: string[]; @@ -167,8 +186,7 @@ type SafariCardItem = { }; type ArchiveCardItem = { title: string; meta: string; type?: string; image: string; copy: string; href?: string }; type FoodCardItem = { id: string; city: string; english: string; region: string; image: string; dishes: string[]; copy: string }; -type TransportCardItem = { id: string; seats: string; english: string; image: string; bestFor: string; luggage: string; copy: string }; -type PoiKind = 'experience' | 'hotel' | 'food' | 'transport'; +type PoiKind = 'experience' | 'hotel' | 'food'; type PoiFact = { label: string; value: string }; type PoiHighlight = { title?: string; copy?: string; image?: string }; type PoiRelatedItem = { title: string; kicker: string; copy: string; image: string; href: string }; @@ -223,8 +241,6 @@ const collectiveArchiveCards: ArchiveCardItem[] = guizhouCollectiveArchiveCards; const foodCards: FoodCardItem[] = guizhouFoodCards; -const transportCards: TransportCardItem[] = guizhouTransportCards; - function localizeSafariCard(safari: SafariCardItem, language: SiteLanguage): SafariCardItem { if (language === 'zh') return safari; const override = safariEnglish[safari.slug as keyof typeof safariEnglish]; @@ -259,6 +275,7 @@ function localizeSafariCard(safari: SafariCardItem, language: SiteLanguage): Saf place: day.place, copy: day.copy, meta: [...day.meta], + schedule: 'schedule' in day ? { ...day.schedule } : undefined, })), inclusions: [...override.inclusions], exclusions: [...override.exclusions], @@ -266,24 +283,6 @@ function localizeSafariCard(safari: SafariCardItem, language: SiteLanguage): Saf }; } -function localizeExperienceCard(card: ArchiveCardItem, language: SiteLanguage): ArchiveCardItem { - if (language === 'zh') return card; - const slug = archiveCardSlug(card); - const override = experienceEnglish[slug as keyof typeof experienceEnglish]; - return override - ? { ...card, title: override.title, meta: override.meta, type: override.type, copy: override.copy } - : { ...card, title: translateUi(card.title, language), meta: translateUi(card.meta, language), type: card.type ? translateUi(card.type, language) : card.type, copy: translateUi(card.copy, language) }; -} - -function localizeHotelCard(card: ArchiveCardItem, language: SiteLanguage): ArchiveCardItem { - if (language === 'zh') return card; - const slug = archiveCardSlug(card); - const override = hotelEnglish[slug as keyof typeof hotelEnglish]; - return override - ? { ...card, title: override.title, meta: override.meta, copy: override.copy } - : { ...card, title: translateUi(card.title, language), meta: translateUi(card.meta, language), copy: translateUi(card.copy, language) }; -} - function localizeFoodCard(card: FoodCardItem, language: SiteLanguage): FoodCardItem { if (language === 'zh') return card; const override = foodEnglish[card.id as keyof typeof foodEnglish]; @@ -292,14 +291,6 @@ function localizeFoodCard(card: FoodCardItem, language: SiteLanguage): FoodCardI : { ...card, city: translateUi(card.city, language), region: translateUi(card.region, language), dishes: translateListFallback(card.dishes, language), copy: translateUi(card.copy, language) }; } -function localizeTransportCard(card: TransportCardItem, language: SiteLanguage): TransportCardItem { - if (language === 'zh') return card; - const override = transportEnglish[card.id as keyof typeof transportEnglish]; - return override - ? { ...card, seats: override.seats, english: override.vehicle, bestFor: override.bestFor, luggage: override.luggage, copy: override.copy } - : { ...card, seats: translateUi(card.seats, language), english: translateUi(card.english, language), bestFor: translateUi(card.bestFor, language), luggage: translateUi(card.luggage, language), copy: translateUi(card.copy, language) }; -} - function translateListFallback(items: string[], language: SiteLanguage) { return items.map((item) => translateUi(item, language)); } @@ -308,17 +299,13 @@ function localizeRelatedItem(item: PoiRelatedItem, language: SiteLanguage): PoiR if (language === 'zh') return item; const slug = slugFromHref(item.href); const foodSlug = slug.replace(/^food-/, ''); - const vehicleSlug = slug.replace(/^transport-/, ''); const experience = experienceEnglish[slug as keyof typeof experienceEnglish]; const hotel = hotelEnglish[slug as keyof typeof hotelEnglish]; const food = foodEnglish[foodSlug as keyof typeof foodEnglish]; - const vehicle = transportEnglish[vehicleSlug as keyof typeof transportEnglish]; if (experience) return { ...item, title: experience.title, kicker: experience.meta, copy: experience.copy }; if (hotel) return { ...item, title: hotel.title, kicker: hotel.meta, copy: hotel.copy }; if (food) return { ...item, title: food.title, kicker: food.region, copy: food.copy }; - if (vehicle) return { ...item, title: vehicle.title, kicker: vehicle.bestFor, copy: vehicle.copy }; - return { ...item, title: translateUi(item.title, language), kicker: translateUi(item.kicker, language), copy: translateUi(item.copy, language) }; } @@ -447,111 +434,9 @@ function localizePoiDetail(detail: PoiDetailContent, language: SiteLanguage, slu }; } - const vehicle = transportEnglish[slug as keyof typeof transportEnglish]; - const title = vehicle?.title || translateUi(detail.title, language); - return { - ...detail, - title, - subtitle: vehicle?.copy || translateUi(detail.subtitle, language), - heroMeta: vehicle ? `${vehicle.vehicle} · ${vehicle.bestFor}` : translateUi(detail.heroMeta, language), - actionLabel: 'Ask for Vehicle Plan', - overviewEyebrow: 'Guizhou Transport', - overviewTitle: 'Match Vehicle, Luggage, and Mountain Transfers First', - overview: [ - vehicle?.copy || translateUi(detail.overview[0] || detail.subtitle, language), - 'Transport planning covers group size, luggage, mountain roads, parking, driver experience, guide language, and backup dispatch.', - ], - facts: [ - { label: 'Vehicle', value: vehicle?.title || title }, - { label: 'Best For', value: vehicle?.bestFor || 'Private Guizhou transfers' }, - { label: 'Luggage', value: vehicle?.luggage || 'Checked by route' }, - { label: 'Quote', value: 'Confirmed by route, dates, vehicle tier, and guide language' }, - ], - locationTitle: 'Dispatch and Roads', - locationCopy: 'Vehicles are matched to airport or rail arrival, hotel location, scenic parking, mountain-road limits, luggage, and group meeting points.', - locationTags: [vehicle?.seats || 'Vehicle', vehicle?.vehicle || 'Transport', 'Guizhou dispatch'], - bestForTitle: 'Best For', - bestFor: [vehicle?.bestFor || 'Private groups', 'Groups that need luggage, driver, and parking checked early', 'Multi-day Guizhou routes with mountain transfers'], - highlights: baseHighlights('Space for People and Luggage', 'We check seats, luggage, and comfort before confirming a vehicle.'), - planningTitle: 'Vehicle Notes', - planningNotes: ['Confirm guests, luggage size, child seats, camera gear, and English-speaking guide needs first.', 'Multi-day routes need driver rest, hotel parking, scenic transfers, and road limits planned together.', 'Peak dates and large groups should keep backup or split-vehicle options.'], - trustTitle: 'Transport Support', - trustPoints: ['Vehicle fit', 'Driver communication', 'Parking check', 'Road-limit review', 'Backup plan'], - relatedTitle: 'Other Vehicle Choices', - relatedItems, - }; + return detail; } -function normalizeFilterValue(value: string) { - return value.trim().toLowerCase(); -} - -function selectedFilterValues(filters: FilterSelections, title: string) { - return filters[title] || []; -} - -function nextFilterSelections(filters: FilterSelections, title: string, item: string) { - const next = { ...filters }; - if (item === 'All' || item === '全部') { - delete next[title]; - return next; - } - - const current = selectedFilterValues(filters, title); - const selected = current.includes(item) ? current.filter((value) => value !== item) : [...current, item]; - if (selected.length) { - next[title] = selected; - } else { - delete next[title]; - } - return next; -} - -function setSingleFilterSelection(filters: FilterSelections, title: string, item: string) { - const next = { ...filters }; - if (item === 'All' || item === '全部') { - delete next[title]; - } else { - next[title] = [item]; - } - return next; -} - -function matchesAnySelected(selected: string[], matcher: (value: string) => boolean) { - return selected.length === 0 || selected.some(matcher); -} - -function safariDurationRange(safari: SafariCardItem) { - const [start, end] = (safari.duration.match(/\d+/g) || []).map(Number); - const min = start || 0; - const max = end || min; - return { min, max }; -} - -function safariMatchesDurationFilter(safari: SafariCardItem, value: string) { - const { min, max } = safariDurationRange(safari); - if (value === '1日游') return max <= 1; - if (value === '3天以内') return max <= 3; - if (value === '3-5天') return min >= 3 && min <= 5; - if (value === '5天以上') return max >= 5; - return safari.duration === value || safari.nights.includes(value); -} - -function safariMatchesFilters(safari: SafariCardItem, filters: FilterSelections) { - const categoryFilters = selectedFilterValues(filters, '线路分类'); - const focusFilters = selectedFilterValues(filters, '游玩重点'); - const paceFilters = selectedFilterValues(filters, '旅行节奏'); - const durationFilters = selectedFilterValues(filters, '天数'); - const destinations = safari.destinations.map(normalizeFilterValue); - - return ( - matchesAnySelected(categoryFilters, (value) => safari.category === value) && - matchesAnySelected(focusFilters, (value) => safari.focus === value) && - matchesAnySelected(paceFilters, (value) => safari.pace === value) && - matchesAnySelected(durationFilters, (value) => safariMatchesDurationFilter(safari, value)) && - destinations.length > 0 - ); -} function safariFromSlug(slug: string, cmsContent: CmsContent | undefined, language: SiteLanguage) { const cmsSafariCards = cmsRouteCards(cmsContent, language); @@ -581,15 +466,6 @@ function foodFromSlug(slug: string) { return foodCards.find((card) => card.id === slug || card.id === normalizedSlug || `food-${card.id}` === slug || slugifyTitle(card.city) === slug || slugifyTitle(card.english) === slug) || foodCards[0]; } -function transportFromSlug(slug: string) { - const normalizedSlug = slug.replace(/^transport-/, ''); - return transportCards.find((card) => card.id === slug || card.id === normalizedSlug || `transport-${card.id}` === slug) || transportCards[0]; -} - -function transportHref(vehicle: TransportCardItem) { - return `/transport/${vehicle.id}/`; -} - function uniqueImages(...sources: Array) { return Array.from(new Set(sources.filter(Boolean) as string[])); } @@ -643,7 +519,6 @@ function cmsRouteProductToSafari(product: Product, cmsContent: CmsContent, langu ...(route?.routeHighlights || []).map((item) => item.imageUrl), route?.stayPlan?.imageUrl, route?.foodPlan?.imageUrl, - route?.transportPlan?.imageUrl, ).slice(0, 6); const title = cmsText(product.title, language) || slug; const summary = cmsText(product.summary, language); @@ -698,7 +573,6 @@ function cmsRouteProductToSafari(product: Product, cmsContent: CmsContent, langu routePlans: { stay: cmsRoutePlanToPillar(route?.stayPlan, language, image), food: cmsRoutePlanToPillar(route?.foodPlan, language, image), - transport: cmsRoutePlanToPillar(route?.transportPlan, language, image), }, }; } @@ -794,47 +668,33 @@ function findCmsDestination(cmsContent: CmsContent | undefined, slug: string, ti )); } -function initialSafariFilters(): FilterSelections { - if (typeof window === 'undefined') return {}; - const params = new URLSearchParams(window.location.search); - const category = params.get('category'); - const focus = params.get('focus'); - return { - ...(category ? { 线路分类: [category] } : {}), - ...(focus ? { 游玩重点: [focus] } : {}), - }; -} - -function experienceMatchesFilters(card: ArchiveCardItem, filters: FilterSelections) { - const typeFilters = selectedFilterValues(filters, '体验类型'); - const locationFilters = selectedFilterValues(filters, '地点'); - const type = normalizeFilterValue(card.type || ''); - const meta = normalizeFilterValue(card.meta); - - return ( - matchesAnySelected(typeFilters, (value) => type === normalizeFilterValue(value)) && - matchesAnySelected(locationFilters, (value) => meta.includes(normalizeFilterValue(value))) - ); -} - -function collectiveMatchesFilters(card: ArchiveCardItem, filters: FilterSelections) { - const locationFilters = selectedFilterValues(filters, '地点'); - const meta = normalizeFilterValue(card.meta); - return matchesAnySelected(locationFilters, (value) => meta.includes(normalizeFilterValue(value))); -} - const experienceTitleZh: Record = { 'cave-expedition': '天然溶洞探险', - rafting: '峡谷漂流与亲水', + 'cave-luxury-dining': '洞穴咖啡与私家晚宴', + rafting: '峡谷溯溪与白水漂流', 'stream-tracing': '溯溪与瀑降', + 'karst-hiking-cycling': '喀斯特峰林徒步与骑行', 'miao-craft': '苗绣与蜡染非遗体验', + 'dong-indigo-architecture': '侗族草木染与木构建筑', + 'shui-horsetail-embroidery': '水族马尾绣工坊', + 'buyi-traditional-crafts': '布依族传统织染技艺', 'dong-song': '侗族大歌与鼓楼村寨', huangguoshu: '黄果树瀑布错峰玩法', 'libo-xiaoqikong': '荔波樟江·小七孔喀斯特水系', 'fanjing-mountain': '梵净山天气窗口', 'xijiang-miao-village': '西江与侗寨夜晚', wanfenglin: '兴义万峰林锥状喀斯特峰林', - 'wild-coffee': '山野咖啡停靠', + 'wild-coffee': '悬崖与山野观景咖啡', + 'village-immersion': '原生村寨沉浸', + 'ethnic-festivals': '节庆民俗盛典', + 'culinary-cultural-journeys': '民族美食文化', + 'iconic-waterfall-clusters': '世界级瀑布群', + 'indigenous-ethnic-villages': '原生民族村寨', + 'historic-ancient-towns': '历史古镇古村', + 'qingyan-battle-immersive-roleplay': '青岩战斗・实景沉浸演绎', + 'loushanguan-battle-immersive-march': '娄山关战役・山道沉浸行军', + 'karst-glamping': '喀斯特野奢星空露营', + 'heritage-outdoor-pairings': '非遗与轻户外融合体验', 'hot-spring-recovery': '温泉恢复日', }; @@ -968,7 +828,7 @@ const experienceDetailOverrides: Record = { { title: '水位先行', copy: '漂流是否执行以当天水位、降雨和景区/项目开放为准。', image: img.experienceRafting }, { title: '家庭友好版本', copy: '亲子客人可改为轻亲水、森林步道或短时水边体验。', image: img.destinationLibo }, { title: '活动后热食', copy: '结束后安排热汤、粉面或稳定正餐,比继续赶路更重要。', image: img.menuFood }, - { title: '不硬塞返程日', copy: '水上活动不建议放在赶飞机或长距离返程当天。', image: img.menuTransport }, + { title: '不硬塞返程日', copy: '水上活动不建议放在赶飞机或长距离返程当天。', image: img.routeOutdoor }, ], }, 'stream-tracing': { @@ -1219,7 +1079,7 @@ const hotelDetailOverrides: Record = { ], }, 'hampton-by-hilton-guiyang-guanshan-lake': { - gallery: [img.menuHotels, img.menuTransport, img.heroHome, img.footerCta], + gallery: [img.menuHotels, img.routeClassic, img.heroHome, img.footerCta], heroMeta: '贵阳 / 观山湖 · 实用型舒适酒店', overviewTitle: '简单可靠的过渡夜酒店', overview: [ @@ -1238,7 +1098,7 @@ const hotelDetailOverrides: Record = { locationCopy: '适合作为贵阳城市过渡节点,重点是车辆衔接和稳定舒适,而不是目的地体验本身。', highlights: [ { title: '品牌稳定', copy: '适合对连锁标准、早餐和基础服务有预期的客人。', image: img.menuHotels }, - { title: '车辆衔接', copy: '贵阳新区出发可与第二天长线车辆调度配合。', image: img.menuTransport }, + { title: '车辆衔接', copy: '贵阳新区出发可与第二天长线车辆调度配合。', image: img.routeClassic }, { title: '预算友好', copy: '比景区度假型住宿更适合作为成本控制节点。', image: img.heroHome }, { title: '不承担景观任务', copy: '景观和慢住体验应安排在黄果树、西江或万峰林等节点。', image: img.footerCta }, ], @@ -1641,76 +1501,13 @@ function makeFoodPoiDetail(food: FoodCardItem): PoiDetailContent { return overridden; } -function makeTransportPoiDetail(vehicle: TransportCardItem): PoiDetailContent { - const gallery = uniqueImages(vehicle.image, img.menuTransport, img.routeMixed, img.routeOutdoor, img.footerCta, img.heroHuangguoshu).slice(0, 5); - const related = transportCards - .filter((card) => card.id !== vehicle.id) - .slice(0, 3) - .map((card) => ({ - title: `${card.seats} ${card.english}`, - kicker: card.bestFor, - copy: card.copy, - image: card.image, - href: transportHref(card), - })); - - return { - kind: 'transport', - title: `${vehicle.seats} ${vehicle.english}`, - subtitle: vehicle.copy, - heroMeta: `${vehicle.english} · ${vehicle.bestFor}`, - image: vehicle.image, - gallery, - actionLabel: '咨询这个车型', - overviewEyebrow: '贵州交通', - overviewTitle: '车型、行李和山地转场要先匹配', - overview: [ - vehicle.copy, - '贵州交通服务不只是选一辆车,还要把人数、行李、山路、景区停车、司机经验和跨地市调度一起确认,避免把体验卡在转场上。', - ], - facts: [ - { label: '车型', value: `${vehicle.seats} ${vehicle.english}` }, - { label: '适合', value: vehicle.bestFor }, - { label: '行李', value: vehicle.luggage }, - { label: '调度方式', value: '接送、包车、多日跨地市用车均可按线路确认' }, - { label: '道路变量', value: '山路、景区停车、酒店车位和限行需提前复核' }, - { label: '报价', value: '按日期、线路、车型等级和司导语言确认' }, - ], - locationTitle: '调度与道路', - locationCopy: `${vehicle.seats} 车型适合在贵州全境按路线调度,具体会结合机场/高铁抵离、酒店位置、景区停车、山路限制和团队集合方式确认。`, - locationTags: [vehicle.seats, vehicle.english, '贵州全境调度'], - bestForTitle: '适合这些用车场景', - bestFor: [ - vehicle.bestFor, - '需要把司机、行李和景区停车提前确认的小团或团队', - '希望长距离转场更稳、更从容的贵州多日路线', - ], - highlights: [ - { title: '人数与行李余量', copy: `按 ${vehicle.bestFor} 和 ${vehicle.luggage} 先判断车内空间,避免满员后行李和乘坐舒适度互相挤压。`, image: vehicle.image }, - { title: '山路和景区停车', copy: '黄果树、荔波、黔东南村寨、梵净山等节点会提前确认道路、换乘、停车和上下车位置。', image: gallery[1] || vehicle.image }, - { title: '司机与司导衔接', copy: '境外客人、亲子家庭或团队接待可同步确认司机经验、英文司导、集合方式和每日出发时间。', image: gallery[2] || vehicle.image }, - { title: '备选车辆预案', copy: '大团队或旺季线路会提前评估分车、备用车、补给和临时调整方案,减少现场等待。', image: gallery[3] || vehicle.image }, - ], - planningTitle: '用车确认事项', - planningNotes: [ - '先确认人数、行李尺寸、儿童座椅、摄影器材和是否需要英文司导。', - '跨地市多日路线要把司机休息、酒店停车、景区换乘和道路限制一起规划。', - '旺季、大团队或山地节点需要保留分车和备选车辆预案。', - ], - trustTitle: '交通执行保障', - trustPoints: ['车型匹配', '司机沟通', '停车复核', '道路限制评估', '备用预案'], - relatedTitle: '其他车型选择', - relatedItems: related, - }; -} - function TravelSite({ content, cmsContent }: { content?: SiteContent; cmsContent?: CmsContent }) { const [menuOpen, setMenuOpen] = useState(false); const [searchOpen, setSearchOpen] = useState(false); const [language, setLanguage] = useState(() => { const stored = window.localStorage.getItem(languageStorageKey); if (stored === 'zh' || stored === 'en') return stored; - return cmsContent?.settings.defaultLanguage || 'zh'; + return cmsContent?.settings.defaultLanguage || 'en'; }); const activeSiteContent = useMemo(() => normalizeSiteContent(content), [content]); const path = normalizePath(window.location.pathname); @@ -1766,6 +1563,8 @@ function TravelSite({ content, cmsContent }: { content?: SiteContent; cmsContent
setLanguage((current) => (current === 'zh' ? 'en' : 'zh'))} onMenu={() => setMenuOpen(true)} onSearch={() => setSearchOpen(true)} @@ -1784,6 +1583,29 @@ function normalizePath(pathname: string) { return path.toLowerCase(); } +function resolveMergedExperienceHref(href: string) { + if (!href.startsWith('/safaris/')) return href; + if (href.includes('culture-outdoor-mix')) return '/experiences/#living-culture'; + if (href.includes('classic-guizhou')) return '/experiences/#iconic-landscapes'; + return '/experiences/#karst-outdoor'; +} + +function keepFocusInsideDialog(event: globalThis.KeyboardEvent, root: HTMLElement | null) { + if (event.key !== 'Tab' || !root) return; + const focusable = Array.from(root.querySelectorAll('a[href], button:not([disabled]), input:not([disabled]), select:not([disabled]), textarea:not([disabled]), [tabindex]:not([tabindex="-1"])')) + .filter((element) => element.getClientRects().length > 0); + if (!focusable.length) return; + const first = focusable[0]; + const last = focusable[focusable.length - 1]; + if (event.shiftKey && document.activeElement === first) { + event.preventDefault(); + last.focus(); + } else if (!event.shiftKey && document.activeElement === last) { + event.preventDefault(); + first.focus(); + } +} + function slugifyTitle(title: string) { return title .toLowerCase() @@ -1809,7 +1631,7 @@ const routeStayPlans: Record> = 'outdoor-coffee': { title: '户外活动前后用住宿做体力缓冲', summary: '高活动量线路的住宿不追求频繁换风景,而是服务装备整理、早出发、活动后洗浴恢复和山地咖啡停靠。', - image: img.routeOutdoor, + image: img.clientMountainPause, tags: ['装备整理', '早出发', '恢复夜'], items: ['贵阳集合日靠近补给和装备确认点。', '洞穴、峡谷或亲水活动后优先保证热水、洗衣和睡眠。', '山野咖啡可作为高强度后的轻恢复住宿节点。'], href: '/hotels/', @@ -1818,7 +1640,7 @@ const routeStayPlans: Record> = 'culture-outdoor-mix': { title: '村寨住宿和自然节点交替,避免体验断层', summary: '混搭线要让文化体验和轻户外互相支撑。村寨或古镇停留需要足够时间,酒店选择要兼顾翻译沟通、餐食和第二天转场。', - image: img.destinationXijiang, + image: img.clientRouteBalanced, tags: ['村寨慢住', '轻户外缓冲', '沟通便利'], items: ['黔东南段优先保证一晚以上慢停留。', '轻户外前后搭配更易休整的住宿节点。', '境外客人入住点要考虑英文沟通和餐食稳定性。'], href: '/hotels/', @@ -1853,63 +1675,6 @@ const routeStayPlans: Record> = }, }; -const routeTransportPlans: Record> = { - 'classic-guizhou': { - title: '跨贵阳、安顺、荔波、黔东南的私家小团转场', - summary: '经典线看似常规,真正影响体验的是山地车程、景区停车、行李和酒店换住顺序。车辆要跟行程节奏一起设计。', - image: img.menuTransport, - tags: ['私家车', '跨地市', '行李管理'], - items: ['2-5 人优先 7 座 MPV,行李和英文司导空间更稳。', '黄果树、荔波、黔东南之间需要预留山路和天气缓冲。', '景区停车和酒店上下车点会提前确认,减少现场绕行。'], - href: '/transport/', - actionLabel: '查看交通', - }, - 'outdoor-coffee': { - title: '按活动风险调度车辆与备用转场', - summary: '户外线交通不是单纯接送。要能携带装备、防水补给、换洗衣物,并根据水位、雨量和客人体力切换活动地点。', - image: img.routeOutdoor, - tags: ['装备空间', '备用路线', '山路调度'], - items: ['车辆需预留装备、防水袋、头灯和换洗物品空间。', '活动点可能临时调整,司机和向导要提前共享备选路线。', '雨季亲水项目后要安排更稳的回程和补给节点。'], - href: '/transport/', - actionLabel: '查看交通', - }, - 'culture-outdoor-mix': { - title: '文化停靠与轻户外之间保持弹性车程', - summary: '混搭线会在村寨、非遗老师、河谷步道和城市节点之间切换。交通设计要给体验留时间,而不是把全天消耗在路上。', - image: img.routeMixed, - tags: ['弹性停靠', '村寨道路', '轻户外接驳'], - items: ['村寨道路、停车点和行李搬运需要提前判断。', '非遗体验老师档期可能影响出发时间,车程要有弹性。', '轻户外节点不宜排在长距离转场后的同一天尾段。'], - href: '/transport/', - actionLabel: '查看交通', - }, - 'family-heritage': { - title: '亲子长辈优先选择舒适车型和短车程组合', - summary: '家庭线路交通的核心是稳定和舒适。要减少连续山路、给午休留空间,并把儿童座椅、行李、餐食和洗手间停靠纳入计划。', - image: img.menuTransport, - tags: ['舒适车型', '短车程', '停靠缓冲'], - items: ['3-5 人家庭建议 7 座 MPV,儿童与行李空间更从容。', '每天车程不宜过满,安排洗手间、简餐和临时停车点。', '孩子或长辈状态变化时,能删减非核心节点。'], - href: '/transport/', - actionLabel: '查看交通', - }, - 'karst-waterfall-forest': { - title: '短线高效率转场,围绕景区错峰进出', - summary: '瀑布与水森林短线要把有限天数用在景观上。交通要提前判断贵阳、黄果树、荔波之间的出发时间和进景区节奏。', - image: img.menuTransport, - tags: ['短线转场', '错峰进入', '贵阳缓冲'], - items: ['黄果树日尽量错峰,车辆和景区换乘时间要提前核对。', '荔波段不建议当天来回,避免自然体验被车程挤压。', '返程前保留贵阳缓冲,降低山路天气风险。'], - href: '/transport/', - actionLabel: '查看交通', - }, - 'fanjing-ancient-towns': { - title: '梵净山票务、索道和天气共同决定交通节奏', - summary: '梵净山和古镇线路需要更强的时间窗口管理。车辆要服务早出发、票务预约、天气替代和镇远/黔东南衔接。', - image: img.destinationFanjing, - tags: ['早出发', '票务窗口', '古镇衔接'], - items: ['梵净山进山日要预留早出发和索道排队时间。', '雨雾天气需要能切换周边自然或文化节点。', '镇远古城段适合放慢车程,给夜景和休整留时间。'], - href: '/transport/', - actionLabel: '查看交通', - }, -}; - const routeFoodPlans: Record> = { 'classic-guizhou': { title: '贵阳夜市、安顺小吃、荔波酸香与黔东南长桌', @@ -1923,7 +1688,7 @@ const routeFoodPlans: Record> = 'outdoor-coffee': { title: '户外补给、热食恢复和山野咖啡', summary: '高强度户外线的饮食先服务体力,再服务特色。活动日前后要安排热食、补水、轻便餐和山地咖啡恢复。', - image: img.experienceCoffee, + image: img.clientCaveDinner, tags: ['活动补给', '热食恢复', '野咖'], items: ['探洞、溯溪或漂流日前要准备补水和轻便能量食。', '活动后优先安排热汤、粉面或容易接受的恢复餐。', '山野咖啡适合作为轻松半日,不和高强度活动硬塞同一天。'], href: '/food/', @@ -1932,7 +1697,7 @@ const routeFoodPlans: Record> = 'culture-outdoor-mix': { title: '村寨主理人餐、酸汤风味和轻户外恢复餐', summary: '人文混搭线的餐食本身就是体验。需要解释礼仪、口味和食材,同时给不习惯酸辣的境外客人准备替代选择。', - image: img.destinationXijiang, + image: img.clientLocalTable, tags: ['村寨餐食', '酸汤', '替代菜单'], items: ['村寨家宴或长桌餐要提前说明礼仪和食材。', '酸汤、腌鱼、牛瘪等强地方风味需要确认可接受度。', '轻户外日前后用稳定正餐恢复体力。'], href: '/food/', @@ -1967,7 +1732,7 @@ const routeFoodPlans: Record> = }, }; -function routePlanFallback(safari: SafariCardItem, kind: 'stay' | 'transport' | 'food'): Omit { +function routePlanFallback(safari: SafariCardItem, kind: 'stay' | 'food'): Omit { if (kind === 'stay') { return { title: '按线路节奏匹配住宿,而不是单独选酒店', @@ -1979,17 +1744,6 @@ function routePlanFallback(safari: SafariCardItem, kind: 'stay' | 'transport' | actionLabel: '查看住宿', }; } - if (kind === 'transport') { - return { - title: '按人数、行李、山路和活动强度匹配车辆', - summary: '贵州线路跨地市、景区和村寨,交通调度会直接决定体验质量。', - image: img.menuTransport, - tags: ['车型匹配', safari.duration, safari.service], - items: ['根据人数和行李选择 5-50 座车辆。', '提前确认景区停车、酒店车位和山路条件。', '保留天气和体力变化的转场缓冲。'], - href: '/transport/', - actionLabel: '查看交通', - }; - } return { title: '把贵州味道放进正确的行程节点', summary: '餐食会根据口味、禁忌、车程、活动强度和城市/村寨节点来安排。', @@ -2004,8 +1758,6 @@ function routePlanFallback(safari: SafariCardItem, kind: 'stay' | 'transport' | function routeDetailPillars(safari: SafariCardItem, language: SiteLanguage = 'zh'): RouteDetailPillar[] { const cmsStaySource = safari.routePlans?.stay; const cmsFoodSource = safari.routePlans?.food; - const cmsTransportSource = safari.routePlans?.transport; - if (language === 'en') { return [ { @@ -2043,19 +1795,6 @@ function routeDetailPillars(safari: SafariCardItem, language: SiteLanguage = 'zh actionLabel: 'View Food', }), }, - { - id: 'route-transport', - label: 'Transport', - ...(cmsTransportSource || { - title: 'Match vehicles to guests, luggage, mountain roads, and activity level', - summary: 'Guizhou routes cross cities, scenic areas, and villages, so vehicle dispatch directly shapes comfort and reliability.', - image: img.menuTransport, - tags: ['Vehicle fit', safari.duration, safari.service], - items: ['Choose 5-50 seat vehicles by group size and luggage.', 'Check scenic parking, hotel drop-off points, and mountain-road limits early.', 'Keep transfer buffers for weather and guest energy changes.'], - href: '/transport/', - actionLabel: 'View Transport', - }), - }, ]; } @@ -2070,18 +1809,19 @@ function routeDetailPillars(safari: SafariCardItem, language: SiteLanguage = 'zh }; const staySource = cmsStaySource || routeStayPlans[safari.slug] || routePlanFallback(safari, 'stay'); - const transportSource = cmsTransportSource || routeTransportPlans[safari.slug] || routePlanFallback(safari, 'transport'); const foodSource = cmsFoodSource || routeFoodPlans[safari.slug] || routePlanFallback(safari, 'food'); return [ route, { id: 'route-stay', label: '住宿', ...staySource }, { id: 'route-food', label: '吃', ...foodSource }, - { id: 'route-transport', label: '交通', ...transportSource }, ]; } function selectPage(path: string) { + if (path === '/preview/classic') return ; + if (path === '/preview/v1') return ; + if (path === '/preview/v2') return ; if (path === '/safari-faqs' || path === '/faqs') return ; if (path.startsWith('/our-guides')) return ; if (path.startsWith('/meet-the-team')) return ; @@ -2093,11 +1833,11 @@ function selectPage(path: string) { if (path.startsWith('/blog') || path.startsWith('/our-expert-guides') || path.startsWith('/live-from-camp')) return ; if (path.startsWith('/new-agents-sign-up') || path.startsWith('/trade-portal')) return ; if (path.startsWith('/expedition')) return ; - if (path.startsWith('/signature')) return ; + if (path.startsWith('/signature')) return ; if (path.startsWith('/icon')) return ; + if (path === '/culture' || path.startsWith('/culture/')) return ; if (path === '/landscapes') return ; - if (path === '/safaris') return ; - if (path.startsWith('/safaris/')) return ; + if (path === '/safaris' || path.startsWith('/safaris/')) return ; if (path === '/destinations' || path === '/destination') return ; if (path.startsWith('/destinations/')) return ; if (path.startsWith('/destination/')) return ; @@ -2105,8 +1845,6 @@ function selectPage(path: string) { if (path.startsWith('/experiences/')) return ; if (path === '/food') return ; if (path.startsWith('/food/')) return ; - if (path === '/transport') return ; - if (path.startsWith('/transport/')) return ; if (path.startsWith('/the-collective') || path.startsWith('/collective/')) return ; if (path === '/hotels') return ; if (path.startsWith('/hotels/')) return ; @@ -2117,13 +1855,280 @@ function selectPage(path: string) { return ; } +function EditorialHomePage() { + const { content, language } = useTravelSite(); + const editorialRef = useRef(null); + const home = content.home; + const editorialExperiences = [ + { number: '01', title: pickText('山野', 'Wild Karst', language), eyebrow: pickText('徒步 · 骑行 · 洞穴', 'Hike · Cycle · Caves', language), image: '/client-assets/karst-hike-ridge.jpg', href: '/experiences/karst-hiking/' }, + { number: '02', title: pickText('村寨', 'Village Life', language), eyebrow: pickText('日常 · 家宴 · 手作', 'Homes · Tables · Craft', language), image: '/client-assets/villages-xijiang-dusk.jpg', href: '/experiences/indigenous-ethnic-villages/' }, + { number: '03', title: pickText('水世界', 'Water Worlds', language), eyebrow: pickText('瀑布 · 峡谷 · 河流', 'Falls · Canyons · Rivers', language), image: '/client-assets/waterfall-huangguoshu-curtain.jpg', href: '/experiences/iconic-waterfall-clusters/' }, + { number: '04', title: pickText('贵州味道', 'Taste Guizhou', language), eyebrow: pickText('家宴 · 市场 · 山野咖啡', 'Tables · Markets · Coffee', language), image: '/client-assets/culinary-long-table-banquet.jpg', href: '/experiences/culinary-cultural-journeys/' }, + ]; + const editorialRoutes = home.safaris.cards.slice(0, 3); + const fieldImages = [ + '/client-assets/team-field-day.webp', + '/client-assets/culture-batik-making.jpg', + '/client-assets/river-packraft-shore.jpg', + '/client-assets/ancient-towns-zhenyuan-night.jpg', + '/client-assets/culinary-long-table-banquet.jpg', + ]; + + useGSAP( + () => { + if (window.matchMedia('(prefers-reduced-motion: reduce)').matches) return; + + const heroTimeline = gsap.timeline({ defaults: { ease: 'power3.out' } }); + heroTimeline + .from('.oc-v2-hero > img', { scale: 1.13, autoAlpha: 0.4, duration: 1.8, ease: 'power2.out' }) + .from('.oc-v2-hero-copy > p', { y: 20, autoAlpha: 0, duration: 0.6 }, '-=1.18') + .from('.oc-v2-hero h1', { y: 90, autoAlpha: 0, duration: 1.05 }, '-=.85') + .from('.oc-v2-hero-bottom > *', { y: 32, autoAlpha: 0, duration: 0.7, stagger: 0.12 }, '-=.58') + .from('.oc-v2-hero-scroll', { scale: 0.65, autoAlpha: 0, duration: 0.55 }, '-=.45'); + + gsap.to('.oc-v2-hero > img', { + yPercent: 10, + scale: 1.08, + ease: 'none', + scrollTrigger: { trigger: '.oc-v2-hero', start: 'top top+=90', end: 'bottom top', scrub: 0.7 }, + }); + + gsap.to('.oc-v2-hero-scroll svg', { + y: 8, + duration: 1.15, + repeat: -1, + yoyo: true, + ease: 'sine.inOut', + }); + + gsap.utils.toArray('.oc-v2-section-intro, .oc-v2-field-heading').forEach((heading) => { + gsap.from(heading.children, { + y: 58, + autoAlpha: 0, + duration: 0.9, + stagger: 0.12, + ease: 'power3.out', + scrollTrigger: { trigger: heading, start: 'top 78%', once: true }, + }); + }); + + gsap.from('.oc-v2-experience-card', { + y: 86, + clipPath: 'inset(0 0 100% 0)', + duration: 1.05, + stagger: 0.11, + ease: 'power4.out', + scrollTrigger: { trigger: '.oc-v2-experience-grid', start: 'top 76%', once: true }, + }); + gsap.from('.oc-v2-experience-card > img', { + scale: 1.18, + duration: 1.5, + stagger: 0.11, + ease: 'power3.out', + scrollTrigger: { trigger: '.oc-v2-experience-grid', start: 'top 76%', once: true }, + }); + + gsap.from('.oc-v2-feature-image', { + clipPath: 'inset(0 100% 0 0)', + duration: 1.25, + ease: 'power4.inOut', + scrollTrigger: { trigger: '.oc-v2-feature', start: 'top 72%', once: true }, + }); + gsap.from('.oc-v2-feature-image img', { + scale: 1.16, + duration: 1.6, + ease: 'power3.out', + scrollTrigger: { trigger: '.oc-v2-feature', start: 'top 72%', once: true }, + }); + gsap.from('.oc-v2-feature-copy > *', { + y: 58, + autoAlpha: 0, + duration: 0.82, + stagger: 0.1, + ease: 'power3.out', + scrollTrigger: { trigger: '.oc-v2-feature-copy', start: 'top 74%', once: true }, + }); + + gsap.from('.oc-v2-route-card', { + y: 90, + clipPath: 'inset(100% 0 0 0)', + duration: 1.08, + stagger: 0.13, + ease: 'power4.out', + scrollTrigger: { trigger: '.oc-v2-route-grid', start: 'top 76%', once: true }, + }); + gsap.from('.oc-v2-route-card img', { + scale: 1.16, + duration: 1.55, + stagger: 0.13, + ease: 'power3.out', + scrollTrigger: { trigger: '.oc-v2-route-grid', start: 'top 76%', once: true }, + }); + + gsap.from('.oc-v2-field-collage figure, .oc-v2-field-note', { + y: 76, + scale: 0.96, + autoAlpha: 0, + duration: 0.9, + stagger: 0.1, + ease: 'power3.out', + scrollTrigger: { trigger: '.oc-v2-field-collage', start: 'top 76%', once: true }, + }); + gsap.to('.oc-v2-field-collage figure.is-1 img', { + yPercent: 10, + scale: 1.08, + ease: 'none', + scrollTrigger: { trigger: '.oc-v2-field-collage', start: 'top bottom', end: 'bottom top', scrub: 0.8 }, + }); + + gsap.from('.oc-v2-local-media img:first-child', { + clipPath: 'inset(0 0 100% 0)', + scale: 1.1, + duration: 1.25, + ease: 'power4.out', + scrollTrigger: { trigger: '.oc-v2-local', start: 'top 72%', once: true }, + }); + gsap.from('.oc-v2-local-media img:last-child', { + x: 70, + y: 60, + rotate: 2, + autoAlpha: 0, + duration: 0.95, + ease: 'power3.out', + scrollTrigger: { trigger: '.oc-v2-local', start: 'top 65%', once: true }, + }); + gsap.from('.oc-v2-local-copy > *', { + y: 52, + autoAlpha: 0, + duration: 0.78, + stagger: 0.09, + ease: 'power3.out', + scrollTrigger: { trigger: '.oc-v2-local-copy', start: 'top 74%', once: true }, + }); + + gsap.from('.oc-v2-final > div > *', { + y: 66, + autoAlpha: 0, + duration: 0.9, + stagger: 0.13, + ease: 'power3.out', + scrollTrigger: { trigger: '.oc-v2-final', start: 'top 66%', once: true }, + }); + gsap.fromTo('.oc-v2-final > img', { scale: 1.06 }, { + scale: 1.16, + ease: 'none', + scrollTrigger: { trigger: '.oc-v2-final', start: 'top bottom', end: 'bottom top', scrub: 0.9 }, + }); + }, + { scope: editorialRef, dependencies: [language], revertOnUpdate: true }, + ); + + return ( +
+
+ {pickText('贵州喀斯特山野中的万趣私家旅行', +
+ +
+
+ 01 / {pickText('选择一种靠近方式', 'Choose how to get closer', language)} +
+

{pickText('贵州不只有一个入口。', 'There is more than one way into Guizhou.', language)}

+

{pickText('从喀斯特山野、村寨日常、水世界或贵州餐桌出发。每一种体验都可以成为一条私家路线的起点。', 'Begin with wild karst, village life, water worlds or the local table. Each can become the first chapter of a private route.', language)}

+
+
+
+ {editorialExperiences.map((item, index) => ( + + {item.title} + {item.number} +
{item.eyebrow}

{item.title}

+
+ ))} +
+
+ +
+
+ {pickText('贵州村寨真实生活', + {pickText('贵州 · 黔东南', 'Southeast Guizhou', language)} +
+
+ 02 / {pickText('本期故事', 'Featured story', language)} +

{pickText('去一个地方,也理解一个地方。', 'Go somewhere. Understand it, too.', language)}

+

{pickText('在村寨里留下一晚,在家常饭桌上多坐一会,听懂一门手艺和一栋木楼背后的生活。我们把“看见”变成真正的相遇。', 'Stay a night in the village. Linger at the family table. Understand the life behind a craft and a timber home. We turn seeing into meeting.', language)}

+ {pickText('阅读村寨故事', 'Read the village story', language)} +
+
100%{pickText('私家定制', 'private planning', language)}
+
24/7{pickText('在地协调', 'local support', language)}
+
EN / 中{pickText('双语支持', 'bilingual support', language)}
+
+
+
+ +
+
+ 03 / {pickText('旅行灵感', 'Journey inspiration', language)} +

{pickText('三条路线,都是讨论的开始。', 'Three routes. Each starts a conversation.', language)}

{pickText('先选一个接近你的方向,再按日期、兴趣、体力和住宿偏好重新编排。', 'Choose the direction closest to you, then reshape it around dates, interests, energy and stays.', language)}

+
+ +
+ +
+
04 / {pickText('来自现场', 'From the field', language)}

{pickText('真实旅行,没有摆拍的模板。', 'Real journeys. No staged template.', language)}

+
+ {fieldImages.map((image, index) =>
{pickText(`贵州旅行现场{index === 0 ?
{pickText('万趣本地团队,在贵州。', 'The WanderQ team, here in Guizhou.', language)}
: null}
)} +
+
+
+ +
+
{pickText('万趣贵州本地团队',{pickText('万趣团队旅行现场',
+
05 / {pickText('为什么是万趣', 'Why WanderQ', language)}

{pickText('离现场近一点,旅程就从容一点。', 'Closer to the field. Calmer on the road.', language)}

{pickText('我们在贵州本地规划与执行。熟悉山路、天气、水位与村寨节奏,也理解境外客人需要怎样清楚、可靠的英文旅行支持。', 'We plan and operate from Guizhou—close to the roads, weather, water and village rhythms, with clear English-language support for international guests.', language)}

  • {pickText('一组客人,一套私家方案', 'One private plan for one party', language)}
  • {pickText('合规入境接待与透明报价', 'Compliant inbound reception and clear pricing', language)}
  • {pickText('行程期间 24 小时在地协调', '24-hour local coordination while travelling', language)}
{pickText('认识本地团队', 'Meet the local team', language)}
+
+ +
+ {pickText('贵州镇远古城夜景', +
{pickText('下一段旅程,从一场对话开始。', 'Your next journey starts with a conversation.', language)}

{pickText('贵州,等你走进。', 'Guizhou is waiting.', language)}

{pickText('开始规划', 'Start planning', language)}
+
+
+ ); +} + function Header({ language, + menuOpen, + searchOpen, onLanguageToggle, onMenu, onSearch, }: { language: SiteLanguage; + menuOpen: boolean; + searchOpen: boolean; onLanguageToggle: () => void; onMenu: () => void; onSearch: () => void; @@ -2312,11 +2317,11 @@ function Header({ > - - @@ -2484,6 +2489,23 @@ function MegaMenu({ menu }: { menu: SiteMegaMenu }) { function FullMenu({ onClose }: { onClose: () => void }) { const { content, language } = useTravelSite(); const menuRef = useRef(null); + const closeRef = useRef(null); + + useEffect(() => { + const returnFocusTo = document.activeElement instanceof HTMLElement ? document.activeElement : document.getElementById('site-menu-trigger'); + closeRef.current?.focus(); + + const handleKeyDown = (event: globalThis.KeyboardEvent) => { + if (event.key === 'Escape') onClose(); + keepFocusInsideDialog(event, menuRef.current); + }; + + window.addEventListener('keydown', handleKeyDown); + return () => { + window.removeEventListener('keydown', handleKeyDown); + returnFocusTo?.focus(); + }; + }, [onClose]); useGSAP( () => { @@ -2560,15 +2582,15 @@ function FullMenu({ onClose }: { onClose: () => void }) { }; return ( -
-
-

{oc(content.fullMenu.title, language)}

+

{oc(content.fullMenu.title, language)}

{oc(content.fullMenu.copy, language)}

{oc(content.fullMenu.ctaLabel, language)} @@ -2595,187 +2617,578 @@ function FullMenu({ onClose }: { onClose: () => void }) { function SearchOverlay({ onClose }: { onClose: () => void }) { const { content, language } = useTravelSite(); + const [query, setQuery] = useState(''); + const searchRef = useRef(null); + const returnFocusRef = useRef(null); + const allSearchLinks = useMemo(() => { + const links = [ + ...enabledSiteLinks(content.search.suggestions), + ...enabledSiteLinks(content.header.nav), + ...content.megaMenus.flatMap((menu) => menu.groups.flatMap((group) => enabledSiteLinks(group.links))), + ]; + const uniqueLinks = new Map(); + links.forEach((link) => { + const key = `${link.href}|${oc(link.label, language)}`; + if (!uniqueLinks.has(key)) uniqueLinks.set(key, link); + }); + return Array.from(uniqueLinks.values()); + }, [content, language]); + const visibleSearchLinks = useMemo(() => { + const normalizedQuery = query.trim().toLocaleLowerCase(); + const source = normalizedQuery ? allSearchLinks : enabledSiteLinks(content.search.suggestions); + return source + .filter((link) => !normalizedQuery || oc(link.label, language).toLocaleLowerCase().includes(normalizedQuery)) + .slice(0, 12); + }, [allSearchLinks, content.search.suggestions, language, query]); + + useEffect(() => { + returnFocusRef.current = document.getElementById('site-search-trigger'); + const handleKeyDown = (event: globalThis.KeyboardEvent) => { + if (event.key === 'Escape') onClose(); + keepFocusInsideDialog(event, searchRef.current); + }; + window.addEventListener('keydown', handleKeyDown); + return () => { + window.removeEventListener('keydown', handleKeyDown); + returnFocusRef.current?.focus(); + }; + }, [onClose]); + return ( -
+ ); } -function HomePage() { +function HomePage({ variant = 'v1' }: { variant?: 'classic' | 'v1' }) { const { content, language } = useTravelSite(); + const prototypeRef = useRef(null); const home = content.home; const heroSlides = useMemo( - () => [home.hero.imageUrl, ...home.hero.awardUrls].filter(Boolean), - [home.hero.awardUrls, home.hero.imageUrl], + () => variant === 'v1' + ? [ + '/client-assets/atlas-hero-waterfall.webp', + '/client-assets/hero-real-travelers.webp', + '/client-assets/hero-miao-home-meal.webp', + ] + : [home.hero.imageUrl, ...home.hero.awardUrls].filter(Boolean), + [home.hero.awardUrls, home.hero.imageUrl, variant], ); - const liveImages = home.liveGallery.imageUrls; const [heroIndex, setHeroIndex] = useState(0); + const [heroPaused, setHeroPaused] = useState(false); const activeHero = heroSlides[heroIndex % heroSlides.length] || home.hero.imageUrl; + useGSAP( + () => { + if (variant === 'classic') return; + if (window.matchMedia('(prefers-reduced-motion: reduce)').matches) return; + + const heroTimeline = gsap.timeline({ defaults: { ease: 'power3.out' } }); + heroTimeline + .from('.oc-atlas-coordinate', { x: -18, autoAlpha: 0, duration: 0.55 }) + .from('.oc-atlas-hero-title-line', { yPercent: 118, duration: 0.92, stagger: 0.09 }, '-=0.25') + .from('.oc-atlas-hero-intro > *', { y: 18, autoAlpha: 0, duration: 0.55, stagger: 0.08 }, '-=0.38') + .from('.oc-atlas-hero-media', { xPercent: 4, autoAlpha: 0, duration: 0.95 }, '-=0.65') + .from('.oc-atlas-hero-rail > *', { y: 12, autoAlpha: 0, duration: 0.42, stagger: 0.06 }, '-=0.45'); + + gsap.to('.oc-atlas-hero-media img', { + yPercent: 7, + scale: 1.045, + ease: 'none', + scrollTrigger: { + trigger: '.oc-atlas-hero', + start: 'top top+=82', + end: 'bottom top', + scrub: true, + }, + }); + + gsap.utils.toArray('.oc-atlas-reveal').forEach((section) => { + gsap.from(section.children, { + y: 46, + autoAlpha: 0, + duration: 0.82, + stagger: 0.09, + ease: 'power3.out', + scrollTrigger: { trigger: section, start: 'top 78%', once: true }, + }); + }); + + gsap.utils.toArray('.oc-atlas-experience-card').forEach((card, index) => { + gsap.from(card, { + y: 58 + index * 10, + rotate: index === 1 ? -1.2 : index === 2 ? 1.2 : 0, + autoAlpha: 0, + duration: 0.9, + ease: 'power3.out', + scrollTrigger: { trigger: card, start: 'top 84%', once: true }, + }); + }); + + gsap.from('.oc-atlas-route-map', { + clipPath: 'inset(0 100% 0 0)', + duration: 1.2, + ease: 'power3.inOut', + scrollTrigger: { trigger: '.oc-atlas-plan', start: 'top 72%', once: true }, + }); + }, + { scope: prototypeRef, dependencies: [language, variant], revertOnUpdate: true }, + ); + useEffect(() => { - if (heroSlides.length <= 1) return undefined; + if (heroSlides.length <= 1 || heroPaused) return undefined; const timer = window.setInterval(() => { setHeroIndex((current) => (current + 1) % heroSlides.length); - }, 5200); + }, 5600); return () => window.clearInterval(timer); - }, [heroSlides.length]); + }, [heroPaused, heroSlides.length]); + + const trustSignals = [ + { + icon: MapPin, + title: pickText('贵州本地团队', 'Guizhou-based team', language), + copy: pickText('熟悉山路、天气与在地节奏', 'Local knowledge of roads, weather and daily rhythms', language), + }, + { + icon: UsersThree, + title: pickText('纯玩私家小团', 'Private journeys only', language), + copy: pickText('按人数、兴趣与节奏定制', 'Designed around your people, interests and pace', language), + }, + { + icon: Globe, + title: pickText('英文旅行支持', 'English trip support', language), + copy: pickText('双语沟通与文化说明', 'Bilingual planning and cultural context', language), + }, + { + icon: Headset, + title: pickText('24 小时在地支持', '24/7 on-ground support', language), + copy: pickText('行程期间持续响应与协调', 'Responsive coordination throughout your journey', language), + }, + ]; + + const prototypeJourneySteps = [ + { + number: '01', + label: pickText('先确认你想怎样旅行', 'Define how you want to travel', language), + copy: pickText('先聊同行的人、真正感兴趣的事、体力和节奏,不急着给你一张固定线路表。', 'We begin with your people, interests, energy and pace—not with a fixed itinerary.', language), + }, + { + number: '02', + label: pickText('由本地团队重新编排', 'Shape one clear journey', language), + copy: pickText('把山水、村寨、住宿与交通做取舍,组合成一条顺路、舒服、真正适合你的贵州旅程。', 'Our local team edits landscapes, villages, stays and transfers into one clear private rhythm.', language), + }, + { + number: '03', + label: pickText('路上始终有人照应', 'Stay supported on the road', language), + copy: pickText('天气、道路和现场变化由我们持续协调,双语支持始终在线,让你安心靠近真实贵州。', 'We stay close with bilingual, on-ground support as weather, roads and field conditions change.', language), + }, + ]; + + const brandValues = [ + { + number: '01', + title: pickText('合规入境接待', 'Compliant inbound reception', language), + copy: pickText('为境外游客提供清晰、正规的入境接待流程。', 'A clear, compliant reception process for international travelers.', language), + }, + { + number: '02', + title: pickText('懂贵州,也会讲贵州', 'Local stories, not scripts', language), + copy: pickText('讲清这里的文化与生活,不做背书式流水线导游。', 'Guizhou specialists who explain the culture, not a memorized script.', language), + }, + { + number: '03', + title: pickText('熟悉山路与天气', 'Locals who know the road', language), + copy: pickText('熟悉贵州山路、天气与现场变化,及时响应。', 'Local knowledge of mountain roads, weather and changing conditions.', language), + }, + { + number: '04', + title: pickText('不赶场的真实旅行', 'A slower, more human pace', language), + copy: pickText('拒绝赶场式打卡,把时间留给山水、村寨与真实生活。', 'No checklist travel—more time for landscapes, villages and daily life.', language), + }, + { + number: '05', + title: pickText('一人一行程,价格透明', 'One journey, clearly priced', language), + copy: pickText('按你的兴趣与节奏设计行程,清楚说明价格与服务。', 'A private itinerary shaped around you, with pricing explained clearly.', language), + }, + ]; + + const inquiryPrompts = [ + { + number: '01', + title: pickText('什么时候,和谁一起', 'When, and with whom', language), + copy: pickText('大致日期和同行人数就够了,不需要现在完全确定。', 'Rough dates and party size are enough. Nothing needs to be fixed yet.', language), + }, + { + number: '02', + title: pickText('你为什么想来贵州', 'Why Guizhou', language), + copy: pickText('户外、山水、村寨、人文或美食,告诉我们你最在意的部分。', 'Adventure, landscapes, villages, culture, or food—tell us what matters most.', language), + }, + { + number: '03', + title: pickText('怎样的节奏最适合你', 'How you like to travel', language), + copy: pickText('轻松一些、充实一些,或者两者之间,再加上你的住宿期待。', 'Easy days, fuller days, or a mix—plus the kind of stays that feel right.', language), + }, + ]; return ( -
-
-
- {heroSlides.map((slide, index) => ( -
- {home.hero.tripAdvisorUrl ? Tripadvisor : null} -
-

{oc(home.hero.kicker, language)}

-

{oc(home.hero.title, language)}

- - {oc(home.hero.ctaLabel, language)} - -
-
- -
- {home.planning.steps.map((step) => ( -
- {step.number} -

{oc(step.title, language)}

-

{oc(step.copy, language)}

-
- ))} -
- -
- -
- {home.experiences.bands.map((experience) => ( - - ))} -
-
- -
- -
+
+ -
- -
- {home.journey.cards.map((item) => ( - - {oc(item.copy, language)} - - ))} -
-
+
+
+ {trustSignals.map(({ icon: Icon, title, copy }) => ( +
+
+ ))} +
+
-
-
- {language -
-
-
-

{oc(home.quote.body, language)}

-
- {oc(home.quote.attribution, language)} -
-
- -
-
- {wanquSocialChannels.map((rawChannel) => { - const channel = localizeSocialChannel(rawChannel, language); - return ( - - -
- {channel.name} - {channel.handle} +
+ -
- -
-

{oc(home.liveGallery.title, language)}

-
-
- {[false, true].map((hiddenSet) => ( -
- {liveImages.map((image, index) => ( -
- {hiddenSet -
+
+ {brandValues.map((value) => ( +
+ {value.number}

{value.title}

{value.copy}

+
))}
+
+
+ + ) : ( + <> +
+
+

26°03′–29°13′ N   103°36′–109°35′ E

+

+ {language === 'zh' ? ( + <> + 不是看过贵州, + 是走进贵州。 + + ) : ( + <> + Don’t just + see Guizhou. + Enter it. + + )} +

+
+

{pickText('从喀斯特秘境、鲜活村寨到贵州山水,由真正生活在这里的人,陪你走进一段只属于你的私家旅程。', 'Private journeys into the heart of Guizhou—karst wonders, living cultures, and timeless landscapes, with local expertise every step of the way.', language)}

+
+