diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..f5565e2 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +tmp/ +.DS_Store + diff --git a/index.html b/index.html new file mode 100644 index 0000000..0158073 --- /dev/null +++ b/index.html @@ -0,0 +1,272 @@ + + + + + + + SportsClubOS | Old Klang Road Court Sports + + + + + +
Opening October 2027 Old Klang Road, Kuala Lumpur
+ + +
+
+
+

Kuala Lumpur's new court-sports destination

+

Your court.
Your community.

+

A purpose-built home for badminton, pickleball and tennis - created for players, families, juniors and teams.

+ +
+ Old Klang Road, Kuala Lumpur + Grand opening October 2027 +
+
+
+ Proposed multi-sport venue exterior at Old Klang Road +
Three sports
One home
+
+
+ +
+
14

Indoor
badminton courts

+
5

Indoor
pickleball courts

+
4

Indoor
tennis courts

+

Professional spaces.
Designed for everyone.

+
+ +
+
+

The venue

+

Built around how
people really play.

+
+
+

A modern indoor sports centre planned for one of Kuala Lumpur's most established and connected neighbourhoods.

+

From casual evening games to focused academy training, every floor brings courts, support spaces and community amenities together in one accessible destination.

+
+ +
+

Inside the venue

Step inside the game.

+

Explore the indoor court environments referenced in the proposal - spaces planned for everyday play, coaching and competition.

+
+ +
+ +
+
+

Three ways to move

+

Choose your court.

+

Dedicated indoor spaces planned for year-round play, training and competition.

+
+
+
+
Indoor badminton courts from the proposal14 courts
+
01 / Badminton

Fast. Focused.
Made for Malaysia.

Fourteen indoor courts form the heart of the venue, supporting everyday bookings, academy programmes and tournament play.

Register for court updates →
+
+
+
Pickleball court from the proposal5 courts
+
02 / Pickleball

Social by nature.
Serious when you are.

Five indoor pickleball courts - convertible for badminton - give new players and regular groups room to play their way.

Join the community →
+
+
+
Indoor tennis courts from the proposal4 courts
+
03 / Tennis

More court time.
Whatever the weather.

Four indoor tennis courts provide a dependable setting for lessons, friendly matches and performance sessions.

Ask about tennis →
+
+
+
+ +
+
Badminton equipment shop shown in the proposal
+
+

More than a court

+

Everything your game needs, under one roof.

+
+ Reception & waiting areaBadminton pro shopChanging roomsFitness gymMeeting roomLounge & food barCourt separation netsFire-safety access +
+
+
+ +
+
+

Space planning

+

A destination built
across every level.

+
+
+
+ + + + +
+
Ground floor venue plan

Arrival, reception, waiting area, pro shop, changing rooms, badminton courts and tennis courts.

+
+
+ +
+

Simple court booking

From “let's play”
to court confirmed.

+
    +
  1. 01Choose your sport
  2. 02Select your area
  3. 03Pick date & time
  4. 04Confirm your court
  5. 05Pay online
  6. +
+

The digital booking experience is planned to make court access easy, anytime and anywhere.

+
+ +
+
+

JUN Badminton Academy

+

Skills for the court.
Character for life.

+

Tailored programmes for ages 4 to 50, from beginners taking their first steps to advanced players preparing for competition.

+
Kids & adult group classesPrivate one-to-one trainingSingles & doubles programmesCorporate & school training
+ +
+
+
Tan Wei Jun, Head Coach of JUN Badminton Academy
+
Founder & head coach

Tan Wei Jun

Former Kedah state player
BAM Level 1-certified coach

+
+
+ Innovative drillsFitness programmesMental conditioningLocal competitions +
+
+ +
+

A venue with a pulse

Play here. Belong here.

The proposal is built around more than bookings: it imagines an active, connected local sports community.

+
+
01

Community events

Regular activities that bring neighbours, families and players together.

+
02

Seasonal programmes

Campaigns, clinics and formats that keep the calendar fresh year-round.

+
03

Leagues & competition

Pathways to play casually, test your level and compete with confidence.

+
04

Business partnerships

Space for corporate play, school programmes and local collaborations.

+
+
+ +
+
Proposed venue in the Old Klang Road neighbourhood
+
+

Old Klang Road / 旧巴生路

+

Connected to the city.
Rooted in the neighbourhood.

+

One of Kuala Lumpur's oldest major corridors, Old Klang Road sits between the city and Petaling Jaya, surrounded by mature residential and commercial communities.

+
Taman DesaOUGKuchai LamaTaman Sri Sentosa
+
  • Links to Federal Highway, NPE and LDP
  • A multicultural neighbourhood with a strong local food culture
  • Accessible to families, students, residents and corporate groups
+
+
+ +
+

Road to opening

Building towards
October 2027.

+
+
01

Planning permission

Four-month planning-permission phase within the wider project programme.

+
02

Earthwork & building plans

Approval work for earthworks and the building plan.

+
03

Construction

Six months planned for venue construction.

+
04

Completion & handover

CCC approval, completion and handover.

+
05

Grand opening

The first serves, rallies and community games begin.

+
+
+ +
+

Get on court early

Be the first to play.
Be part of the community.

Register for opening updates, academy news and early booking information.

+
+

Choose the channel that works best for you. Every contact detail can be copied individually.

+
Training programmesCourt enquiriesCorporate & school sessions
+ +
+
+
+ + + + + +

Contact JUN Academy

+ + +

+
+ Expanded venue view + + + diff --git a/public/assets/assistant-coaches.png b/public/assets/assistant-coaches.png new file mode 100644 index 0000000..a39431e Binary files /dev/null and b/public/assets/assistant-coaches.png differ diff --git a/public/assets/badminton-court.png b/public/assets/badminton-court.png new file mode 100644 index 0000000..47e520f Binary files /dev/null and b/public/assets/badminton-court.png differ diff --git a/public/assets/badminton-detail.png b/public/assets/badminton-detail.png new file mode 100644 index 0000000..88c9429 Binary files /dev/null and b/public/assets/badminton-detail.png differ diff --git a/public/assets/coach-tan-hq.png b/public/assets/coach-tan-hq.png new file mode 100644 index 0000000..89b48da Binary files /dev/null and b/public/assets/coach-tan-hq.png differ diff --git a/public/assets/coach-tan.png b/public/assets/coach-tan.png new file mode 100644 index 0000000..71f3de6 Binary files /dev/null and b/public/assets/coach-tan.png differ diff --git a/public/assets/pickleball-blue.png b/public/assets/pickleball-blue.png new file mode 100644 index 0000000..87eebd9 Binary files /dev/null and b/public/assets/pickleball-blue.png differ diff --git a/public/assets/pickleball-court.png b/public/assets/pickleball-court.png new file mode 100644 index 0000000..acf1e99 Binary files /dev/null and b/public/assets/pickleball-court.png differ diff --git a/public/assets/plan-ground.png b/public/assets/plan-ground.png new file mode 100644 index 0000000..b248117 Binary files /dev/null and b/public/assets/plan-ground.png differ diff --git a/public/assets/plan-level-1.png b/public/assets/plan-level-1.png new file mode 100644 index 0000000..cc34199 Binary files /dev/null and b/public/assets/plan-level-1.png differ diff --git a/public/assets/plan-level-2.png b/public/assets/plan-level-2.png new file mode 100644 index 0000000..f4c6684 Binary files /dev/null and b/public/assets/plan-level-2.png differ diff --git a/public/assets/plan-roof.png b/public/assets/plan-roof.png new file mode 100644 index 0000000..cde9e17 Binary files /dev/null and b/public/assets/plan-roof.png differ diff --git a/public/assets/pro-shop.png b/public/assets/pro-shop.png new file mode 100644 index 0000000..787103d Binary files /dev/null and b/public/assets/pro-shop.png differ diff --git a/public/assets/tennis-court.png b/public/assets/tennis-court.png new file mode 100644 index 0000000..bd30cef Binary files /dev/null and b/public/assets/tennis-court.png differ diff --git a/public/assets/tennis-indoor.png b/public/assets/tennis-indoor.png new file mode 100644 index 0000000..99413df Binary files /dev/null and b/public/assets/tennis-indoor.png differ diff --git a/public/assets/venue-entrance.png b/public/assets/venue-entrance.png new file mode 100644 index 0000000..568ef9b Binary files /dev/null and b/public/assets/venue-entrance.png differ diff --git a/public/assets/venue-front.png b/public/assets/venue-front.png new file mode 100644 index 0000000..0983ed3 Binary files /dev/null and b/public/assets/venue-front.png differ diff --git a/public/assets/venue-hero.png b/public/assets/venue-hero.png new file mode 100644 index 0000000..6ce291a Binary files /dev/null and b/public/assets/venue-hero.png differ diff --git a/public/assets/venue-section.png b/public/assets/venue-section.png new file mode 100644 index 0000000..fb2debb Binary files /dev/null and b/public/assets/venue-section.png differ diff --git a/public/assets/venue-side.png b/public/assets/venue-side.png new file mode 100644 index 0000000..1280b32 Binary files /dev/null and b/public/assets/venue-side.png differ diff --git a/public/assets/venue-street-a.png b/public/assets/venue-street-a.png new file mode 100644 index 0000000..dfa1424 Binary files /dev/null and b/public/assets/venue-street-a.png differ diff --git a/public/assets/venue-street-b.png b/public/assets/venue-street-b.png new file mode 100644 index 0000000..919d66a Binary files /dev/null and b/public/assets/venue-street-b.png differ diff --git a/script.js b/script.js new file mode 100644 index 0000000..4c75b70 --- /dev/null +++ b/script.js @@ -0,0 +1,265 @@ +const menuButton = document.querySelector('.menu-toggle'); +const nav = document.querySelector('.nav'); +const header = document.querySelector('.site-header'); +const scrollProgress = document.querySelector('.scroll-progress'); + +const EN_TO_ZH = { + 'Opening October 2027': '预计 2027 年 10 月开业', + 'Old Klang Road, Kuala Lumpur': '吉隆坡旧巴生路', + 'Venue': '场馆介绍', 'Courts': '球场', 'Spaces': '空间规划', 'Academy': '羽球学院', 'Community': '社区活动', 'Contact': '联系我们', + 'Register interest': '登记意向', 'Register interest →': '发送邮件咨询 →', + "Kuala Lumpur's new court-sports destination": '吉隆坡全新综合球类运动目的地', + 'Your court.': '你的球场。', 'Your community.': '你的社区。', + 'A purpose-built home for badminton, pickleball and tennis - created for players, families, juniors and teams.': '为羽毛球、匹克球与网球量身打造,为球员、家庭、青少年和团队提供共同的运动主场。', + 'Explore academy': '了解学院', 'Three sports': '三种运动', 'One home': '一个主场', + 'Grand opening': '预计开业', 'October 2027': '2027 年 10 月', + 'Indoor': '室内', 'badminton courts': '羽毛球场', 'pickleball courts': '匹克球场', 'tennis courts': '网球场', + 'Professional spaces.': '专业运动空间。', 'Designed for everyone.': '为每一个人打造。', + 'The venue': '场馆介绍', 'Built around how': '真正围绕', 'people': '人们的', 'really play.': '运动方式打造。', + "A modern indoor sports centre planned for one of Kuala Lumpur's most established and connected neighbourhoods.": '一座规划于吉隆坡成熟、交通便利社区中的现代室内体育中心。', + 'From casual evening games to focused academy training, every floor brings courts, support spaces and community amenities together in one accessible destination.': '从轻松的晚间约球到系统的学院训练,每一层都把球场、辅助空间与社区配套集中在同一个便捷目的地。', + 'Entrance perspective': '入口效果图', 'Front elevation': '建筑正立面', 'Street context': '街景效果图', + 'Inside the venue': '走进场馆', 'Step inside the': '走进', 'game.': '运动现场。', + 'Explore the indoor court environments referenced in the proposal - spaces planned for everyday play, coaching and competition.': '查看提案中的场内环境,为日常约球、专业训练和赛事活动规划的运动空间。', + 'Indoor badminton courts': '室内羽毛球场', 'Pickleball courts': '匹克球场', 'Indoor tennis courts': '室内网球场', 'Indoor multi-court space': '室内多用途球场', 'Outdoor tennis courts': '室外网球场', + 'Three ways to move': '三种运动方式', 'Choose your': '选择你的', 'court.': '球场。', + 'Dedicated indoor spaces planned for year-round play, training and competition.': '为全年运动、训练和比赛规划的专业室内空间。', + '14 courts': '14 个球场', '5 courts': '5 个球场', '4 courts': '4 个球场', + '01 / Badminton': '01 / 羽毛球', '02 / Pickleball': '02 / 匹克球', '03 / Tennis': '03 / 网球', + 'Fast. Focused.': '快速。专注。', 'Made for Malaysia.': '为马来西亚而生。', + 'Fourteen indoor courts form the heart of the venue, supporting everyday bookings, academy programmes and tournament play.': '14 个室内羽毛球场构成场馆核心,满足日常预约、学院课程及赛事活动。', + 'Register for court updates →': '登记球场资讯 →', + 'Social by nature.': '天生适合社交。', 'Serious when you are.': '也能认真竞技。', + 'Five indoor pickleball courts - convertible for badminton - give new players and regular groups room to play their way.': '5 个室内匹克球场可转换为羽毛球场,让新手与固定球友都能自在开打。', + 'Join the community →': '加入社区 →', + 'More court time.': '更多上场时间。', 'Whatever the weather.': '无惧天气变化。', + 'Four indoor tennis courts provide a dependable setting for lessons, friendly matches and performance sessions.': '4 个室内网球场为课程、友谊赛和进阶训练提供稳定环境。', + 'Ask about tennis →': '咨询网球场 →', + 'More than a court': '不只是球场', 'Everything your game needs,': '运动所需的一切,', 'under one roof.': '都在同一屋檐下。', + 'Reception & waiting area': '前台与等候区', 'Badminton pro shop': '羽毛球用品店', 'Changing rooms': '更衣室', 'Fitness gym': '健身房', 'Meeting room': '会议室', 'Lounge & food bar': '休息室与餐饮吧', 'Court separation nets': '球场隔离网', 'Fire-safety access': '消防通道', + 'Space planning': '空间规划', 'A destination built': '逐层规划的', 'across every level.': '综合运动目的地。', + 'Ground': '底层', 'Arrival & first courts': '接待与首层球场', 'Level 1': '一楼', 'Play, train & recharge': '运动、训练与休息', 'Level 2': '二楼', 'Expanded court capacity': '扩展球场容量', 'Upper level': '上层', 'The full venue programme': '完整场馆布局', + 'Arrival, reception, waiting area, pro shop, changing rooms, badminton courts and tennis courts.': '设置场馆入口、前台、等候区、用品店、更衣室、羽毛球场与网球场。', + 'Badminton and pickleball courts supported by changing rooms, meeting room, fitness gym, lounge and food bar.': '羽毛球与匹克球场配套更衣室、会议室、健身房、休息室与餐饮吧。', + 'Additional badminton, pickleball and tennis capacity with dedicated circulation and court separation.': '增加羽毛球、匹克球与网球场地,并配置独立动线与球场隔离。', + "The upper-level court plan completes the building's multi-sport programme and maximises playable space.": '上层球场完善整栋建筑的综合运动布局,并最大化可运动空间。', + 'Simple court booking': '轻松预约球场', 'From “let\'s play”': '从“约场球吧”', 'to': '到', 'court confirmed.': '确认球场。', + 'Choose your sport': '选择运动项目', 'Select your area': '选择地区', 'Pick date & time': '选择日期与时间', 'Confirm your court': '确认时间与场地', 'Pay online': '线上付款', + 'The digital booking experience is planned to make court access easy, anytime and anywhere.': '数字预约流程让用户随时随地轻松预订球场。', + 'JUN Badminton Academy': 'JUN 羽毛球学院', 'Skills for the court.': '练就球场技能。', 'Character for life.': '塑造终身品格。', + 'Tailored programmes for ages 4 to 50, from beginners taking their first steps to advanced players preparing for competition.': '为 4 至 50 岁不同水平的学员提供定制课程,从初学入门到进阶备赛。', + 'Kids & adult group classes': '儿童与成人团体课程', 'Private one-to-one training': '私人一对一训练', 'Singles & doubles programmes': '单打与双打课程', 'Corporate & school training': '企业与学校训练', + 'Enquire about training →': '咨询训练课程 →', 'Founder & head coach': '创办人兼主教练', 'Former Kedah state player': '前吉打州代表队球员', 'BAM Level 1-certified coach': '马来西亚羽总一级认证教练', + 'Innovative drills': '创新训练', 'Fitness programmes': '体能课程', 'Mental conditioning': '心理训练', 'Local competitions': '本地赛事', + 'A venue with a pulse': '充满活力的场馆', 'Play here.': '在这里运动。', 'Belong here.': '在这里找到归属。', + 'The proposal is built around more than bookings: it imagines an active, connected local sports community.': '项目不只关注预约,更希望打造一个活跃、紧密连接的本地运动社区。', + 'Community events': '社区活动', 'Regular activities that bring neighbours, families and players together.': '通过定期活动连接邻里、家庭和球友。', + 'Seasonal programmes': '季节性活动', 'Campaigns, clinics and formats that keep the calendar fresh year-round.': '以主题推广、训练营和多种赛制丰富全年活动。', + 'Leagues & competition': '联赛与竞技', 'Pathways to play casually, test your level and compete with confidence.': '从休闲约球、水平测试到正式竞技,提供清晰进阶路径。', + 'Business partnerships': '商业合作', 'Space for corporate play, school programmes and local collaborations.': '承接企业活动、学校课程及本地合作项目。', + 'Old Klang Road / 旧巴生路': '旧巴生路 / Old Klang Road', 'Connected to the city.': '连接城市。', 'Rooted in the neighbourhood.': '扎根社区。', + "One of Kuala Lumpur's oldest major corridors, Old Klang Road sits between the city and Petaling Jaya, surrounded by mature residential and commercial communities.": '旧巴生路是吉隆坡历史悠久的重要道路之一,连接市区与八打灵再也,周边拥有成熟住宅和商业社区。', + 'Links to Federal Highway, NPE and LDP': '连接联邦大道、NPE 与 LDP', 'A multicultural neighbourhood with a strong local food culture': '多元族群共融,并拥有丰富本地美食文化', 'Accessible to families, students, residents and corporate groups': '方便家庭、学生、居民与企业团队到访', + 'Road to opening': '开业进程', 'Building towards': '稳步迈向', 'Planning permission': '规划许可', 'Earthwork & building plans': '土方与建筑计划', 'Construction': '场馆施工', 'Completion & handover': '完工审批与交付', 'Grand opening': '正式开业', + 'Four-month planning-permission phase within the wider project programme.': '项目规划中的四个月规划许可申请阶段。', 'Approval work for earthworks and the building plan.': '完成土方工程与建筑计划审批。', 'Six months planned for venue construction.': '预计用六个月完成场馆施工。', 'CCC approval, completion and handover.': '完成合规证书审批、完工与交付。', 'The first serves, rallies and community games begin.': '迎来首场发球、对打与社区活动。', + 'Get on court early': '抢先上场', 'Be the first to play.': '成为首批球友。', 'Be part of the community.': '加入我们的社区。', 'Register for opening updates, academy news and early booking information.': '登记获取开业动态、学院资讯与优先预约信息。', + 'Choose the channel that works best for you. Every contact detail can be copied individually.': '选择最方便的联系方式,每条信息都可以单独复制。', 'Training programmes': '训练课程', 'Court enquiries': '球场咨询', 'Corporate & school sessions': '企业与学校课程', 'View contact details →': '查看联系方式 →', + 'Contact JUN Academy': '联系 JUN 学院', 'Choose a channel.': '选择联系方式。', 'Copy and connect.': '复制后自行联系。', 'Copy any contact detail below, then reach out using the app you prefer.': '单独复制下方任意联系信息,再使用你常用的应用与我们联系。', + 'Phone': '电话', 'Email': '邮箱', 'Xiaohongshu': '小红书', 'Address': '地址', 'Copy': '复制', + 'Your name': '姓名', 'Email address': '电子邮箱', "I'm interested in": '感兴趣的内容', 'Name': '姓名', + 'Court bookings': '球场预约', 'JUN Badminton Academy': 'JUN 羽毛球学院', 'Corporate or school programmes': '企业或学校课程', 'Opening updates': '开业动态', + 'A new home for court sports at Old Klang Road, Kuala Lumpur.': '位于吉隆坡旧巴生路的全新球类运动主场。', 'JUN Academy': 'JUN 学院', 'Explore': '网站导航', 'Location': '场馆位置', + 'Ground Floor, Jalan Perdana 1,': '底层,Jalan Perdana 1,', 'Taman Segar Perdana, 43200 Cheras, Selangor': 'Taman Segar Perdana,43200 蕉赖,雪兰莪', + 'Proposed venue information based on the current project proposal. Plans and opening schedule are subject to final approvals.': '场馆资料来自当前项目提案,具体规划与开业时间以最终审批为准。' +}; + +const ORIGINAL_TEXT = new WeakMap(); + +function translateTextNodes(isChinese) { + const walker = document.createTreeWalker(document.body, NodeFilter.SHOW_TEXT); + const nodes = []; + while (walker.nextNode()) nodes.push(walker.currentNode); + nodes.forEach((node) => { + if (['SCRIPT', 'STYLE'].includes(node.parentElement?.tagName)) return; + if (node.parentElement?.closest('.footer-contact') || node.parentElement?.closest('.contact-value')) return; + if (!isChinese) { + if (ORIGINAL_TEXT.has(node)) node.nodeValue = ORIGINAL_TEXT.get(node); + return; + } + if (!ORIGINAL_TEXT.has(node)) ORIGINAL_TEXT.set(node, node.nodeValue); + const original = ORIGINAL_TEXT.get(node); + const value = original.trim(); + if (value && EN_TO_ZH[value]) node.nodeValue = original.replace(value, EN_TO_ZH[value]); + }); +} + +function setLanguage(language) { + const isChinese = language === 'zh'; + translateTextNodes(isChinese); + document.documentElement.lang = isChinese ? 'zh-CN' : 'en'; + document.querySelectorAll('.language-toggle').forEach((button) => { + button.textContent = isChinese ? 'EN' : '中文'; + button.setAttribute('aria-label', isChinese ? 'Switch to English' : '切换为中文'); + }); + const nameInput = document.querySelector('input[name="name"]'); + if (nameInput) nameInput.placeholder = isChinese ? '姓名' : 'Name'; + const activePlanCopy = document.querySelector('.plan-tab.active')?.dataset.copy; + const planDescription = document.querySelector('#plan-copy'); + if (activePlanCopy && planDescription) planDescription.textContent = isChinese ? (EN_TO_ZH[activePlanCopy] || activePlanCopy) : activePlanCopy; + const formStatus = document.querySelector('.form-status'); + if (formStatus) formStatus.textContent = ''; + localStorage.setItem('site-language', language); +} + +document.querySelectorAll('.language-toggle').forEach((button) => { + button.addEventListener('click', () => { + setLanguage(document.documentElement.lang.startsWith('zh') ? 'en' : 'zh'); + }); +}); + +setLanguage(localStorage.getItem('site-language') === 'zh' ? 'zh' : 'en'); + +menuButton?.addEventListener('click', () => { + const open = nav.classList.toggle('open'); + menuButton.setAttribute('aria-expanded', String(open)); +}); + +nav?.querySelectorAll('a').forEach((link) => { + link.addEventListener('click', () => { + nav.classList.remove('open'); + menuButton?.setAttribute('aria-expanded', 'false'); + }); +}); + +let headerAnchor = header?.offsetTop ?? 0; +window.addEventListener('scroll', () => { + if (!header) return; + header.classList.toggle('is-sticky', window.scrollY > headerAnchor + 160); + document.body.style.paddingTop = header.classList.contains('is-sticky') ? `${header.offsetHeight}px` : '0'; + const scrollable = document.documentElement.scrollHeight - window.innerHeight; + const progress = scrollable > 0 ? Math.min(1, Math.max(0, window.scrollY / scrollable)) : 0; + if (scrollProgress) scrollProgress.style.transform = `scaleX(${progress})`; +}, { passive: true }); + +const planImage = document.querySelector('#plan-image'); +const planCopy = document.querySelector('#plan-copy'); +document.querySelectorAll('.plan-tab').forEach((tab) => { + tab.addEventListener('click', () => { + document.querySelectorAll('.plan-tab').forEach((item) => { + item.classList.remove('active'); + item.setAttribute('aria-selected', 'false'); + }); + tab.classList.add('active'); + tab.setAttribute('aria-selected', 'true'); + planImage.style.opacity = '0'; + setTimeout(() => { + planImage.src = tab.dataset.plan; + planImage.alt = `${tab.querySelector('strong').textContent} venue plan`; + const planText = tab.dataset.copy; + planCopy.textContent = document.documentElement.lang.startsWith('zh') ? (EN_TO_ZH[planText] || planText) : planText; + planImage.style.opacity = '1'; + }, 160); + }); +}); + +const lightbox = document.querySelector('#lightbox'); +const lightboxImage = lightbox?.querySelector('img'); +document.querySelectorAll('.gallery-item').forEach((item) => { + item.addEventListener('click', () => { + lightboxImage.src = item.dataset.image; + lightbox.showModal(); + }); +}); +lightbox?.querySelector('button').addEventListener('click', () => lightbox.close()); +lightbox?.addEventListener('click', (event) => { + if (event.target === lightbox) lightbox.close(); +}); + +const revealObserver = new IntersectionObserver((entries) => { + entries.forEach((entry) => { + if (entry.isIntersecting) { + entry.target.classList.add('visible'); + revealObserver.unobserve(entry.target); + } + }); +}, { threshold: 0.08, rootMargin: '0px 0px -30px' }); +document.querySelectorAll('.reveal').forEach((element) => revealObserver.observe(element)); + +const reducedMotion = window.matchMedia('(prefers-reduced-motion: reduce)').matches; +const countSection = document.querySelector('.court-counts'); +const countNumbers = [...document.querySelectorAll('.court-count strong')]; +if (countSection && !reducedMotion) { + const countObserver = new IntersectionObserver((entries) => { + if (!entries.some((entry) => entry.isIntersecting)) return; + countNumbers.forEach((number) => { + const target = Number(number.textContent); + const start = performance.now(); + const duration = 850; + number.classList.add('counting'); + const update = (now) => { + const elapsed = Math.min(1, (now - start) / duration); + const eased = 1 - Math.pow(1 - elapsed, 3); + number.textContent = String(Math.round(target * eased)); + if (elapsed < 1) requestAnimationFrame(update); + else number.classList.remove('counting'); + }; + requestAnimationFrame(update); + }); + countObserver.disconnect(); + }, { threshold: .35 }); + countObserver.observe(countSection); +} + +const contactModal = document.querySelector('#contact-modal'); +const copyStatus = contactModal?.querySelector('.copy-status'); + +document.querySelectorAll('.contact-modal-trigger').forEach((button) => { + button.addEventListener('click', () => { + if (!contactModal?.open) contactModal.showModal(); + }); +}); + +contactModal?.querySelector('.modal-close').addEventListener('click', () => contactModal.close()); +contactModal?.addEventListener('click', (event) => { + if (event.target === contactModal) contactModal.close(); +}); + +async function copyContactText(text) { + if (navigator.clipboard?.writeText) { + try { + await navigator.clipboard.writeText(text); + return true; + } catch (_) { + // Fall through to the file:// compatible copy method. + } + } + const field = document.createElement('textarea'); + field.value = text; + field.setAttribute('readonly', ''); + field.style.position = 'fixed'; + field.style.opacity = '0'; + document.body.appendChild(field); + field.select(); + const copied = document.execCommand('copy'); + field.remove(); + return copied; +} + +document.querySelectorAll('.copy-contact').forEach((button) => { + button.addEventListener('click', async () => { + const copied = await copyContactText(button.dataset.copy); + const isChinese = document.documentElement.lang.startsWith('zh'); + if (copyStatus) { + copyStatus.textContent = copied + ? (isChinese ? `已复制:${button.dataset.copy}` : `Copied: ${button.dataset.copy}`) + : (isChinese ? '复制失败,请手动选择文字复制。' : 'Copy failed. Please select and copy the text manually.'); + } + if (!copied) return; + button.textContent = isChinese ? '已复制' : 'Copied'; + button.classList.add('copied'); + setTimeout(() => { + button.textContent = isChinese ? '复制' : 'Copy'; + button.classList.remove('copied'); + }, 1600); + }); +}); diff --git a/styles.css b/styles.css new file mode 100644 index 0000000..ef1bf4a --- /dev/null +++ b/styles.css @@ -0,0 +1,363 @@ +:root { + --blue: #0b43bf; + --blue-dark: #072a82; + --orange: #f36c21; + --green: #3f8f43; + --ink: #101419; + --muted: #656b73; + --line: #dfe2e7; + --paper: #f7f8fa; + --display: Impact, Haettenschweiler, "Arial Narrow Bold", sans-serif; + --body: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; +} + +* { box-sizing: border-box; } +html { scroll-behavior: smooth; } +body { margin: 0; color: var(--ink); background: #fff; font-family: var(--body); font-size: 16px; line-height: 1.55; overflow-x: hidden; } +.scroll-progress { position: fixed; top: 0; left: 0; width: 100%; height: 3px; z-index: 100; background: var(--orange); transform: scaleX(0); transform-origin: left center; pointer-events: none; will-change: transform; } +img { width: 100%; display: block; } +a { color: inherit; text-decoration: none; } +button, input, select { font: inherit; } +button { color: inherit; } + +.announcement { height: 31px; display: flex; align-items: center; justify-content: center; gap: 12px; background: var(--blue); color: #fff; text-transform: uppercase; letter-spacing: .18em; font-size: 10px; font-weight: 800; } +.announcement span { width: 3px; height: 3px; border-radius: 50%; background: var(--orange); } +.site-header { height: 78px; max-width: 1440px; margin: auto; padding: 0 4.5vw; display: flex; align-items: center; gap: 42px; background: #fff; position: relative; z-index: 20; } +.site-header.is-sticky { position: fixed; top: 0; left: 0; right: 0; max-width: none; box-shadow: 0 6px 30px rgb(0 0 0 / 8%); animation: drop .25s ease; } +@keyframes drop { from { transform: translateY(-100%); } } +.brand { font-size: clamp(20px, 2.1vw, 31px); font-weight: 900; letter-spacing: -.06em; color: var(--blue); white-space: nowrap; } +.brand span { color: var(--orange); } +.nav { display: flex; align-items: center; justify-content: center; gap: 32px; margin-left: auto; } +.nav a { position: relative; font-size: 11px; font-weight: 900; text-transform: uppercase; letter-spacing: .06em; } +.nav a::after { content: ""; position: absolute; left: 0; right: 100%; bottom: -8px; height: 2px; background: var(--orange); transition: .25s; } +.nav a:hover::after { right: 0; } +.header-actions { display: flex; align-items: center; gap: 18px; } +.language { padding: 0; border: 0; background: transparent; font-size: 12px; font-weight: 800; cursor: pointer; } +.language-mobile { display: none; } +.button { min-height: 48px; padding: 0 23px; display: inline-flex; align-items: center; justify-content: center; gap: 22px; border: 2px solid var(--blue); background: var(--blue); color: #fff; text-transform: uppercase; letter-spacing: .04em; font-size: 11px; font-weight: 900; cursor: pointer; transition: transform .2s, background .2s, color .2s; } +.button:hover { transform: translateY(-2px); background: var(--blue-dark); } +.button b { transition: transform .22s ease; } +.button:hover b { transform: translateX(4px); } +.button-small { min-height: 41px; padding: 0 18px; } +.button-outline { color: var(--blue); background: transparent; } +.button-outline:hover { color: #fff; } +.menu-toggle { display: none; border: 0; background: transparent; width: 38px; height: 38px; padding: 8px; } +.menu-toggle i { display: block; height: 2px; background: var(--ink); margin: 6px 0; } + +.hero { min-height: 680px; display: grid; grid-template-columns: minmax(400px, .86fr) 1.45fr; background: linear-gradient(100deg, #fff 0%, #fff 42%, #edf4ff 42%, #edf4ff 100%); overflow: hidden; } +.hero-copy { padding: clamp(70px, 9vw, 132px) 1vw 70px max(5vw, calc((100vw - 1320px)/2)); position: relative; z-index: 2; } +.hero-copy > * { animation: hero-copy-in .7s both cubic-bezier(.22,.8,.32,1); } +.hero-copy > *:nth-child(2) { animation-delay: .08s; } +.hero-copy > *:nth-child(3) { animation-delay: .15s; } +.hero-copy > *:nth-child(4) { animation-delay: .22s; } +.hero-copy > *:nth-child(5) { animation-delay: .29s; } +@keyframes hero-copy-in { from { opacity: 0; transform: translateY(24px); } to { opacity: 1; transform: none; } } +.eyebrow { margin: 0 0 16px; color: var(--blue); font-size: 11px; line-height: 1; text-transform: uppercase; letter-spacing: .16em; font-weight: 900; } +h1, h2 { margin: 0; font-family: var(--display); font-weight: 900; text-transform: uppercase; line-height: .96; letter-spacing: .005em; } +h1 { font-size: clamp(60px, 6.6vw, 104px); } +h1 em, h2 em { color: var(--blue); font-style: normal; } +.hero-lede { max-width: 480px; margin: 28px 0 30px; font-size: clamp(17px, 1.55vw, 21px); line-height: 1.5; } +.hero-actions { display: flex; flex-wrap: wrap; gap: 14px; } +.hero-meta { display: grid; gap: 11px; margin-top: 38px; color: #353a42; font-size: 13px; } +.hero-meta span { display: flex; align-items: center; gap: 9px; } +.hero-meta svg { width: 18px; height: 18px; fill: none; stroke: var(--blue); stroke-width: 1.8; } +.hero-meta strong { color: var(--orange); } +.hero-image { position: relative; min-width: 0; } +.hero-image { animation: hero-image-in 1s both cubic-bezier(.2,.75,.25,1); transform-origin: right center; } +@keyframes hero-image-in { from { opacity: 0; transform: scale(1.035) translateX(24px); } to { opacity: 1; transform: none; } } +.hero-image::before { content: ""; position: absolute; inset: 0; background: linear-gradient(90deg, #edf4ff 0, transparent 22%); z-index: 1; pointer-events: none; } +.hero-image img { height: 100%; object-fit: cover; object-position: center; } +.hero-stamp { position: absolute; right: 5vw; bottom: 40px; z-index: 2; width: 122px; height: 122px; border-radius: 50%; display: grid; place-content: center; border: 1px solid #fff; background: rgb(11 67 191 / 88%); color: #fff; text-align: center; text-transform: uppercase; transform: rotate(-8deg); font-size: 10px; letter-spacing: .12em; } +.hero-stamp strong { font-family: var(--display); font-size: 22px; letter-spacing: .03em; } + +.court-counts { max-width: 1180px; min-height: 155px; margin: 0 auto; display: grid; grid-template-columns: repeat(3, 1fr) .9fr; align-items: center; border-bottom: 1px solid var(--line); } +.court-count { height: 80px; padding: 0 34px; display: grid; grid-template-columns: auto auto 1fr; align-items: center; gap: 15px; border-right: 1px solid var(--line); } +.court-count strong { font-family: var(--display); color: var(--blue); font-size: 60px; line-height: 1; } +.court-count strong.counting { color: var(--orange); } +.court-count p { margin: 0; text-transform: uppercase; font-family: var(--display); font-size: 16px; line-height: 1.1; } +.sport-mark { width: 42px; height: 42px; display: grid; place-items: center; font-size: 35px; line-height: 1; } +.badminton { color: var(--blue); }.pickleball { color: var(--green); }.tennis { color: var(--orange); } +.count-note { padding-left: 34px; font-size: 13px; line-height: 1.5; color: var(--muted); } + +.section { padding: 120px max(5vw, calc((100vw - 1320px)/2)); } +.section-heading { display: flex; justify-content: space-between; align-items: flex-end; gap: 30px; margin-bottom: 52px; } +.section-heading h2, .amenities h2, .booking-flow h2, .academy h2, .location h2, .contact h2 { font-size: clamp(48px, 5vw, 78px); } +.section-heading h2::after { content: ""; display: block; width: 54px; height: 4px; margin-top: 20px; background: var(--orange); transform: scaleX(0); transform-origin: left; transition: transform .7s .18s cubic-bezier(.2,.8,.3,1); } +.section-heading.centered h2::after { margin-inline: auto; transform-origin: center; } +.section-heading.visible h2::after { transform: scaleX(1); } +.section-heading.centered { display: block; max-width: 700px; margin: 0 auto 58px; text-align: center; } +.section-heading.centered > p:last-child { max-width: 580px; margin: 22px auto 0; color: var(--muted); } +.intro { display: grid; grid-template-columns: 1.1fr .8fr; gap: 20px 7vw; } +.intro .section-heading { margin: 0; display: block; } +.intro-copy { align-self: end; padding-bottom: 8px; color: var(--muted); } +.intro-copy .lead { color: var(--ink); font-size: 19px; font-weight: 650; } +.venue-gallery { grid-column: 1 / -1; display: grid; grid-template-columns: 1.55fr .8fr; grid-template-rows: repeat(2, 245px); gap: 12px; margin-top: 35px; } +.gallery-item { border: 0; margin: 0; padding: 0; position: relative; overflow: hidden; cursor: zoom-in; background: #eee; } +.gallery-main { grid-row: 1 / 3; } +.gallery-item img { width: 100%; height: 100%; object-fit: cover; transition: transform .55s ease; } +.gallery-item:hover img { transform: scale(1.035); } +.gallery-item::after { content: "↗"; position: absolute; right: 14px; top: 14px; width: 30px; height: 30px; display: grid; place-items: center; border-radius: 50%; color: #fff; background: rgb(11 67 191 / 86%); opacity: 0; transform: translateY(6px); transition: .25s; font-size: 12px; } +.gallery-item:hover::after { opacity: 1; transform: none; } +.gallery-item span { position: absolute; left: 16px; bottom: 14px; padding: 7px 10px; background: #fff; color: var(--ink); text-transform: uppercase; letter-spacing: .08em; font-size: 9px; font-weight: 900; } +.interior-intro { grid-column: 1 / -1; margin-top: 58px; display: grid; grid-template-columns: 1fr 1fr; gap: 6vw; align-items: end; } +.interior-intro .eyebrow { margin-bottom: 10px; } +.interior-intro h3 { margin: 0; font-family: var(--display); font-size: clamp(38px, 4vw, 60px); line-height: 1; text-transform: uppercase; } +.interior-intro h3 em { color: var(--blue); font-style: normal; } +.interior-intro > p { max-width: 560px; margin: 0; color: var(--muted); } +.interior-gallery { grid-column: 1 / -1; display: grid; grid-template-columns: repeat(3, 1fr); gap: 12px; margin-top: 24px; } +.interior-item { height: 270px; } + +.courts { background: var(--paper); } +.sport-grid { display: grid; gap: 34px; } +.sport-card { display: grid; grid-template-columns: 1.08fr 1fr; min-height: 410px; background: #fff; } +.sport-card:nth-child(even) .sport-image { order: 2; } +.sport-image { min-height: 390px; position: relative; overflow: hidden; } +.sport-image img { height: 100%; object-fit: cover; transition: transform .5s; } +.sport-card:hover .sport-image img { transform: scale(1.03); } +.sport-image span { position: absolute; top: 0; left: 0; padding: 14px 18px; background: var(--orange); color: #fff; font-size: 11px; font-weight: 900; text-transform: uppercase; } +.sport-content { padding: clamp(35px, 5vw, 70px); align-self: center; } +.sport-content small { color: var(--blue); font-size: 10px; font-weight: 900; text-transform: uppercase; letter-spacing: .14em; } +.sport-content h3 { margin: 12px 0 20px; font-family: var(--display); font-size: clamp(35px, 3.4vw, 54px); line-height: 1; text-transform: uppercase; } +.sport-content p { color: var(--muted); max-width: 500px; } +.sport-content a { display: inline-block; margin-top: 16px; color: var(--blue); text-transform: uppercase; letter-spacing: .06em; font-size: 11px; font-weight: 900; } + +.amenities { display: grid; grid-template-columns: .85fr 1.15fr; background: var(--ink); color: #fff; } +.amenities-image { min-height: 610px; } +.amenities-image img { height: 100%; object-fit: cover; } +.amenities-content { padding: clamp(70px, 8vw, 130px); align-self: center; } +.eyebrow-light { color: #82a9ff; } +.amenities h2 em, .booking-flow h2 em, .contact h2 em { color: #fff; -webkit-text-stroke: 1px #fff; } +.amenity-list { margin-top: 44px; display: grid; grid-template-columns: 1fr 1fr; border-top: 1px solid rgb(255 255 255 / 20%); } +.amenity-list span { padding: 16px 0; border-bottom: 1px solid rgb(255 255 255 / 20%); font-size: 13px; } +.amenity-list span::before { content: "+"; color: var(--orange); margin-right: 10px; font-weight: 900; } + +.plans { background: #fff; } +.plan-layout { display: grid; grid-template-columns: 330px 1fr; gap: 50px; align-items: start; } +.plan-tabs { border-top: 1px solid var(--line); } +.plan-tab { width: 100%; padding: 24px 10px; display: grid; grid-template-columns: 100px 1fr; text-align: left; border: 0; border-bottom: 1px solid var(--line); background: transparent; cursor: pointer; } +.plan-tab strong { font-family: var(--display); font-size: 25px; text-transform: uppercase; } +.plan-tab span { color: var(--muted); font-size: 12px; align-self: center; } +.plan-tab.active { padding-left: 18px; color: var(--blue); box-shadow: inset 4px 0 var(--orange); background: #f4f7ff; } +.plan-visual { min-width: 0; background: var(--paper); padding: 30px; } +.plan-visual img { height: min(52vw, 620px); object-fit: contain; mix-blend-mode: multiply; } +.plan-visual p { max-width: 680px; margin: 20px auto 0; padding-top: 16px; border-top: 1px solid var(--line); color: var(--muted); text-align: center; font-size: 13px; } + +.booking-flow { padding: 100px max(5vw, calc((100vw - 1320px)/2)); color: #fff; background: var(--blue); position: relative; overflow: hidden; } +.booking-flow::after { content: ""; width: 350px; height: 620px; position: absolute; right: -140px; top: -220px; border: 1px solid rgb(255 255 255 / 20%); transform: rotate(36deg); } +.booking-title { display: flex; align-items: end; justify-content: space-between; } +.booking-title .eyebrow { align-self: start; } +.steps { list-style: none; padding: 0; margin: 65px 0 20px; display: grid; grid-template-columns: repeat(5, 1fr); counter-reset: step; } +.steps li { min-height: 120px; padding: 0 20px; display: flex; flex-direction: column; justify-content: space-between; border-left: 1px solid rgb(255 255 255 / 35%); } +.steps b { color: #7fa6ff; font-size: 11px; } +.steps span { font-family: var(--display); font-size: clamp(22px, 2.2vw, 34px); line-height: 1; text-transform: uppercase; } +.booking-note { max-width: 580px; margin: 28px 0 0; color: #d7e3ff; font-size: 13px; } + +.academy { padding: 110px max(5vw, calc((100vw - 1320px)/2)) 0; display: grid; grid-template-columns: 1fr .78fr; background: linear-gradient(120deg, #fff 0, #fff 64%, #f0f5ff 64%); overflow: hidden; } +.academy-copy { padding: 20px 7vw 100px 0; } +.academy-copy > p:not(.eyebrow) { max-width: 600px; color: var(--muted); font-size: 17px; } +.programmes { display: grid; grid-template-columns: 1fr 1fr; gap: 0 24px; margin: 30px 0 36px; } +.programmes span { padding: 13px 0; border-bottom: 1px solid var(--line); font-size: 12px; font-weight: 750; } +.programmes span::before { content: "✓"; color: var(--orange); margin-right: 9px; } +.coach-card { align-self: end; position: relative; min-height: 610px; } +.coach-image { height: 610px; display: flex; align-items: flex-end; justify-content: center; background: radial-gradient(circle at 50% 45%, #e9f1ff, #cbdcff 68%, transparent 69%); } +.coach-image img { width: auto; max-width: 100%; height: 94%; object-fit: contain; object-position: bottom; filter: drop-shadow(0 20px 25px rgb(17 45 94 / 18%)); } +.coach-info { position: absolute; right: 0; bottom: 35px; padding: 20px 25px; min-width: 250px; background: var(--blue); color: #fff; } +.coach-info small { color: #a9c1ff; text-transform: uppercase; letter-spacing: .12em; font-size: 9px; font-weight: 900; } +.coach-info h3 { margin: 7px 0 3px; font-family: var(--display); font-size: 32px; text-transform: uppercase; } +.coach-info p { margin: 0; font-size: 11px; } +.academy-philosophy { grid-column: 1 / -1; display: grid; grid-template-columns: repeat(4, 1fr); color: #fff; background: var(--ink); } +.academy-philosophy span { padding: 28px 25px; border-right: 1px solid #34373c; text-align: center; text-transform: uppercase; font-size: 11px; font-weight: 850; letter-spacing: .06em; } + +.community { background: var(--paper); } +.community-grid { display: grid; grid-template-columns: repeat(4, 1fr); border-top: 1px solid #cfd3da; border-left: 1px solid #cfd3da; } +.community-grid article { min-height: 290px; padding: 34px; border-right: 1px solid #cfd3da; border-bottom: 1px solid #cfd3da; background: #fff; transition: .25s; } +.community-grid article:hover { color: #fff; background: var(--blue); transform: translateY(-5px); } +.community-grid b { color: var(--orange); font-size: 11px; } +.community-grid h3 { margin: 70px 0 15px; font-family: var(--display); font-size: 30px; text-transform: uppercase; line-height: 1; } +.community-grid p { margin: 0; color: var(--muted); font-size: 13px; } +.community-grid article:hover p { color: #d9e3ff; } + +.location { display: grid; grid-template-columns: 1.05fr .95fr; } +.location-image { min-height: 680px; } +.location-image img { height: 100%; object-fit: cover; } +.location-copy { padding: clamp(65px, 7vw, 115px); align-self: center; } +.location-copy > p:not(.eyebrow), .location-copy li { color: var(--muted); } +.nearby { margin: 30px 0; display: flex; flex-wrap: wrap; gap: 9px; } +.nearby span { padding: 8px 12px; border: 1px solid var(--blue); color: var(--blue); font-size: 10px; font-weight: 900; text-transform: uppercase; } +.location-copy ul { padding-left: 17px; } +.location-copy li { margin: 10px 0; } + +.timeline { background: #fff; } +.timeline-track { display: grid; grid-template-columns: repeat(5, 1fr); position: relative; } +.timeline-track::before { content: ""; position: absolute; left: 0; right: 0; top: 22px; height: 2px; background: var(--line); } +.timeline-track article { padding: 70px 24px 25px 0; position: relative; } +.timeline-track article::before { content: ""; position: absolute; top: 14px; left: 0; width: 18px; height: 18px; border: 5px solid #fff; border-radius: 50%; background: var(--blue); box-shadow: 0 0 0 1px var(--blue); } +.timeline-track.visible article::before { animation: timeline-pulse .55s both; } +.timeline-track.visible article:nth-child(2)::before { animation-delay: .1s; } +.timeline-track.visible article:nth-child(3)::before { animation-delay: .2s; } +.timeline-track.visible article:nth-child(4)::before { animation-delay: .3s; } +.timeline-track.visible article:nth-child(5)::before { animation-delay: .4s; } +@keyframes timeline-pulse { 0% { transform: scale(.25); opacity: 0; } 65% { transform: scale(1.25); } 100% { transform: scale(1); opacity: 1; } } +.timeline-track b { color: #a1a6ae; font-size: 10px; } +.timeline-track time { display: block; margin: 10px 0 8px; color: var(--blue); font-size: 11px; font-weight: 900; text-transform: uppercase; } +.timeline-track h3 { margin: 0 0 12px; font-family: var(--display); font-size: 25px; line-height: 1; text-transform: uppercase; } +.timeline-track p { margin: 0; color: var(--muted); font-size: 12px; } +.timeline-track .timeline-finish::before { background: var(--orange); box-shadow: 0 0 0 1px var(--orange); } +.timeline-finish h3, .timeline-finish time { color: var(--orange); } + +.contact { padding: 100px max(5vw, calc((100vw - 1320px)/2)); display: grid; grid-template-columns: 1.2fr 1fr; gap: 8vw; color: #fff; background: linear-gradient(125deg, var(--blue-dark), var(--blue)); } +.contact-copy p:last-child { max-width: 550px; color: #d7e4ff; } +.interest-form { display: grid; grid-template-columns: 1fr 1fr; gap: 17px; align-content: center; } +.interest-form label:nth-child(3) { grid-column: 1 / -1; } +.interest-form label span { display: block; margin-bottom: 6px; color: #b8ceff; font-size: 9px; font-weight: 900; text-transform: uppercase; letter-spacing: .12em; } +.interest-form input, .interest-form select { width: 100%; height: 49px; padding: 0 14px; border: 1px solid rgb(255 255 255 / 35%); border-radius: 0; color: #fff; background: rgb(0 0 0 / 15%); outline: none; } +.interest-form input:focus, .interest-form select:focus { border-color: #fff; } +.interest-form input::placeholder { color: #bdc9e5; } +.button-light { border-color: #fff; background: #fff; color: var(--blue); } +.button-light:hover { background: var(--orange); border-color: var(--orange); } +.form-status { margin: 0; align-self: center; color: #dbe6ff; font-size: 11px; } +.contact-direct { align-self: center; padding: 35px; border: 1px solid rgb(255 255 255 / 30%); background: rgb(0 0 0 / 12%); } +.contact-direct > p { margin: 0 0 22px; color: #d7e4ff; } +.contact-direct > div { display: flex; flex-wrap: wrap; gap: 9px; margin-bottom: 28px; } +.contact-direct > div span { padding: 7px 10px; border: 1px solid rgb(255 255 255 / 28%); color: #fff; text-transform: uppercase; font-size: 9px; font-weight: 850; letter-spacing: .05em; } + +footer { padding: 70px max(5vw, calc((100vw - 1320px)/2)) 30px; display: grid; grid-template-columns: 1.6fr 1fr .7fr; gap: 60px; color: #d4d6d9; background: var(--ink); font-size: 12px; } +.brand-footer { color: #fff; } +footer h4 { margin: 0 0 16px; color: #fff; text-transform: uppercase; letter-spacing: .1em; font-size: 10px; } +footer a, footer span { display: block; margin: 8px 0; } +.footer-contact { min-width: 0; } +.footer-contact .contact-row { display: flex; align-items: center; gap: 11px; margin: 10px 0; color: #d4d6d9; line-height: 1.35; } +.footer-contact a.contact-row:hover { color: #fff; } +.footer-contact .contact-row > span { margin: 0; } +.footer-contact .contact-icon { width: 27px; height: 27px; flex: 0 0 27px; display: grid; place-items: center; border: 1px solid #454b53; border-radius: 50%; color: #fff; } +.contact-icon svg { width: 15px; height: 15px; fill: none; stroke: currentColor; stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round; } +.contact-icon svg .solid { fill: currentColor; stroke: none; } +.footer-contact .instagram-icon { color: #fff; background: linear-gradient(140deg, #7258d5, #db3d84 55%, #f39b3d); border-color: transparent; } +.footer-contact .xhs-icon { width: 31px; height: 31px; flex-basis: 31px; border: 0; border-radius: 8px; color: #fff; background: #ff2442; font-size: 7px; font-weight: 900; } +.footer-contact .facebook-icon { border: 0; border-radius: 5px; color: #fff; background: #4267b2; font-family: Arial, sans-serif; font-size: 22px; font-weight: 900; } +.footer-contact .contact-address { align-items: flex-start; margin-top: 14px; color: #9da2aa; font-size: 10px; } +.footer-contact .contact-address .contact-icon { margin-top: 1px; } +.footer-note { grid-column: 1 / -1; margin: 25px 0 0; padding-top: 24px; border-top: 1px solid #34383e; color: #777d85; font-size: 10px; } + +.contact-modal { width: min(90vw, 540px); max-height: 78vh; padding: 24px 28px 20px; border: 0; border-radius: 16px; color: var(--ink); background: #fff; box-shadow: 0 24px 80px rgb(0 0 0 / 35%); overflow-y: auto; } +.contact-modal::backdrop { background: rgb(5 12 25 / 82%); backdrop-filter: blur(5px); } +.contact-modal .modal-close { position: absolute; right: 13px; top: 13px; width: 30px; height: 30px; border: 1px solid var(--line); border-radius: 50%; color: var(--ink); background: #fff; cursor: pointer; font-size: 18px; } +.contact-modal .eyebrow { margin-bottom: 7px; } +.contact-modal h2 { margin: 0; padding-right: 24px; font-size: clamp(32px, 3.2vw, 40px); line-height: .94; } +.contact-modal h2 em { color: var(--blue); font-style: normal; } +.modal-intro { max-width: 480px; margin: 9px 0 14px; color: var(--muted); font-size: 11px; } +.modal-contact-list { border-top: 1px solid var(--line); } +.modal-contact-row { min-height: 48px; display: grid; grid-template-columns: 29px minmax(0, 1fr) auto; align-items: center; gap: 9px; border-bottom: 1px solid var(--line); } +.modal-contact-row:last-child { border-bottom: 0; } +.modal-contact-icon { width: 24px; height: 24px; display: grid; place-items: center; border: 1px solid var(--line); border-radius: 50%; color: var(--blue); font-size: 10px; font-weight: 900; } +.modal-contact-icon.instagram-icon { color: #fff; border: 0; background: linear-gradient(140deg, #7258d5, #db3d84 55%, #f39b3d); } +.modal-contact-icon.xhs-icon { color: #fff; border: 0; border-radius: 7px; background: #ff2442; font-size: 7px; } +.modal-contact-icon.facebook-icon { color: #fff; border: 0; border-radius: 5px; background: #4267b2; font-family: Arial, sans-serif; font-size: 18px; } +.modal-contact-row small { display: block; color: var(--muted); text-transform: uppercase; letter-spacing: .09em; font-size: 8px; font-weight: 850; } +.modal-contact-row strong { display: block; margin-top: 1px; overflow-wrap: anywhere; font-size: 10.5px; } +.copy-contact { min-width: 54px; height: 27px; padding: 0 8px; border: 1px solid var(--blue); color: var(--blue); background: #fff; text-transform: uppercase; font-size: 8px; font-weight: 900; cursor: pointer; transition: .2s; } +.copy-contact:hover, .copy-contact.copied { color: #fff; background: var(--blue); } +.copy-status { min-height: 15px; margin: 10px 0 0; color: var(--blue); font-size: 10px; } +.lightbox { width: min(94vw, 1100px); padding: 0; border: 0; background: transparent; overflow: visible; } +.lightbox::backdrop { background: rgb(0 0 0 / 90%); } +.lightbox img { max-height: 84vh; object-fit: contain; } +.lightbox button { position: absolute; right: 0; top: -47px; width: 42px; height: 42px; border: 1px solid #fff; border-radius: 50%; color: #fff; background: transparent; font-size: 26px; cursor: pointer; } +.reveal { opacity: 0; transform: translateY(24px); transition: opacity .7s ease, transform .7s ease; } +.reveal.visible { opacity: 1; transform: none; } + +@media (max-width: 1050px) { + .nav { gap: 17px; } + .nav a { font-size: 9px; } + .site-header { padding-inline: 3vw; gap: 20px; } + .court-counts { grid-template-columns: repeat(3, 1fr); } + .count-note { display: none; } + .court-count:last-of-type { border-right: 0; } + .community-grid { grid-template-columns: 1fr 1fr; } + .timeline-track { grid-template-columns: 1fr 1fr; gap: 0 30px; } + .timeline-track::before { display: none; } + .timeline-track article { padding-top: 45px; border-top: 1px solid var(--line); } + .timeline-track article::before { top: -9px; } +} + +@media (max-width: 800px) { + .announcement { height: 28px; font-size: 8px; } + .site-header { height: 67px; padding: 0 20px; } + .menu-toggle { display: block; margin-left: auto; } + .header-actions { display: none; } + .nav { display: none; position: absolute; left: 0; top: 67px; width: 100%; padding: 25px 20px 30px; flex-direction: column; align-items: flex-start; gap: 18px; background: #fff; box-shadow: 0 16px 25px rgb(0 0 0 / 12%); } + .nav.open { display: flex; } + .nav a { font-size: 13px; } + .nav .language-mobile { display: block; color: var(--blue); font-size: 13px; } + .hero { min-height: 0; display: flex; flex-direction: column; background: #fff; } + .hero-copy { padding: 70px 22px 40px; } + .hero-lede { font-size: 16px; } + .hero-image { min-height: 420px; } + .hero-image::before { background: linear-gradient(180deg, #fff 0, transparent 20%); } + .hero-stamp { width: 92px; height: 92px; right: 18px; bottom: 18px; } + .court-counts { min-height: 0; grid-template-columns: 1fr; padding: 20px 22px; } + .court-count { height: 86px; padding: 0; border-right: 0; border-bottom: 1px solid var(--line); } + .section { padding: 80px 22px; } + .section-heading { display: block; } + .section-heading h2, .amenities h2, .booking-flow h2, .academy h2, .location h2, .contact h2 { font-size: 48px; } + .intro { grid-template-columns: 1fr; } + .venue-gallery { grid-template-columns: 1fr 1fr; grid-template-rows: 330px 180px; } + .gallery-main { grid-column: 1 / -1; grid-row: auto; } + .interior-intro { grid-template-columns: 1fr; gap: 18px; margin-top: 45px; } + .interior-gallery { grid-template-columns: 1fr; } + .interior-item { height: 260px; } + .sport-card { grid-template-columns: 1fr; } + .sport-card:nth-child(even) .sport-image { order: 0; } + .sport-content { padding: 38px 26px; } + .amenities, .location, .contact { grid-template-columns: 1fr; } + .amenities-image, .location-image { min-height: 420px; } + .amenities-content, .location-copy { padding: 70px 22px; } + .plan-layout { grid-template-columns: 1fr; gap: 25px; } + .plan-tabs { display: grid; grid-template-columns: 1fr 1fr; } + .plan-tab { grid-template-columns: 1fr; } + .plan-visual { padding: 12px; } + .plan-visual img { height: 65vw; } + .booking-flow { padding: 80px 22px; } + .booking-title { display: block; } + .steps { grid-template-columns: 1fr; margin-top: 40px; } + .steps li { min-height: 0; padding: 16px 0; flex-direction: row; border-left: 0; border-top: 1px solid rgb(255 255 255 / 30%); } + .steps span { font-size: 25px; } + .academy { padding: 80px 22px 0; grid-template-columns: 1fr; background: #fff; } + .academy-copy { padding: 0 0 65px; } + .coach-card { min-height: 520px; } + .coach-image { height: 520px; } + .academy-philosophy { margin-inline: -22px; grid-template-columns: 1fr 1fr; } + .community-grid { grid-template-columns: 1fr; } + .community-grid article { min-height: 220px; } + .community-grid h3 { margin-top: 35px; } + .timeline-track { grid-template-columns: 1fr; } + .timeline-track article { padding: 42px 0 35px; } + .contact { padding: 80px 22px; gap: 50px; } + .contact-direct { padding: 25px 20px; } + footer { grid-template-columns: 1fr 1fr; padding: 60px 22px 25px; gap: 40px; } + footer > div:first-child, .footer-note { grid-column: 1 / -1; } +} + +@media (max-width: 480px) { + h1 { font-size: 56px; } + .hero-actions .button { width: 100%; } + .hero-image { min-height: 330px; } + .venue-gallery { display: block; } + .gallery-item { height: 240px; margin-bottom: 8px; width: 100%; } + .interior-gallery { display: block; } + .amenity-list, .programmes, .interest-form { grid-template-columns: 1fr; } + .interest-form label:nth-child(3) { grid-column: auto; } + .plan-tabs { grid-template-columns: 1fr; } + .academy-philosophy { grid-template-columns: 1fr; } + .academy-philosophy span { border-bottom: 1px solid #34373c; } + .contact-modal { width: min(92vw, 380px); max-height: 86vh; padding: 24px 16px 20px; } + .contact-modal h2 { padding-right: 28px; font-size: 34px; } + .modal-contact-row { grid-template-columns: 34px minmax(0, 1fr) auto; gap: 9px; } + .copy-contact { min-width: 56px; padding-inline: 8px; } +} + +@media (prefers-reduced-motion: reduce) { + html { scroll-behavior: auto; } + *, *::before, *::after { animation: none !important; transition: none !important; } + .reveal { opacity: 1; transform: none; } + .hero-copy > *, .hero-image { opacity: 1; transform: none; } +}