Boutique Hotel Website HTML Template — Free Snippet
Boutique Hotel Website template · 11 website sections · Plain HTML, CSS & JS · Customise it in the Website Builder
What's included
Features
About this UI Snippet
A Boutique Hotel Website That Sells the Stay: Rooms, Experience and Direct Booking

Small hotels and B&Bs compete with booking platforms that take a commission, so the site's job is to make a direct booking feel better. The dusk hero sets the mood and states the essentials (location, price from, availability), and the rooms scroll sideways as the guest scrolls down, a horizontal gallery that gives each room space to be looked at, which a grid of thumbnails cannot.
The experience is told in stacking cards, one idea at a time (breakfast, the garden, the walks nearby), so guests picture the stay rather than comparing room specifications. Reviews from past guests, a FAQ on check-in, parking and pets, and a booking request form with a map complete the page, with a popup available for a seasonal offer such as "stay three nights, pay for two".
Use your own photography, because in hospitality the images are the product. It is the layout of the Boutique Hotel Website template, which also comes as a multi-page site with Rooms, Experience and Book pages; open it in the Website Builder to edit and export.
Built from website section templates
The 11 Sections Behind This Boutique Hotel Website Page
This page is not one big block of code: it is stacked from ready-made sections in the free Website Section Templates library, in this order. Open any of them to edit it on its own, or start with the whole page.
- Simple Sticky Navbara sticky bar with a Book direct button, the action that saves you the platform commission
- Image Background Heroa dusk photograph with the location, a "from" price and a booking button
- Horizontal Scroll Galleryrooms that scroll sideways as the guest scrolls down, giving each one room to be looked at
- Stacking Cardsthe experience told in stacking cards: breakfast, the garden, the walks nearby
- Filterable Image Gallerya filterable gallery by room, dining and surroundings
- Testimonial Carouselreviews from past guests, which a booking platform would normally keep for itself
- FAQ Accordioncheck-in times, parking, pets and cancellation, answered before the enquiry
- Booking Request Forma booking request form with dates, guests and room preference
- Contact With Mapa map with directions, nearest station and parking
- Popup & Promo Modala popup for a seasonal offer such as three nights for the price of two
- Minimal Footera minimal footer with contact details, registration and legal links
Step by step
How to Use
- 1Open the template in the Website BuilderPress "Start using this template" to open the Boutique Hotel Website in the Website Builder. Everything is edited with forms in a side panel; no code is needed.
- 2Describe each room honestly with real photosAdd one slide per room with its name, size, bed type and a "from" price, using your own photography taken in good light.
- 3Write the experience cards about the stay, not the buildingUse the stacking cards for moments a guest will remember (the breakfast, the view, the evening drink) rather than a list of facilities.
- 4Offer a reason to book directUse the popup and booking form to offer something a platform does not, such as a welcome drink, free late checkout or a best-rate guarantee.
- 5Export and publishDownload one HTML file or a ZIP (or one HTML file per page for the multi-page version) and upload it to Netlify, Vercel, Cloudflare Pages, GitHub Pages or your own host. Or copy the code from this page and export it to React, Vue, Angular or Tailwind with the buttons above the editor.
Real-world uses
Common Use Cases
Got questions?
Frequently Asked Questions
Rooms with photos and prices, what makes the stay special, reviews, practical answers, a way to book direct and a map.
The form sends booking requests to your email. For live availability, link the booking button to your property management or booking engine.
A horizontal gallery gives each room the full width of the screen, so photographs read bigger and guests look at each room properly.
It is assembled from 11 templates in the free Website Section Templates library: Simple Sticky Navbar, Image Background Hero, Horizontal Scroll Gallery, Stacking Cards, Filterable Image Gallery, Testimonial Carousel, FAQ Accordion, Booking Request Form, Contact With Map, Popup & Promo Modal, Minimal Footer. Each one has its own page where you can edit it separately.
It is the same page. Here you read and edit the HTML, CSS and JavaScript directly with a live preview; in the Website Builder you edit it with forms, change the theme once for the whole page, add pages and export a finished site.
Source Code
<section class="st st-navbar-simple" data-uid="smvnkxdctoexb">
<header class="st-wrap nb">
<a class="st-brand" href="#">
<span class="st-brand-mark"><span class="st-brand-icon"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M15 21v-8a1 1 0 0 0-1-1h-4a1 1 0 0 0-1 1v8" /><path d="M3 10a2 2 0 0 1 .709-1.528l7-5.999a2 2 0 0 1 2.582 0l7 5.999A2 2 0 0 1 21 10v9a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z" /></svg></span><span>Casa Mar</span></span>
</a>
<nav class="nb-nav" data-menu aria-label="Main">
<ul class="nb-links">
<li data-menu-item><a class="nb-link" href="#work"><span>Rooms</span></a></li>
<li data-menu-item><a class="nb-link" href="#highlights"><span>Experience</span></a></li>
<li data-menu-item><a class="nb-link" href="#customers"><span>Reviews</span></a></li>
<li data-menu-item><a class="nb-link" href="#contact"><span>Location</span></a></li>
</ul>
<div class="nb-actions" data-menu-item>
<a class="st-btn nb-cta" href="#contact"><span>Book a stay</span></a>
</div>
</nav>
<button type="button" class="st-burger" data-menu-toggle aria-expanded="false" aria-label="Open menu"><span></span><span></span><span></span></button>
</header>
<i hidden data-sticky-flag></i>
</section>
<section class="st st-image-background-hero" data-uid="smvnkxdct8swn">
<div class="ib-bg" role="img" aria-label="Background photo" style="background-image:url('https://webdevpuneet.com/images/section-templates/tpl-hotel.jpg')"></div>
<div class="ib-shade" aria-hidden="true"></div>
<div class="ib st-wrap">
<div class="ib-copy">
<span class="st-eyebrow ib-eyebrow" data-anim="item">Boutique hotel · Algarve coast</span>
<h1 class="ib-title" data-anim="item" data-anim-text>Slow mornings, <span class="hl">salt-water days</span></h1>
<p class="st-lead ib-lead" data-anim="item">Twenty-four rooms, a pool among the palms and the beach two minutes away. Breakfast is served until noon.</p>
<div class="st-btns" data-anim="item">
<a class="st-btn" href="#contact"><span>Book a stay</span></a>
<a class="st-btn st-btn--ghost ib-ghost" href="#work"><span>See the rooms</span></a>
</div>
</div>
<div class="ib-stats" data-anim="media">
<div><strong>24</strong><span>rooms and suites</span></div>
<div><strong>2 min</strong><span>to the beach</span></div>
<div><strong>9.4</strong><span>guest rating</span></div>
</div>
</div>
</section>
<section id="work" class="st st-scroll-gallery" data-uid="smvnkxdct01u7">
<div class="st-wrap hs-head">
<div class="hs-titles">
<p class="st-eyebrow" data-anim="item">Rooms & suites</p>
<h2 class="st-h2" data-anim="item" data-anim-text>Find <span class="hl">your room</span></h2>
</div>
<p class="st-lead hs-lead" data-anim="item">Every room has linen sheets, a rain shower and a balcony or garden terrace. Keep scrolling to see them all.</p>
</div>
<div class="hs-row" data-hscroll>
<a class="hs-card" href="#contact">
<img class="hs-img" width="900" height="1100" loading="lazy" src="https://webdevpuneet.com/images/section-templates/room-1.jpg" alt="Garden room with a double bed">
<span class="hs-tag">From €160 / night</span>
<span class="hs-title">Garden Room</span>
<span class="hs-text">A quiet double opening onto the orange grove.</span>
</a>
<a class="hs-card" href="#contact">
<img class="hs-img" width="900" height="1100" loading="lazy" src="https://webdevpuneet.com/images/section-templates/room-2.jpg" alt="Green-toned room with a large window">
<span class="hs-tag">From €190 / night</span>
<span class="hs-title">Palm Room</span>
<span class="hs-text">Big windows over the palms and the pool.</span>
</a>
<a class="hs-card" href="#contact">
<img class="hs-img" width="900" height="1100" loading="lazy" src="https://webdevpuneet.com/images/section-templates/room-3.jpg" alt="Dark suite with a sunset window">
<span class="hs-tag">From €260 / night</span>
<span class="hs-title">Sea View Suite</span>
<span class="hs-text">Sunsets over the bay from a private balcony.</span>
</a>
<a class="hs-card" href="#contact">
<img class="hs-img" width="900" height="1100" loading="lazy" src="https://webdevpuneet.com/images/section-templates/room-4.jpg" alt="Pink-toned loft room">
<span class="hs-tag">From €240 / night</span>
<span class="hs-title">Rose Loft</span>
<span class="hs-text">A split-level loft with a reading nook.</span>
</a>
</div>
</section>
<section id="highlights" class="st st-scroll-stack" data-uid="smvnkxdct4jgl">
<div class="st-art" aria-hidden="true" style="color:var(--st-brand);opacity:0.15" data-art-anim="float"><svg viewBox="0 0 1200 800" preserveAspectRatio="xMidYMid slice"><defs><radialGradient id="art-glow-smvnkxdct4jgl"><stop offset="0" stop-color="currentColor"/><stop offset="1" stop-color="currentColor" stop-opacity="0"/></radialGradient></defs><ellipse data-float cx="600" cy="80" rx="620" ry="380" fill="url(#art-glow-smvnkxdct4jgl)"/><ellipse data-float cx="1100" cy="760" rx="420" ry="300" fill="url(#art-glow-smvnkxdct4jgl)"/></svg></div>
<div class="st-wrap">
<header class="st-head">
<p class="st-eyebrow" data-anim="item">The experience</p>
<h2 class="st-h2" data-anim="item" data-anim-text>Everything for <span class="hl">a slow stay</span></h2>
<p class="st-lead" data-anim="item">Scroll on for the little things guests remember.</p>
</header>
<div class="sk-list" data-stack>
<article class="sk-card">
<div class="sk-inner">
<div class="sk-copy">
<span class="st-icon"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M10 2v2" /><path d="M14 2v2" /><path d="M16 8a1 1 0 0 1 1 1v8a4 4 0 0 1-4 4H7a4 4 0 0 1-4-4V9a1 1 0 0 1 1-1h14a4 4 0 1 1 0 8h-1" /><path d="M6 2v2" /></svg></span>
<span class="sk-label">Mornings</span>
<h3 class="sk-title">Breakfast until noon</h3>
<p class="sk-text">Fresh bread, fruit from the garden and eggs any way you like, served on the terrace.</p>
</div>
</div>
</article>
<article class="sk-card">
<div class="sk-inner">
<div class="sk-copy">
<span class="st-icon"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M9.937 15.5A2 2 0 0 0 8.5 14.063l-6.135-1.582a.5.5 0 0 1 0-.962L8.5 9.936A2 2 0 0 0 9.937 8.5l1.582-6.135a.5.5 0 0 1 .963 0L14.063 8.5A2 2 0 0 0 15.5 9.937l6.135 1.581a.5.5 0 0 1 0 .964L15.5 14.063a2 2 0 0 0-1.437 1.437l-1.582 6.135a.5.5 0 0 1-.963 0z" /><path d="M20 3v4" /><path d="M22 5h-4" /><path d="M4 17v2" /><path d="M5 18H3" /></svg></span>
<span class="sk-label">Afternoons</span>
<h3 class="sk-title">Pool, spa and shade</h3>
<p class="sk-text">A heated salt-water pool among the palms, a small spa and plenty of loungers.</p>
</div>
</div>
</article>
<article class="sk-card">
<div class="sk-inner">
<div class="sk-copy">
<span class="st-icon"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M20 10c0 4.993-5.539 10.193-7.399 11.799a1 1 0 0 1-1.202 0C9.539 20.193 4 14.993 4 10a8 8 0 0 1 16 0" /><circle cx="12" cy="10" r="3" /></svg></span>
<span class="sk-label">Days out</span>
<h3 class="sk-title">Coves, vineyards and boats</h3>
<p class="sk-text">We book boat trips, wine tastings and the best hidden beaches for you.</p>
</div>
</div>
</article>
<article class="sk-card">
<div class="sk-inner">
<div class="sk-copy">
<span class="st-icon"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M11.525 2.295a.53.53 0 0 1 .95 0l2.31 4.679a2.123 2.123 0 0 0 1.595 1.16l5.166.756a.53.53 0 0 1 .294.904l-3.736 3.638a2.123 2.123 0 0 0-.611 1.878l.882 5.14a.53.53 0 0 1-.771.56l-4.618-2.428a2.122 2.122 0 0 0-1.973 0L6.396 21.01a.53.53 0 0 1-.77-.56l.881-5.139a2.122 2.122 0 0 0-.611-1.879L2.16 9.795a.53.53 0 0 1 .294-.906l5.165-.755a2.122 2.122 0 0 0 1.597-1.16z" /></svg></span>
<span class="sk-label">Evenings</span>
<h3 class="sk-title">Dinner under the stars</h3>
<p class="sk-text">Grilled fish and local wine in the courtyard, three nights a week.</p>
</div>
</div>
</article>
</div>
</div>
</section>
<section id="gallery" class="st st-gallery-grid" data-uid="smvnkxdctgv3a">
<div class="st-wrap">
<header class="st-head">
<p class="st-eyebrow" data-anim="item">Gallery</p>
<h2 class="st-h2" data-anim="item" data-anim-text>A look around <span class="hl">Casa Mar</span></h2>
<p class="st-lead" data-anim="item">Rooms, the pool and the evenings on the terrace. Tap any photo to see it larger.</p>
</header>
<div class="gg-filters" data-gallery-filters role="group" aria-label="Filter photos" hidden data-all="All"></div>
<ul class="gg-grid" data-gallery>
<li class="gg-item" data-anim="item" data-tag="Rooms">
<img class="gg-img" width="1200" height="900" loading="lazy" src="https://webdevpuneet.com/images/section-templates/room-1.jpg" alt="A bright double room with tall windows">
<p class="gg-cap"><strong class="gg-title">Garden room</strong><span class="gg-text">Morning light and a quiet view</span></p>
</li>
<li class="gg-item" data-anim="item" data-tag="Outdoors">
<img class="gg-img" width="1200" height="900" loading="lazy" src="https://webdevpuneet.com/images/section-templates/tpl-hotel.jpg" alt="The hotel at dusk beside the pool">
<p class="gg-cap"><strong class="gg-title">The pool at dusk</strong><span class="gg-text">Open until ten every evening</span></p>
</li>
<li class="gg-item" data-anim="item" data-tag="Dining">
<img class="gg-img" width="1200" height="900" loading="lazy" src="https://webdevpuneet.com/images/section-templates/tpl-restaurant.jpg" alt="Plates of food on a wooden table">
<p class="gg-cap"><strong class="gg-title">Breakfast on the terrace</strong><span class="gg-text">Served from 8 until 11</span></p>
</li>
<li class="gg-item" data-anim="item" data-tag="Rooms">
<img class="gg-img" width="1200" height="900" loading="lazy" src="https://webdevpuneet.com/images/section-templates/room-3.jpg" alt="A dark suite with gold details">
<p class="gg-cap"><strong class="gg-title">Night suite</strong><span class="gg-text">Our largest room, with a terrace</span></p>
</li>
<li class="gg-item" data-anim="item" data-tag="Outdoors">
<img class="gg-img" width="1200" height="900" loading="lazy" src="https://webdevpuneet.com/images/section-templates/tpl-nature.jpg" alt="Green hills at sunrise">
<p class="gg-cap"><strong class="gg-title">The coast path</strong><span class="gg-text">Two minutes from the door</span></p>
</li>
<li class="gg-item" data-anim="item" data-tag="Dining">
<img class="gg-img" width="1200" height="900" loading="lazy" src="https://webdevpuneet.com/images/section-templates/wed-dinner.jpg" alt="A long table set with candles">
<p class="gg-cap"><strong class="gg-title">Dinner by candlelight</strong><span class="gg-text">Long tables on summer evenings</span></p>
</li>
</ul>
</div>
</section>
<section id="customers" class="st st-testimonials-carousel" data-uid="smvnkxdctg5nb">
<div class="st-wrap">
<div class="tc-top">
<header class="st-head st-head--left tc-head">
<p class="st-eyebrow" data-anim="item">Guest reviews</p>
<h2 class="st-h2" data-anim="item" data-anim-text>Guests <span class="hl">come back</span></h2>
<p class="st-lead" data-anim="item">9.4 from 820 verified reviews</p>
</header>
<div class="tc-arrows" data-anim="item">
<button type="button" class="tc-arrow" data-carousel-prev><span class="tc-sr">Previous testimonials</span><svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="m15 18-6-6 6-6"/></svg></button>
<button type="button" class="tc-arrow" data-carousel-next><span class="tc-sr">Next testimonials</span><svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="m9 18 6-6-6-6"/></svg></button>
</div>
</div>
<div class="tc-track" data-carousel tabindex="0" role="region" aria-label="Testimonials">
<figure class="tc-card" data-anim="item">
<p class="st-stars" role="img" aria-label="Rated 5 out of 5"><span aria-hidden="true">★★★★★</span></p>
<blockquote class="tc-quote"><p>The calmest week we have had in years. Breakfast on the terrace was the highlight of every day.</p></blockquote>
<figcaption><div class="st-person">
<img class="st-avatar" width="96" height="96" loading="lazy" src="https://webdevpuneet.com/images/section-templates/avatar-3.jpg" alt="">
<div><p class="st-person-name">Hannah & Tom</p><p class="st-person-role">Stayed in the Garden Room</p></div>
</div></figcaption>
</figure>
<figure class="tc-card" data-anim="item">
<p class="st-stars" role="img" aria-label="Rated 5 out of 5"><span aria-hidden="true">★★★★★</span></p>
<blockquote class="tc-quote"><p>Thoughtful, warm staff who booked us the perfect boat trip. The Sea View Suite is worth every euro.</p></blockquote>
<figcaption><div class="st-person">
<img class="st-avatar" width="96" height="96" loading="lazy" src="https://webdevpuneet.com/images/section-templates/avatar-4.jpg" alt="">
<div><p class="st-person-name">Rafael M.</p><p class="st-person-role">Stayed in the Sea View Suite</p></div>
</div></figcaption>
</figure>
<figure class="tc-card" data-anim="item">
<p class="st-stars" role="img" aria-label="Rated 5 out of 5"><span aria-hidden="true">★★★★★</span></p>
<blockquote class="tc-quote"><p>Small enough to feel personal, beautiful enough to never want to leave. Already planning our return.</p></blockquote>
<figcaption><div class="st-person">
<img class="st-avatar" width="96" height="96" loading="lazy" src="https://webdevpuneet.com/images/section-templates/avatar-2.jpg" alt="">
<div><p class="st-person-name">Elena K.</p><p class="st-person-role">Stayed in the Rose Loft</p></div>
</div></figcaption>
</figure>
</div>
</div>
</section>
<section id="faq" class="st st-faq-accordion" data-uid="smvnkxdct45su">
<div class="st-wrap">
<header class="st-head">
<p class="st-eyebrow" data-anim="item">FAQ</p>
<h2 class="st-h2" data-anim="item" data-anim-text>Before you <span class="hl">arrive</span></h2>
<p class="st-lead" data-anim="item">Check-in, breakfast, children and getting here from the airport.</p>
</header>
<div class="fq-list" data-accordion="single first">
<details class="st-acc" data-anim="item">
<summary class="st-acc-q"><span>What time is check-in?</span><span class="st-acc-icon" aria-hidden="true"></span></summary>
<div class="st-acc-a"><p>From 3 pm, and check-out is until 11 am. We store luggage before and after your stay.</p></div>
</details>
<details class="st-acc" data-anim="item">
<summary class="st-acc-q"><span>Is breakfast included?</span><span class="st-acc-icon" aria-hidden="true"></span></summary>
<div class="st-acc-a"><p>Yes, breakfast is included in every rate and served until noon.</p></div>
</details>
<details class="st-acc" data-anim="item">
<summary class="st-acc-q"><span>Do you allow children?</span><span class="st-acc-icon" aria-hidden="true"></span></summary>
<div class="st-acc-a"><p>Children over 12 are welcome; the hotel is designed as a quiet retreat.</p></div>
</details>
<details class="st-acc" data-anim="item">
<summary class="st-acc-q"><span>Can you arrange airport transfers?</span><span class="st-acc-icon" aria-hidden="true"></span></summary>
<div class="st-acc-a"><p>Yes. Faro airport is 45 minutes away and we can book a private transfer for you.</p></div>
</details>
</div>
</div>
</section>
<section id="contact" class="st st-booking-form" data-uid="smvnkxdct0dme">
<div class="st-wrap bk">
<div class="bk-info">
<header class="st-head st-head--left bk-head">
<p class="st-eyebrow" data-anim="item">Book a stay</p>
<h2 class="st-h2" data-anim="item" data-anim-text>Request <span class="hl">your stay</span></h2>
<p class="st-lead" data-anim="item">Tell us the room, the day you arrive and roughly when. We reply within a few hours with availability and the best rate.</p>
</header>
<div class="bk-block" data-anim="item">
<h3 class="bk-sub">Reception</h3>
<dl class="bk-hours">
<div class="bk-row"><dt>Reception</dt><dd>7:00 am – 11:00 pm</dd></div>
<div class="bk-row"><dt>Check-in</dt><dd>from 3:00 pm</dd></div>
<div class="bk-row"><dt>Check-out</dt><dd>until 11:00 am</dd></div>
</dl>
</div>
<div class="bk-block" data-anim="item">
<h3 class="bk-sub">Good to know</h3>
<ul class="st-checks"><li>Check-in from 3 pm, check-out until 11 am</li><li>Breakfast included in every rate</li><li>Free cancellation up to 7 days before arrival</li></ul>
</div>
</div>
<div class="bk-card" data-anim="media">
<form class="st-form" method="post" data-form action="https://formspree.io/f/your-form-id">
<div class="st-form-fields" data-form-fields>
<div class="st-form-row">
<label class="st-field"><span>Your name</span><input name="name" type="text" required autocomplete="name"></label>
<label class="st-field"><span>Email</span><input name="email" type="email" required autocomplete="email"></label>
</div>
<label class="st-field"><span>Phone</span><input name="phone" type="tel" autocomplete="tel"></label>
<label class="st-field"><span>Room</span><select name="service" required>
<option value="Garden room">Garden room</option>
<option value="Sea room">Sea room</option>
<option value="Night suite">Night suite</option>
<option value="Family suite">Family suite</option>
</select></label>
<div class="st-form-row">
<label class="st-field"><span>Arrival date</span><input name="date" type="date" required data-booking-date></label>
<label class="st-field"><span>Expected arrival</span><select name="time" required>
<option value="Before 2 pm">Before 2 pm</option>
<option value="Afternoon (2 pm – 6 pm)">Afternoon (2 pm – 6 pm)</option>
<option value="Evening (6 pm – 9 pm)">Evening (6 pm – 9 pm)</option>
<option value="Late (after 9 pm)">Late (after 9 pm)</option>
</select></label>
</div>
<label class="st-field"><span>Anything we should know?</span><textarea name="notes" rows="3"></textarea></label>
<input class="st-hp" type="text" name="_gotcha" tabindex="-1" autocomplete="off" aria-hidden="true">
<button class="st-btn st-form-btn" type="submit"><span>Request this stay</span></button>
<p class="st-form-note">This is a request, not a confirmed booking. We reply with availability.</p>
<p class="st-form-error" data-form-error hidden role="alert">Sorry, something went wrong. Please try again or call us directly.</p>
</div>
<div class="st-form-success" data-form-success hidden tabindex="-1" role="status">
<span class="st-icon"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M20 6 9 17l-5-5"/></svg></span>
<h3>Request received</h3>
<p>Thank you. We will email you availability and the rate shortly.</p>
</div>
</form>
</div>
</div>
</section>
<section id="contact-2" class="st st-contact-map" data-uid="smvnkxdcuz7vp">
<div class="st-wrap cm">
<div class="cm-info">
<header class="st-head st-head--left cm-head">
<p class="st-eyebrow" data-anim="item">Find us</p>
<h2 class="st-h2" data-anim="item" data-anim-text>Two minutes <span class="hl">from the sea</span></h2>
<p class="st-lead" data-anim="item">On a quiet lane above Praia da Luz, 45 minutes from Faro airport.</p>
</header>
<ul class="cm-offices">
<li class="cm-office" data-anim="item">
<h3 class="cm-city">Casa Mar</h3>
<address class="cm-address">Rua da Praia 12<br>8600-160 Luz, Algarve</address>
<p class="cm-hours">Reception 8am – 10pm</p>
<p class="cm-contact">
<a href="tel:+351282000123"><span>+351 282 000 123</span></a>
<a href="mailto:hello@webdevpuneet.com"><span>hello@webdevpuneet.com</span></a>
</p>
</li>
</ul>
</div>
<div class="cm-map" data-anim="media">
<iframe class="cm-frame" loading="lazy" referrerpolicy="no-referrer-when-downgrade" src="https://www.openstreetmap.org/export/embed.html?bbox=-0.1135%2C51.5185%2C-0.0955%2C51.5265&layer=mapnik&marker=51.5225%2C-0.1045" title="Map showing Casa Mar"></iframe>
</div>
</div>
</section>
<section class="st st-popup-modal" data-uid="smvnkxdcunsrb">
<div class="pu" data-pu data-trigger="delay" data-delay="15" data-scroll="50" data-days="7" data-pos="bottom-center" data-layout="left" data-autoplay="0" data-pu-id="ncmalq">
<div class="pu-backdrop" data-pu-close hidden></div>
<div class="pu-dialog" role="dialog" aria-modal="true" aria-labelledby="pu-heading" tabindex="-1" hidden>
<button type="button" class="pu-x" data-pu-close aria-label="Close popup"><svg viewBox="0 0 24 24" width="18" height="18" fill="none" stroke="currentColor" stroke-width="2.4" stroke-linecap="round" aria-hidden="true"><path d="M6 6l12 12M18 6 6 18"/></svg></button>
<div class="pu-media">
<img class="pu-img" loading="lazy" src="https://webdevpuneet.com/images/section-templates/tpl-hotel.jpg" alt="The terrace at Casa Mar">
</div>
<div class="pu-body">
<p class="st-eyebrow">Book direct</p>
<h2 class="pu-h" id="pu-heading">Save <span class="hl">10%</span> when you book direct</h2>
<p class="pu-lead">Best price guaranteed, free breakfast and a late checkout on stays of two nights or more.</p>
<div class="pu-ctas">
<a class="st-btn pu-cta" href="#contact"><span>Check dates</span></a>
</div>
<button type="button" class="pu-no" data-pu-close><span>No thanks</span></button>
</div>
</div>
</div>
</section>
<section class="st st-footer-minimal" data-uid="smvnkxdcuvwn7">
<footer class="st-wrap fm">
<div class="fm-row" data-anim="item">
<a class="st-brand" href="#">
<span class="st-brand-mark"><span class="st-brand-icon"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M15 21v-8a1 1 0 0 0-1-1h-4a1 1 0 0 0-1 1v8" /><path d="M3 10a2 2 0 0 1 .709-1.528l7-5.999a2 2 0 0 1 2.582 0l7 5.999A2 2 0 0 1 21 10v9a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z" /></svg></span><span>Casa Mar</span></span>
</a>
<nav aria-label="Footer"><ul class="fm-links"><li><a href="#work">Rooms</a></li><li><a href="#highlights">Experience</a></li><li><a href="#customers">Reviews</a></li><li><a href="#contact">Location</a></li></ul></nav>
<div><ul class="st-socials">
<li><a class="st-social" href="https://x.com/" aria-label="X (Twitter)"><span><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M22 4s-.7 2.1-2 3.4c1.6 10-9.4 17.3-18 11.6 2.2.1 4.4-.6 6-2C3 15.5.5 9.6 3 5c2.2 2.6 5.6 4.1 9 4-.9-4.2 4-6.6 7-3.8 1.1 0 3-1.2 3-1.2z" /></svg></span></a></li>
<li><a class="st-social" href="https://www.linkedin.com/" aria-label="LinkedIn"><span><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M16 8a6 6 0 0 1 6 6v7h-4v-7a2 2 0 0 0-2-2 2 2 0 0 0-2 2v7h-4v-7a6 6 0 0 1 6-6z" /><rect width="4" height="12" x="2" y="9" /><circle cx="4" cy="4" r="2" /></svg></span></a></li>
<li><a class="st-social" href="https://github.com/" aria-label="GitHub"><span><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M15 22v-4a4.8 4.8 0 0 0-1-3.5c3 0 6-2 6-5.5.08-1.25-.27-2.48-1-3.5.28-1.15.28-2.35 0-3.5 0 0-1 0-3 1.5-2.64-.5-5.36-.5-8 0C6 2 5 2 5 2c-.3 1.15-.3 2.35 0 3.5A5.403 5.403 0 0 0 4 9c0 3.5 3 5.5 6 5.5-.39.49-.68 1.05-.85 1.65-.17.6-.22 1.23-.15 1.85v4" /><path d="M9 18c-4.51 2-5-2-7-2" /></svg></span></a></li>
</ul></div>
</div>
<p class="fm-copy">© 2026 Casa Mar Boutique Hotel</p>
</footer>
</section>@import url('https://fonts.googleapis.com/css2?family=Playfair+Display:wght@400;500;600;700;800;900&family=DM+Sans:wght@400;500;600;700;800;900&display=swap');
body{margin:0;background:#fbf8f3}
html{scroll-behavior:smooth}section[id]{scroll-margin-top:84px}
@media (prefers-reduced-motion:reduce){html{scroll-behavior:auto}}
.st{--st-brand:#0f766e;--st-btn-text:#ffffff;--st-bg:#fbf8f3;--st-surface:#f1ebe1;--st-text:#1f2a24;--st-muted:#5c665f;--st-radius:14;--st-max:1200;--st-font-heading:"Playfair Display", serif;--st-font-body:"DM Sans", sans-serif}
.st{--st-pad:clamp(20px,5cqi,56px);container:st/inline-size;position:relative;overflow:hidden;background:var(--st-bg);color:var(--st-text);font-family:var(--st-font-body);font-size:17px;line-height:1.6;-webkit-font-smoothing:antialiased}
:where(.st) *,:where(.st) *::before,:where(.st) *::after{box-sizing:border-box;margin:0;padding:0}
:where(.st img){display:block;max-width:100%;height:auto}
:where(.st a){color:inherit}
:where(.st h1,.st h2,.st h3){font-family:var(--st-font-heading);line-height:1.08;letter-spacing:-.025em;font-weight:800;color:var(--st-text)}
.st .hl{color:var(--st-brand)}
.st [data-edit]:empty,.st [data-i-edit]:empty{display:none}
.st-wrap{width:100%;max-width:calc(var(--st-max) * 1px);margin:0 auto;padding-left:var(--st-pad);padding-right:var(--st-pad)}
.st-eyebrow{display:inline-flex;align-items:center;gap:8px;font-size:13px;font-weight:700;letter-spacing:.12em;text-transform:uppercase;color:var(--st-brand)}
.st-pill{display:inline-flex;align-items:center;gap:8px;padding:6px 14px;border-radius:999px;background:color-mix(in srgb,var(--st-brand) 12%,transparent);color:var(--st-brand);font-size:13.5px;font-weight:700}
.st-btns{display:flex;flex-wrap:wrap;gap:12px}
.st-btn{display:inline-flex;align-items:center;justify-content:center;gap:8px;min-height:50px;padding:0 26px;border-radius:calc(var(--st-radius) * 1px);border:2px solid var(--st-brand);background:var(--st-brand);color:var(--st-btn-text);font:700 16px/1 var(--st-font-body);text-decoration:none;transition:transform .15s ease,box-shadow .15s ease,background .15s ease}
.st-btn:hover{transform:translateY(-1px);box-shadow:0 8px 24px color-mix(in srgb,var(--st-brand) 35%,transparent)}
.st-btn:focus-visible{outline:3px solid color-mix(in srgb,var(--st-brand) 45%,transparent);outline-offset:3px}
.st-btn--ghost{background:transparent;color:var(--st-text);border-color:color-mix(in srgb,var(--st-text) 22%,transparent)}
.st-btn--ghost:hover{box-shadow:none;border-color:var(--st-text)}
.st-lead{font-size:clamp(17px,1.2cqi + 12px,20px);line-height:1.65;color:var(--st-muted)}
.st-head{display:flex;flex-direction:column;align-items:center;gap:14px;max-width:46em;margin:0 auto clamp(36px,5cqi,64px);text-align:center}
.st-head--left{align-items:flex-start;margin-left:0;text-align:left}
.st-h2{font-size:clamp(30px,2.6cqi + 16px,48px)}
.st-icon{display:inline-grid;place-items:center;flex:none;width:48px;height:48px;border-radius:calc(var(--st-radius) * .85px);background:color-mix(in srgb,var(--st-brand) 12%,transparent);color:var(--st-brand)}
.st-icon svg{width:24px;height:24px}
.st-icon:empty{display:none}
.st-checks{list-style:none;display:flex;flex-direction:column;gap:11px}
.st-checks li{position:relative;padding-left:30px;font-size:15.5px;line-height:1.5}
.st-checks li::before{content:"";position:absolute;left:0;top:.12em;width:20px;height:20px;border-radius:50%;background:color-mix(in srgb,var(--st-brand) 15%,transparent)}
.st-checks li::after{content:"";position:absolute;left:5px;top:calc(.12em + 5px);width:10px;height:10px;background:var(--st-brand);-webkit-mask:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='3.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M20 6 9 17l-5-5'/%3E%3C/svg%3E") center/contain no-repeat;mask:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='3.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M20 6 9 17l-5-5'/%3E%3C/svg%3E") center/contain no-repeat}
@media (prefers-reduced-motion:reduce){.st *{transition:none!important;animation:none!important}}
/* Simple Sticky Navbar */
.st-navbar-simple{overflow:visible;background:color-mix(in srgb,var(--st-bg) 88%,transparent);-webkit-backdrop-filter:saturate(1.6) blur(14px);backdrop-filter:saturate(1.6) blur(14px);border-bottom:1px solid color-mix(in srgb,var(--st-text) 8%,transparent)}
.st-brand{display:inline-flex;align-items:center;gap:10px;flex:none;text-decoration:none;color:var(--st-text)}
.st-brand-img{height:32px;width:auto;max-width:180px;object-fit:contain}
.st-brand-mark{display:inline-flex;align-items:center;gap:10px;font:800 21px/1 var(--st-font-heading);letter-spacing:-.03em}
.st-brand-icon{display:grid;place-items:center;width:34px;height:34px;border-radius:calc(var(--st-radius) * .7px);background:var(--st-brand);color:var(--st-btn-text)}
.st-brand-icon svg{width:19px;height:19px}
.st:has([data-sticky-flag]){position:sticky;top:0;z-index:50;transition:box-shadow .3s ease}
.st.is-scrolled{box-shadow:0 10px 30px -18px rgba(15,23,42,.35)}
.st-burger{display:none;position:relative;flex:none;width:44px;height:44px;border:0;border-radius:calc(var(--st-radius) * .7px);background:color-mix(in srgb,var(--st-text) 7%,transparent);color:var(--st-text);cursor:pointer}
.st-burger span{position:absolute;left:12px;right:12px;height:2px;border-radius:2px;background:currentColor;transition:transform .3s ease,opacity .2s ease}
.st-burger span:nth-child(1){top:15px}.st-burger span:nth-child(2){top:21px}.st-burger span:nth-child(3){top:27px}
.st-burger[aria-expanded="true"] span:nth-child(1){transform:translateY(6px) rotate(45deg)}
.st-burger[aria-expanded="true"] span:nth-child(2){opacity:0}
.st-burger[aria-expanded="true"] span:nth-child(3){transform:translateY(-6px) rotate(-45deg)}
.st-burger:focus-visible{outline:3px solid color-mix(in srgb,var(--st-brand) 45%,transparent);outline-offset:2px}
.nb{position:relative;display:flex;align-items:center;gap:clamp(20px,3cqi,40px);min-height:72px}
.nb-nav{flex:1;display:flex;align-items:center;justify-content:space-between;gap:24px}
.nb-links{list-style:none;display:flex;align-items:center;gap:4px;margin:0 auto}
.nb-link{display:block;padding:8px 14px;border-radius:calc(var(--st-radius) * .7px);color:var(--st-muted);font-weight:600;font-size:15.5px;text-decoration:none;transition:color .2s ease,background .2s ease}
.nb-link:hover{color:var(--st-text);background:color-mix(in srgb,var(--st-text) 6%,transparent)}
.nb-link[aria-current="page"]{color:var(--st-brand);background:color-mix(in srgb,var(--st-brand) 11%,transparent)}
.nb-actions{display:flex;align-items:center;gap:18px}
.nb-login{color:var(--st-text);font-weight:600;font-size:15.5px;text-decoration:none}
.nb-login:hover{color:var(--st-brand)}
.nb .nb-cta{min-height:44px;padding:0 20px;font-size:15px}
@container st (max-width:900px){
.nb .st-burger{display:inline-block;margin-left:auto}
.nb-nav{position:absolute;left:var(--st-pad);right:var(--st-pad);top:calc(100% + 8px);flex-direction:column;align-items:stretch;gap:8px;padding:10px;border-radius:calc(var(--st-radius) * 1.2px);background:var(--st-bg);border:1px solid color-mix(in srgb,var(--st-text) 9%,transparent);box-shadow:0 24px 60px -24px rgba(15,23,42,.35)}
.nb-links{flex-direction:column;align-items:stretch;gap:2px;margin:0}
.nb-link{padding:12px 14px;font-size:16.5px;color:var(--st-text)}
.nb-actions{flex-direction:column;align-items:stretch;gap:10px;padding:12px 4px 4px;border-top:1px solid color-mix(in srgb,var(--st-text) 8%,transparent)}
.nb-login{padding:8px 10px}
.nb .nb-cta{width:100%;min-height:48px}
.has-menu:not(.menu-open) .nb-nav{display:none}
.st:not(.has-menu) .nb{flex-wrap:wrap;padding-top:12px;padding-bottom:12px}
.st:not(.has-menu) .nb-nav{position:static;flex-basis:100%;box-shadow:none}
.st:not(.has-menu) .st-burger{display:none}
}
/* Image Background Hero */
.st-image-background-hero{min-height:min(88vh,760px);display:flex;align-items:stretch;background:var(--st-bg)}
.ib-bg{position:absolute;inset:0;background-size:cover;background-position:center}
.ib-shade{position:absolute;inset:0;background:linear-gradient(90deg,color-mix(in srgb,var(--st-bg) 88%,transparent) 0%,color-mix(in srgb,var(--st-bg) 55%,transparent) 55%,color-mix(in srgb,var(--st-bg) 15%,transparent) 100%),linear-gradient(0deg,color-mix(in srgb,var(--st-bg) 70%,transparent),transparent 45%)}
.ib{position:relative;display:flex;flex-direction:column;justify-content:space-between;gap:48px;padding-top:clamp(72px,10cqi,140px);padding-bottom:clamp(32px,4cqi,48px)}
.ib-copy{display:flex;flex-direction:column;align-items:flex-start;gap:22px;max-width:640px}
.ib-eyebrow{color:var(--st-brand)}
.ib-title{font-size:clamp(42px,5.6cqi + 10px,80px);line-height:1.02}
.ib-lead{color:var(--st-muted);max-width:32em}
.ib-ghost{color:var(--st-text);border-color:color-mix(in srgb,var(--st-text) 55%,transparent);backdrop-filter:blur(6px)}
.ib-stats{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:16px;padding-top:24px;border-top:1px solid color-mix(in srgb,var(--st-text) 22%,transparent)}
.ib-stats div{display:flex;flex-direction:column;gap:2px}
.ib-stats strong{font-family:var(--st-font-heading);font-size:clamp(26px,2.6cqi + 8px,38px);line-height:1.1;color:var(--st-text)}
.ib-stats span{font-size:14px;color:var(--st-muted)}
@container st (max-width:640px){.ib-stats{grid-template-columns:1fr}.ib-shade{background:color-mix(in srgb,var(--st-bg) 72%,transparent)}}
/* Horizontal Scroll Gallery */
.st-scroll-gallery{padding:clamp(64px,8cqi,112px) 0}
.hs-head{display:flex;align-items:flex-end;justify-content:space-between;gap:24px 48px;margin-bottom:clamp(28px,4cqi,48px)}
.hs-titles{display:flex;flex-direction:column;gap:12px;max-width:40em}
.hs-lead{max-width:28em}
.hs-row{display:flex;gap:clamp(16px,2cqi,28px);overflow-x:auto;scroll-snap-type:x mandatory;--hs-in:max(var(--st-pad),calc((100% - var(--st-max) * 1px) / 2 + var(--st-pad)));padding:4px var(--hs-in) 18px;scroll-padding-inline:var(--hs-in);scrollbar-width:thin}
.st-scroll-gallery.is-hscroll .hs-row{overflow:visible;scroll-snap-type:none}
.hs-card{flex:none;width:clamp(240px,28cqi,380px);scroll-snap-align:start;display:flex;flex-direction:column;gap:6px;color:inherit;text-decoration:none}
.hs-img{width:100%;aspect-ratio:4/5;object-fit:cover;margin-bottom:10px;border-radius:calc(var(--st-radius) * 1px);background:var(--st-surface);transition:transform .5s cubic-bezier(.2,.7,.2,1)}
.hs-card:hover .hs-img{transform:translateY(-6px)}
.hs-card:focus-visible{outline:3px solid color-mix(in srgb,var(--st-brand) 50%,transparent);outline-offset:6px;border-radius:calc(var(--st-radius) * 1px)}
.hs-tag{font-size:12px;font-weight:700;letter-spacing:.12em;text-transform:uppercase;color:var(--st-brand)}
.hs-title{font:700 clamp(19px,.8cqi + 14px,22px)/1.25 var(--st-font-heading)}
.hs-text{color:var(--st-muted);font-size:15px;line-height:1.5}
@container st (max-width:720px){.hs-head{flex-direction:column;align-items:flex-start}}
/* Stacking Cards */
.st-scroll-stack{padding:clamp(64px,8cqi,112px) 0}
.sk-list{display:flex;flex-direction:column;gap:clamp(20px,3cqi,32px);max-width:1040px;margin:0 auto}
.sk-inner{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1.1fr);gap:clamp(20px,3cqi,44px);align-items:center;min-height:min(62vh,500px);padding:clamp(24px,3.5cqi,52px);border-radius:calc(var(--st-radius) * 1.3px);background:var(--st-surface);border:1px solid color-mix(in srgb,var(--st-text) 9%,transparent);box-shadow:0 40px 70px -48px rgba(0,0,0,.45);transform-origin:50% 0}
.sk-card:nth-child(3n+2) .sk-inner{background:color-mix(in srgb,var(--st-brand) 9%,var(--st-surface))}
.sk-card:nth-child(3n) .sk-inner{background:color-mix(in srgb,var(--st-text) 92%,var(--st-brand));color:var(--st-bg)}
.sk-card:nth-child(3n) .sk-title{color:var(--st-bg)}
.sk-card:nth-child(3n) .sk-text{color:color-mix(in srgb,var(--st-bg) 72%,transparent)}
.sk-copy{display:flex;flex-direction:column;align-items:flex-start;gap:10px}
.sk-label{font-size:13px;font-weight:800;letter-spacing:.1em;text-transform:uppercase;color:var(--st-brand)}
.sk-title{font-size:clamp(24px,1.6cqi + 14px,36px);line-height:1.1}
.sk-text{color:var(--st-muted);font-size:17px;max-width:30em}
.sk-img{width:100%;aspect-ratio:4/3;object-fit:cover;border-radius:calc(var(--st-radius) * .8px);background:color-mix(in srgb,var(--st-text) 6%,transparent)}
.sk-inner:not(:has(.sk-img)){grid-template-columns:1fr;min-height:0}
@container st (max-width:760px){.sk-inner{grid-template-columns:1fr;min-height:0}}
/* Filterable Image Gallery */
.st-gallery-grid{padding:clamp(56px,7cqi,104px) 0}
.gg-filters{display:flex;flex-wrap:wrap;justify-content:center;gap:8px;margin-bottom:clamp(24px,3cqi,36px)}
.gg-filters:empty{display:none}
.gg-chip{min-height:40px;padding:0 18px;border:1px solid color-mix(in srgb,var(--st-text) 14%,transparent);border-radius:999px;background:transparent;color:var(--st-text);font:600 14.5px/1 var(--st-font-body);cursor:pointer;transition:background .2s ease,color .2s ease,border-color .2s ease}
.gg-chip:hover{border-color:var(--st-brand);color:var(--st-brand)}
.gg-chip[aria-pressed="true"]{background:var(--st-brand);border-color:var(--st-brand);color:var(--st-btn-text)}
.gg-chip:focus-visible{outline:3px solid color-mix(in srgb,var(--st-brand) 45%,transparent);outline-offset:2px}
.gg-grid{list-style:none;display:grid;grid-template-columns:repeat(auto-fill,minmax(min(100%,260px),1fr));gap:clamp(12px,1.6cqi,20px)}
.gg-item{position:relative;overflow:hidden;border-radius:calc(var(--st-radius) * 1px);background:var(--st-surface);aspect-ratio:4/3}
.gg-item[hidden]{display:none}
.gg-item[role="button"]{cursor:zoom-in}
.gg-item:focus-visible{outline:3px solid var(--st-brand);outline-offset:3px}
.gg-img{width:100%;height:100%;object-fit:cover;transition:transform .7s cubic-bezier(.2,.8,.2,1)}
.gg-item:hover .gg-img{transform:scale(1.07)}
.gg-cap{position:absolute;inset:auto 0 0;display:flex;flex-direction:column;gap:2px;padding:44px 16px 14px;color:#fff;background:linear-gradient(to top,rgba(10,12,20,.78),transparent);opacity:0;transform:translateY(8px);transition:opacity .3s ease,transform .3s ease}
.gg-item:hover .gg-cap,.gg-item:focus-visible .gg-cap{opacity:1;transform:none}
.gg-title{font-size:16px;line-height:1.3}
.gg-text{font-size:13.5px;opacity:.85}
@media (hover:none){.gg-cap{opacity:1;transform:none}}
.stg-lb{position:fixed;inset:0;z-index:9999;display:flex;align-items:center;justify-content:center;padding:clamp(16px,4vw,48px);background:rgba(8,10,16,.92);animation:stg-fade .2s ease}
.stg-lb[hidden]{display:none}
.stg-lb-fig{display:flex;flex-direction:column;align-items:center;gap:14px;max-width:min(1100px,100%);max-height:100%;margin:0}
.stg-lb-img{display:block;max-width:100%;max-height:calc(var(--lb-h,100vh) - 150px);border-radius:10px;object-fit:contain;background:#111}
.stg-lb-cap{color:#e5e7eb;font:500 15px/1.5 system-ui,sans-serif;text-align:center}
.stg-lb-cap:empty{display:none}
.stg-lb-close,.stg-lb-nav{position:absolute;display:grid;place-items:center;width:48px;height:48px;border:0;border-radius:50%;background:rgba(255,255,255,.12);color:#fff;font:400 30px/1 system-ui,sans-serif;cursor:pointer;transition:background .2s ease}
.stg-lb-close svg,.stg-lb-nav svg{display:block;width:22px;height:22px;pointer-events:none}
.stg-lb-close:hover,.stg-lb-nav:hover{background:rgba(255,255,255,.24)}
.stg-lb-close:focus-visible,.stg-lb-nav:focus-visible{outline:3px solid #fff;outline-offset:2px}
.stg-lb-close{top:16px;right:16px}
.stg-lb-prev{left:16px;top:50%;margin-top:-24px}
.stg-lb-next{right:16px;top:50%;margin-top:-24px}
.stg-lb.is-single .stg-lb-nav{display:none}
.stg-lb-count{position:absolute;bottom:14px;left:0;right:0;margin:0;color:#9ca3af;font:500 13px/1 system-ui,sans-serif;text-align:center}
html.stg-open{overflow:hidden}
@keyframes stg-fade{from{opacity:0}to{opacity:1}}
@media (prefers-reduced-motion:reduce){.stg-lb{animation:none}.gg-img,.gg-cap{transition:none}}
@container st (max-width:520px){.gg-grid{grid-template-columns:1fr 1fr}.gg-cap{display:none}}
/* Testimonial Carousel */
.st-testimonials-carousel{padding:clamp(64px,8cqi,112px) 0}
.st-stars{color:#f59e0b;font-size:16px;letter-spacing:2px;line-height:1}
.st-person{display:flex;align-items:center;gap:12px}
.st-avatar{width:44px;height:44px;flex:none;border-radius:50%;object-fit:cover;background:var(--st-surface)}
.st-person-name{font-weight:700;font-size:15.5px;line-height:1.3}
.st-person-role{color:var(--st-muted);font-size:14px;line-height:1.4}
.st-person-role:empty{display:none}
.tc-top{display:flex;align-items:flex-end;justify-content:space-between;gap:24px;margin-bottom:clamp(28px,3.4cqi,44px)}
.tc-head{margin:0}
.tc-arrows{display:flex;gap:10px;flex:none}
.tc-arrow{position:relative;display:grid;place-items:center;width:48px;height:48px;border-radius:50%;border:1px solid color-mix(in srgb,var(--st-text) 16%,transparent);background:var(--st-bg);color:var(--st-text);cursor:pointer;transition:background .2s ease,color .2s ease,opacity .2s ease}
.tc-arrow:hover:not(:disabled){background:var(--st-brand);border-color:var(--st-brand);color:var(--st-btn-text)}
.tc-arrow:disabled{opacity:.35;cursor:default}
.tc-arrow:focus-visible,.tc-track:focus-visible{outline:3px solid color-mix(in srgb,var(--st-brand) 45%,transparent);outline-offset:3px}
.tc-sr{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap}
.tc-track{display:flex;gap:clamp(14px,1.8cqi,22px);overflow-x:auto;scroll-snap-type:x mandatory;scrollbar-width:none;padding:4px 2px 16px;margin:0 -2px;overscroll-behavior-x:contain}
.tc-track::-webkit-scrollbar{display:none}
.tc-track.is-draggable{scroll-snap-type:none;cursor:grab}
.tc-track.is-draggable:active{cursor:grabbing}
.tc-card{flex:0 0 clamp(280px,32%,400px);scroll-snap-align:start;display:flex;flex-direction:column;gap:16px;margin:0;padding:clamp(24px,2.6cqi,32px);border-radius:calc(var(--st-radius) * 1px);background:var(--st-surface);user-select:none}
.tc-quote{flex:1;font-size:17px;line-height:1.65}
@container st (max-width:700px){.tc-top{flex-direction:column;align-items:flex-start}.tc-card{flex-basis:85%}}
/* FAQ Accordion */
.st-faq-accordion{padding:clamp(64px,8cqi,112px) 0}
.st-acc{border-bottom:1px solid color-mix(in srgb,var(--st-text) 11%,transparent)}
.st-acc-q{display:flex;align-items:center;justify-content:space-between;gap:20px;padding:22px 2px;cursor:pointer;list-style:none;font:700 clamp(17px,.6cqi + 14px,19px)/1.4 var(--st-font-heading);letter-spacing:-.01em}
.st-acc-q::-webkit-details-marker{display:none}
.st-acc-q:hover{color:var(--st-brand)}
.st-acc-q:focus-visible{outline:3px solid color-mix(in srgb,var(--st-brand) 45%,transparent);outline-offset:2px;border-radius:6px}
.st-acc-icon{position:relative;flex:none;width:28px;height:28px;border-radius:50%;background:color-mix(in srgb,var(--st-brand) 11%,transparent);transition:transform .3s ease,background .3s ease}
.st-acc-icon::before,.st-acc-icon::after{content:"";position:absolute;left:50%;top:50%;width:12px;height:2px;border-radius:2px;background:var(--st-brand);transform:translate(-50%,-50%)}
.st-acc-icon::after{transform:translate(-50%,-50%) rotate(90deg);transition:transform .3s ease}
.st-acc[open]:not(.is-closing) .st-acc-icon{transform:rotate(180deg);background:var(--st-brand)}
.st-acc[open]:not(.is-closing) .st-acc-icon::before,.st-acc[open]:not(.is-closing) .st-acc-icon::after{background:var(--st-btn-text)}
.st-acc[open]:not(.is-closing) .st-acc-icon::after{transform:translate(-50%,-50%) rotate(0deg)}
.st-acc-a{overflow:hidden}
.st-acc-a p{padding:0 48px 24px 2px;color:var(--st-muted);font-size:16.5px;line-height:1.7}
.fq-list{max-width:820px;margin:0 auto;border-top:1px solid color-mix(in srgb,var(--st-text) 11%,transparent)}
.fq-contact{max-width:820px;margin:clamp(32px,4cqi,48px) auto 0;padding:20px 24px;border-radius:calc(var(--st-radius) * 1px);background:var(--st-surface);text-align:center;color:var(--st-muted)}
.fq-contact a{color:var(--st-brand);font-weight:700;text-decoration:none}
.fq-contact a:hover{text-decoration:underline}
/* Booking Request Form */
.st-booking-form{padding:clamp(64px,8cqi,112px) 0}
.st-form{display:block}
.st-form-fields{display:flex;flex-direction:column;gap:16px}
.st-form-row{display:grid;grid-template-columns:1fr 1fr;gap:16px}
.st-field{display:flex;flex-direction:column;gap:7px;font-size:14.5px;font-weight:600;color:var(--st-text)}
.st-field input,.st-field textarea{width:100%;padding:13px 15px;border-radius:calc(var(--st-radius) * .8px);border:1px solid color-mix(in srgb,var(--st-text) 16%,transparent);background:var(--st-bg);color:var(--st-text);font:400 16px/1.5 var(--st-font-body);outline:none;transition:border-color .2s ease,box-shadow .2s ease;resize:vertical}
.st-field input:focus,.st-field textarea:focus{border-color:var(--st-brand);box-shadow:0 0 0 4px color-mix(in srgb,var(--st-brand) 18%,transparent)}
.st-hp{position:absolute;left:-9999px;width:1px;height:1px;opacity:0}
.st-form-btn{align-self:flex-start;min-width:180px}
.st-form-btn[aria-busy="true"]{opacity:.7;cursor:progress}
.st-form-note{font-size:13.5px;color:var(--st-muted)}
.st-form-error{padding:12px 14px;border-radius:calc(var(--st-radius) * .8px);background:#fef2f2;color:#b91c1c;font-size:14.5px}
.st-form-success{display:flex;flex-direction:column;align-items:flex-start;gap:10px;padding:8px 0;outline:none}
.st-form-success[hidden],.st-form-error[hidden]{display:none}
.st-form-success h3{font-size:22px}
.st-form-success p{color:var(--st-muted)}
@container st (max-width:560px){.st-form-row{grid-template-columns:1fr}.st-form-btn{width:100%}}
.st-field select{width:100%;padding:13px 44px 13px 15px;-webkit-appearance:none;appearance:none;background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%2364748b' stroke-width='2.4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");background-repeat:no-repeat;background-position:right 16px center;background-size:16px;cursor:pointer;border-radius:calc(var(--st-radius) * .8px);border:1px solid color-mix(in srgb,var(--st-text) 16%,transparent);background-color:var(--st-bg);color:var(--st-text);font:400 16px/1.5 var(--st-font-body);outline:none;transition:border-color .2s ease,box-shadow .2s ease}
.st-field select:focus,.st-field input[type="date"]:focus{border-color:var(--st-brand);box-shadow:0 0 0 4px color-mix(in srgb,var(--st-brand) 18%,transparent)}
.st-field input[type="date"]{min-height:51px}
.bk{display:grid;grid-template-columns:minmax(0,.85fr) minmax(0,1.15fr);align-items:start;gap:clamp(36px,5cqi,80px)}
.bk-info{display:flex;flex-direction:column;gap:30px}
.bk-head{margin:0}
.bk-sub{margin-bottom:12px;font-size:17px;letter-spacing:-.01em}
.bk-hours{display:flex;flex-direction:column;border-top:1px solid color-mix(in srgb,var(--st-text) 10%,transparent)}
.bk-row{display:flex;justify-content:space-between;gap:16px;padding:11px 0;border-bottom:1px solid color-mix(in srgb,var(--st-text) 10%,transparent);font-size:15.5px}
.bk-row dt{font-weight:600}
.bk-row dd{color:var(--st-muted);font-variant-numeric:tabular-nums}
.bk-card{padding:clamp(24px,3.4cqi,40px);border-radius:calc(var(--st-radius) * 1.3px);background:var(--st-surface);border:1px solid color-mix(in srgb,var(--st-text) 7%,transparent);box-shadow:0 30px 70px -40px color-mix(in srgb,var(--st-text) 45%,transparent)}
@container st (max-width:860px){.bk{grid-template-columns:1fr}}
/* Contact With Map */
.st-contact-map{padding:clamp(64px,8cqi,112px) 0}
.cm{display:grid;grid-template-columns:minmax(0,.9fr) minmax(0,1.1fr);align-items:stretch;gap:clamp(32px,5cqi,72px)}
.cm-info{display:flex;flex-direction:column;gap:32px}
.cm-head{margin:0}
.cm-offices{list-style:none;display:grid;grid-template-columns:repeat(auto-fit,minmax(220px,1fr));gap:24px}
.cm-office{display:flex;flex-direction:column;gap:6px;padding:22px;border-radius:calc(var(--st-radius) * 1px);background:var(--st-surface)}
.cm-city{font-size:18px;margin-bottom:4px}
.cm-address{font-style:normal;color:var(--st-muted);font-size:15.5px;line-height:1.6}
.cm-hours{color:var(--st-text);font-size:14.5px;font-weight:600;margin-top:4px}
.cm-contact{display:flex;flex-direction:column;gap:2px;margin-top:6px}
.cm-contact a{color:var(--st-brand);font-weight:600;font-size:15px;text-decoration:none;word-break:break-word}
.cm-contact a:hover{text-decoration:underline}
.cm-map{min-height:420px;overflow:hidden;border-radius:calc(var(--st-radius) * 1.2px);background:var(--st-surface);border:1px solid color-mix(in srgb,var(--st-text) 9%,transparent);box-shadow:0 30px 70px -40px rgba(28,25,23,.45)}
.cm-frame{display:block;width:100%;height:100%;min-height:420px;border:0}
@container st (max-width:860px){.cm{grid-template-columns:1fr}.cm-map,.cm-frame{min-height:320px}}
/* Popup & Promo Modal */
.st-popup-modal{overflow:visible;container-type:normal;height:0;min-height:0;background:transparent}
.st-popup-modal:has(.pu.is-preview){height:auto;padding:clamp(24px,4vw,48px) var(--st-pad);background:color-mix(in srgb,var(--st-text) 8%,var(--st-bg))}
.pu-backdrop{position:fixed;inset:0;z-index:1000;background:rgba(15,23,42,.58);-webkit-backdrop-filter:blur(2px);backdrop-filter:blur(2px);opacity:0;transition:opacity .3s ease}
.pu-backdrop[hidden],.pu-dialog[hidden]{display:none}
.pu-dialog{position:fixed;z-index:1001;display:grid;grid-template-columns:minmax(0,5fr) minmax(0,6fr);--pu-wd:780px;width:min(var(--pu-w,var(--pu-wd)),calc(100vw - 32px));height:var(--pu-h,auto);max-height:calc(100vh - 32px);max-height:calc(100dvh - 32px);overflow:auto;border-radius:calc(var(--st-radius) * 1.2px);background:var(--st-bg);color:var(--st-text);box-shadow:0 40px 90px -20px rgba(15,23,42,.55);font-family:var(--st-font-body);opacity:0;transition:opacity .3s ease,transform .35s cubic-bezier(.2,.8,.2,1)}
.pu[data-pos=center] .pu-dialog{top:50%;left:50%;transform:translate(-50%,-46%) scale(.97)}
.pu:not([data-pos=center]) .pu-dialog{--pu-wd:400px;grid-template-columns:1fr;box-shadow:0 24px 60px -16px rgba(15,23,42,.5),0 0 0 1px color-mix(in srgb,var(--st-text) 8%,transparent)}
.pu:not([data-pos=center]) .pu-backdrop{display:none}
.pu[data-pos^=bottom] .pu-dialog{bottom:20px;transform:translateY(24px)}
.pu[data-pos^=top] .pu-dialog{top:20px;transform:translateY(-24px)}
.pu[data-pos$=right] .pu-dialog{right:20px}
.pu[data-pos$=left] .pu-dialog{left:20px}
.pu[data-pos=bottom-center] .pu-dialog{left:50%;--pu-wd:460px;transform:translate(-50%,24px)}
.pu.is-open .pu-backdrop{opacity:1}
.pu.is-open .pu-dialog{opacity:1}
.pu[data-pos=center].is-open .pu-dialog{transform:translate(-50%,-50%)}
.pu[data-pos=bottom-center].is-open .pu-dialog{transform:translateX(-50%)}
.pu:not([data-pos=center]):not([data-pos=bottom-center]).is-open .pu-dialog{transform:none}
.pu-media{position:relative;min-height:220px;background:var(--st-surface)}
.pu-media:not(:has(.pu-img,.pu-car,.pu-video)){display:none}
.pu-dialog:not(:has(.pu-img,.pu-car,.pu-video)){grid-template-columns:1fr}
.pu-body:not(:has(.st-eyebrow:not(:empty),.pu-h:not(:empty),.pu-lead:not(:empty),.pu-form,.pu-ctas,.pu-html-wrap,.pu-no span:not(:empty))){display:none}
.pu-dialog:not(:has(.st-eyebrow:not(:empty),.pu-h:not(:empty),.pu-lead:not(:empty),.pu-form,.pu-ctas,.pu-html-wrap,.pu-no span:not(:empty))){grid-template-columns:1fr}
.pu-dialog:not(:has(.st-eyebrow:not(:empty),.pu-h:not(:empty),.pu-lead:not(:empty),.pu-form,.pu-ctas,.pu-html-wrap,.pu-no span:not(:empty))) .pu-media{min-height:clamp(240px,40vw,380px)}
.pu[data-pos=center][data-layout=right] .pu-dialog{grid-template-columns:minmax(0,6fr) minmax(0,5fr)}
.pu[data-pos=center][data-layout=right] .pu-media{order:2}
.pu[data-pos=center][data-layout=top] .pu-dialog{grid-template-columns:1fr;--pu-wd:520px}
.pu[data-pos=center][data-layout=top] .pu-media{min-height:0;aspect-ratio:16/9}
.pu[data-pos=center][data-layout=bottom] .pu-dialog{grid-template-columns:1fr;--pu-wd:520px}
.pu[data-pos=center][data-layout=bottom] .pu-media{min-height:0;aspect-ratio:16/9}
.pu[data-layout=bottom] .pu-media{order:2}
.pu:not([data-pos=center]) .pu-media{min-height:150px;aspect-ratio:16/9}
.pu-img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover}
.pu-car{position:absolute;inset:0}
.pu-video{position:absolute;inset:0;z-index:1;background:#0b1020;overflow:hidden}
.pu-video .vs-poster{position:absolute;inset:0;width:100%;height:100%;object-fit:cover}
.pu-video .vs-play{position:absolute;inset:0;display:grid;place-items:center;background:linear-gradient(to top,rgba(8,10,20,.55),rgba(8,10,20,.08) 65%);color:#fff;text-decoration:none}
.pu-video .vs-btn{display:grid;place-items:center;width:64px;height:64px;border-radius:50%;background:var(--st-brand);color:var(--st-btn-text);box-shadow:0 8px 24px rgba(0,0,0,.35);transition:transform .2s ease}
.pu-video .vs-btn svg{margin-left:3px}
.pu-video .vs-play:hover .vs-btn{transform:scale(1.08)}
.pu-video .vs-play:focus-visible{outline:4px solid var(--st-brand);outline-offset:-4px}
.pu-video .vs-embed{position:absolute;inset:0;width:100%;height:100%;border:0;background:#000}
.pu-video.is-playing .vs-poster,.pu-video.is-playing .vs-play{display:none}
.pu-html-wrap{width:100%;min-width:0}
.pu-html{min-width:0;color:var(--st-text);font-size:15px;line-height:1.6}
.pu-html iframe,.pu-html img,.pu-html video{max-width:100%}
.pu-track{display:flex;height:100%;margin:0;padding:0;list-style:none;overflow-x:auto;scroll-snap-type:x mandatory;scrollbar-width:none;-webkit-overflow-scrolling:touch}
.pu-track::-webkit-scrollbar{display:none}
.pu-slide{position:relative;flex:0 0 100%;height:100%;scroll-snap-align:center}
.pu-slide img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover}
.pu-slide-link{position:absolute;inset:0}
.pu-cap{position:absolute;left:0;right:0;bottom:0;padding:34px 16px 38px;background:linear-gradient(to top,rgba(8,10,20,.72),transparent);color:#fff;font-weight:700;font-size:15px;line-height:1.3;pointer-events:none}
.pu-cap:empty{display:none}
.pu-nav{position:absolute;top:50%;z-index:2;display:grid;place-items:center;width:34px;height:34px;margin-top:-17px;border:0;border-radius:50%;background:rgba(255,255,255,.9);color:#0f172a;cursor:pointer;box-shadow:0 2px 8px rgba(15,23,42,.3)}
.pu-nav:hover{background:#fff}
.pu-prev{left:10px}
.pu-next{right:10px}
.pu-dots{position:absolute;left:0;right:0;bottom:12px;z-index:2;display:flex;justify-content:center;gap:7px}
.pu-dot{width:9px;height:9px;padding:0;border:0;border-radius:50%;background:rgba(255,255,255,.55);cursor:pointer;transition:background .2s ease,transform .2s ease}
.pu-dot[aria-current=true]{background:#fff;transform:scale(1.25)}
.pu-car.is-single .pu-nav,.pu-car.is-single .pu-dots{display:none}
.pu-body{display:flex;flex-direction:column;align-items:flex-start;gap:12px;justify-content:safe center;padding:clamp(24px,4vw,40px)}
.pu:not([data-pos=center]) .pu-body{padding:20px 22px 22px;gap:10px}
.pu-h{font-size:clamp(24px,2vw + 14px,34px)}
.pu:not([data-pos=center]) .pu-h{font-size:clamp(20px,1vw + 14px,26px)}
.pu-lead{color:var(--st-muted);font-size:16px}
.pu:not([data-pos=center]) .pu-lead{font-size:14.5px}
.pu-form{width:100%}
.pu-row{display:flex;flex-direction:column;gap:10px}
.pu-input{width:100%;min-height:50px;padding:0 16px;border:1.5px solid color-mix(in srgb,var(--st-text) 18%,transparent);border-radius:calc(var(--st-radius) * .7px);background:var(--st-bg);color:var(--st-text);font:500 16px/1 var(--st-font-body);outline:none}
.pu-input:focus{border-color:var(--st-brand);box-shadow:0 0 0 4px color-mix(in srgb,var(--st-brand) 18%,transparent)}
.pu-btn{width:100%}
.pu-ctas{display:flex;flex-wrap:wrap;gap:10px;width:100%}
.pu-ctas .pu-cta{flex:1 1 auto}
.pu-note{margin-top:8px;font-size:13px;color:var(--st-muted)}
.pu-note:empty,.pu-ok:empty,.pu-err:empty{display:none}
.pu-ok{padding:12px 14px;border-radius:calc(var(--st-radius) * .6px);background:color-mix(in srgb,#16a34a 14%,transparent);color:var(--st-text);font-weight:600}
.pu-err{margin-top:8px;color:#b91c1c;font-size:14px;font-weight:600}
.pu-no{align-self:center;padding:6px 10px;border:0;background:none;color:var(--st-muted);font:600 14px/1 var(--st-font-body);text-decoration:underline;text-underline-offset:3px;cursor:pointer}
.pu-no:hover{color:var(--st-text)}
.pu-no:has(span:empty){display:none}
.pu-x{position:absolute;top:12px;right:12px;z-index:3;display:grid;place-items:center;width:36px;height:36px;border:0;border-radius:50%;background:color-mix(in srgb,var(--st-bg) 88%,transparent);color:var(--st-text);cursor:pointer;box-shadow:0 2px 8px rgba(15,23,42,.18);transition:background .2s ease,transform .2s ease}
.pu-x:hover{background:var(--st-bg);transform:scale(1.06)}
.pu-x:focus-visible,.pu-no:focus-visible,.pu-input:focus-visible,.pu-nav:focus-visible,.pu-dot:focus-visible{outline:3px solid color-mix(in srgb,var(--st-brand) 55%,transparent);outline-offset:2px}
.pu.is-preview .pu-backdrop{display:none}
.pu.is-preview .pu-dialog{position:relative;inset:auto;transform:none;margin:0 auto;opacity:1;max-height:none}
@media (max-width:640px){
.pu[data-pos=center] .pu-dialog,.pu[data-pos=center][data-layout=right] .pu-dialog{grid-template-columns:1fr}
.pu[data-pos=center][data-layout=right] .pu-media{order:0}
.pu-media{min-height:150px;max-height:220px}
.pu:not([data-pos=center]) .pu-dialog{left:12px;right:12px;width:auto}
.pu[data-pos=bottom-center] .pu-dialog,.pu[data-pos=bottom-center].is-open .pu-dialog{left:12px;transform:none}
.pu[data-pos^=bottom] .pu-dialog{bottom:12px}
.pu[data-pos^=top] .pu-dialog{top:12px}
.pu-body{padding:22px}
}
@media print{.pu{display:none}}
/* Minimal Footer */
.st-footer-minimal{padding:36px 0 28px;border-top:1px solid color-mix(in srgb,var(--st-text) 8%,transparent)}
.st-brand{display:inline-flex;align-items:center;gap:10px;flex:none;text-decoration:none;color:var(--st-text)}
.st-brand-img{height:32px;width:auto;max-width:180px;object-fit:contain}
.st-brand-mark{display:inline-flex;align-items:center;gap:10px;font:800 21px/1 var(--st-font-heading);letter-spacing:-.03em}
.st-brand-icon{display:grid;place-items:center;width:34px;height:34px;border-radius:calc(var(--st-radius) * .7px);background:var(--st-brand);color:var(--st-btn-text)}
.st-brand-icon svg{width:19px;height:19px}
.st-socials{list-style:none;display:flex;flex-wrap:wrap;gap:8px}
.st-social{display:grid;place-items:center;width:40px;height:40px;border-radius:calc(var(--st-radius) * .7px);color:var(--st-muted);background:color-mix(in srgb,var(--st-text) 6%,transparent);transition:color .2s ease,background .2s ease,transform .2s ease}
.st-social:hover{color:var(--st-btn-text);background:var(--st-brand);transform:translateY(-2px)}
.st-social > span{display:block;line-height:0}
.st-social svg{display:block;width:19px;height:19px}
.fm .st-brand-mark{font-size:19px}
.fm .st-brand-icon{width:30px;height:30px}
.fm-row{display:flex;align-items:center;justify-content:space-between;flex-wrap:wrap;gap:20px 32px;padding-bottom:24px;border-bottom:1px solid color-mix(in srgb,var(--st-text) 8%,transparent)}
.fm-links{list-style:none;display:flex;flex-wrap:wrap;gap:8px 26px}
.fm-links a{color:var(--st-muted);font-size:15px;font-weight:500;text-decoration:none}
.fm-links a:hover{color:var(--st-brand)}
.fm .st-social{width:36px;height:36px;background:none}
.fm .st-social:hover{background:color-mix(in srgb,var(--st-brand) 12%,transparent);color:var(--st-brand)}
.fm-copy{padding-top:20px;color:var(--st-muted);font-size:14px;text-align:center}
@container st (max-width:760px){.fm-row{flex-direction:column;text-align:center}.fm-links{justify-content:center}.fm .st-socials{justify-content:center}}
.st:has(>.st-art){isolation:isolate}
.st-art{position:absolute;inset:0;z-index:-1;overflow:hidden;pointer-events:none}
.st-art>svg{position:absolute;top:0;left:0;display:block;width:100%;height:100%}
.st-art--bottom>svg{top:auto;bottom:-1px;height:var(--st-art-h,80px)}
.st-art--top>svg{top:-1px;bottom:auto;height:var(--st-art-h,80px);transform:scaleY(-1)}
.st-art--corner>svg{top:-12%;right:-8%;left:auto;width:min(58%,620px);height:auto}
.st-art--corners>svg{top:0;right:0;left:auto;width:clamp(140px,22cqi,300px);height:auto}
.st-art--corners>svg+svg{top:auto;right:auto;bottom:0;left:0;transform:rotate(180deg)}
(function () {
var G = window.gsap;
var reduce = window.matchMedia && window.matchMedia('(prefers-reduced-motion: reduce)').matches;
var anim = G && !reduce;
document.querySelectorAll('.st').forEach(function (sec) {
var btn = sec.querySelector('[data-menu-toggle]');
var panel = sec.querySelector('[data-menu]');
if (btn && panel) {
sec.classList.add('has-menu');
var isOpen = false;
var mobile = function () { return getComputedStyle(btn).display !== 'none'; };
// The toggle and the panel's controls, in document order (the toggle may come after the panel)
var focusables = function () {
return Array.prototype.filter.call(sec.querySelectorAll('a[href], button'), function (el) { return el === btn || panel.contains(el); });
};
var open = function () {
isOpen = true;
sec.classList.add('menu-open');
btn.setAttribute('aria-expanded', 'true');
if (anim) {
G.fromTo(panel, { opacity: 0, y: -12 }, { opacity: 1, y: 0, duration: 0.35, ease: 'power3.out', clearProps: 'transform,opacity' });
G.fromTo(panel.querySelectorAll('[data-menu-item]'), { opacity: 0, y: -8 }, { opacity: 1, y: 0, duration: 0.3, stagger: 0.04, delay: 0.05, ease: 'power2.out', clearProps: 'transform,opacity' });
}
var first = panel.querySelector('a[href], button');
if (first) first.focus();
};
var close = function (returnFocus) {
if (!isOpen) return;
isOpen = false;
btn.setAttribute('aria-expanded', 'false');
var done = function () { sec.classList.remove('menu-open'); };
if (anim) G.to(panel, { opacity: 0, y: -8, duration: 0.2, ease: 'power2.in', onComplete: function () { done(); G.set(panel, { clearProps: 'transform,opacity' }); } });
else done();
if (returnFocus) btn.focus();
};
btn.addEventListener('click', function () { if (isOpen) close(false); else open(); });
document.addEventListener('keydown', function (e) {
if (!isOpen) return;
if (e.key === 'Escape') { close(true); return; }
if (e.key === 'Tab') {
var f = focusables(), first = f[0], last = f[f.length - 1];
if (e.shiftKey && document.activeElement === first) { e.preventDefault(); last.focus(); }
else if (!e.shiftKey && document.activeElement === last) { e.preventDefault(); first.focus(); }
}
});
document.addEventListener('click', function (e) { if (isOpen && !sec.contains(e.target)) close(false); });
panel.addEventListener('click', function (e) { if (e.target.closest('a')) close(false); });
window.addEventListener('resize', function () { if (isOpen && !mobile()) close(false); });
}
sec.querySelectorAll('[data-dismiss]').forEach(function (x) {
x.addEventListener('click', function () {
var box = x.closest('[data-dismissable]');
if (!box) return;
if (anim) G.to(box, { height: 0, opacity: 0, paddingTop: 0, paddingBottom: 0, duration: 0.35, ease: 'power2.inOut', onComplete: function () { box.remove(); } });
else box.remove();
});
});
if (sec.querySelector('[data-sticky-flag]')) {
var hideOn = !!sec.querySelector('[data-hide-flag]');
var last = window.scrollY, hidden = false;
var onScroll = function () {
var y = window.scrollY;
sec.classList.toggle('is-scrolled', y > 8);
if (hideOn && !sec.classList.contains('menu-open')) {
var down = y > last && y > 120;
if (down !== hidden) {
hidden = down;
if (anim) G.to(sec, { yPercent: down ? -100 : 0, duration: 0.35, ease: 'power2.out' });
else sec.style.transform = down ? 'translateY(-100%)' : '';
}
}
last = y;
};
window.addEventListener('scroll', onScroll, { passive: true });
onScroll();
}
});
})();
(function () {
var G = window.gsap, reduce = window.matchMedia && window.matchMedia('(prefers-reduced-motion: reduce)').matches;
if (!G || !window.ScrollTrigger || reduce || (window.ST_STILL && !window.ST_SCROLL_FX)) return;
G.registerPlugin(ScrollTrigger);
G.matchMedia().add('(min-width: 768px)', function () {
var made = [];
document.querySelectorAll('.st [data-hscroll]').forEach(function (row) {
var sec = row.closest('.st');
sec.classList.add('is-hscroll');
var dist = function () { return Math.max(0, row.scrollWidth - row.clientWidth); };
// A sticky header stays on screen, so the section pins just below it instead of under it
var head = function () { var h = 0; document.querySelectorAll('.st').forEach(function (n) { if (n !== sec && n.querySelector('[data-sticky-flag]')) h = Math.max(h, n.offsetHeight); }); return h; };
var tw = G.to(row, { x: function () { return -dist(); }, ease: 'none', scrollTrigger: { trigger: sec, start: function () { return 'top ' + head(); }, end: function () { return '+=' + dist(); }, pin: true, scrub: 0.6, anticipatePin: 1, invalidateOnRefresh: true } });
made.push(function () { tw.scrollTrigger.kill(); tw.kill(); G.set(row, { clearProps: 'transform' }); sec.classList.remove('is-hscroll'); });
});
return function () { made.forEach(function (f) { f(); }); };
});
})();
(function () {
var G = window.gsap, reduce = window.matchMedia && window.matchMedia('(prefers-reduced-motion: reduce)').matches;
if (!G || !window.ScrollTrigger || reduce || (window.ST_STILL && !window.ST_SCROLL_FX)) return;
G.registerPlugin(ScrollTrigger);
G.matchMedia().add('(min-width: 768px)', function () {
var made = [];
document.querySelectorAll('.st [data-stack]').forEach(function (list) {
var cards = Array.prototype.slice.call(list.children);
if (cards.length < 2) return;
var last = cards[cards.length - 1];
cards.forEach(function (card, i) {
var top = 90 + i * 22;
var pin = ScrollTrigger.create({ trigger: card, start: 'top ' + top, endTrigger: last, end: 'top ' + (90 + (cards.length - 1) * 22), pin: true, pinSpacing: false });
made.push(function () { pin.kill(); });
if (card === last) return;
// Scale the card's inner wrapper: the card itself is positioned by its pin
var inner = card.firstElementChild || card;
// fromTo: GSAP can't tween a filter from "none" (it would start at brightness 0)
var tw = G.fromTo(inner, { scale: 1, filter: 'brightness(1)' }, { scale: 1 - (cards.length - 1 - i) * 0.04, filter: 'brightness(.82)', ease: 'none', scrollTrigger: { trigger: cards[i + 1], start: 'top bottom', end: 'top ' + top, scrub: true } });
made.push(function () { tw.scrollTrigger.kill(); tw.kill(); G.set(inner, { clearProps: 'transform,filter' }); });
});
});
return function () { made.forEach(function (f) { f(); }); };
});
})();
(function () {
var viewer, imgEl, capEl, countEl, items = [], index = 0, opener = null;
function build() {
if (viewer) return;
viewer = document.createElement('div');
viewer.className = 'stg-lb';
viewer.setAttribute('role', 'dialog');
viewer.setAttribute('aria-modal', 'true');
viewer.setAttribute('aria-label', 'Image viewer');
viewer.hidden = true;
viewer.innerHTML = '<button type="button" class="stg-lb-close" aria-label="Close"><svg viewBox="0 0 24 24" width="22" height="22" fill="none" stroke="currentColor" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M6 6l12 12M18 6 6 18"/></svg></button>' +
'<button type="button" class="stg-lb-nav stg-lb-prev" aria-label="Previous image"><svg viewBox="0 0 24 24" width="22" height="22" fill="none" stroke="currentColor" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="m15 5-7 7 7 7"/></svg></button>' +
'<figure class="stg-lb-fig"><img class="stg-lb-img" alt=""><figcaption class="stg-lb-cap"></figcaption></figure>' +
'<button type="button" class="stg-lb-nav stg-lb-next" aria-label="Next image"><svg viewBox="0 0 24 24" width="22" height="22" fill="none" stroke="currentColor" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="m9 5 7 7-7 7"/></svg></button>' +
'<p class="stg-lb-count" aria-live="polite"></p>';
document.body.appendChild(viewer);
imgEl = viewer.querySelector('.stg-lb-img');
capEl = viewer.querySelector('.stg-lb-cap');
countEl = viewer.querySelector('.stg-lb-count');
viewer.addEventListener('click', function (e) {
if (e.target === viewer || e.target.classList.contains('stg-lb-fig')) close();
});
viewer.querySelector('.stg-lb-close').addEventListener('click', close);
viewer.querySelector('.stg-lb-prev').addEventListener('click', function () { show(index - 1); });
viewer.querySelector('.stg-lb-next').addEventListener('click', function () { show(index + 1); });
document.addEventListener('keydown', function (e) {
if (viewer.hidden) return;
if (e.key === 'Escape') close();
else if (e.key === 'ArrowLeft') show(index - 1);
else if (e.key === 'ArrowRight') show(index + 1);
else if (e.key === 'Tab') {
var f = viewer.querySelectorAll('button');
var first = f[0], last = f[f.length - 1];
if (e.shiftKey && document.activeElement === first) { e.preventDefault(); last.focus(); }
else if (!e.shiftKey && document.activeElement === last) { e.preventDefault(); first.focus(); }
}
});
}
function show(i) {
if (!items.length) return;
index = (i + items.length) % items.length;
var fig = items[index], img = fig.querySelector('img');
imgEl.src = img.currentSrc || img.src;
imgEl.alt = img.alt || '';
var cap = fig.querySelector('.gg-cap');
var parts = cap ? [].slice.call(cap.children).map(function (c) { return c.textContent.trim(); }).filter(Boolean) : [];
capEl.textContent = parts.join(' — ');
countEl.textContent = (index + 1) + ' / ' + items.length;
viewer.classList.toggle('is-single', items.length < 2);
}
// In the editor the preview is a tall frame inside a scrolling panel: centre the viewer in the
// part of the frame you can actually see (a normal page uses the whole window)
// The part of this frame you can see when it sits inside a scrolling panel of the editor
// (null on a normal page): { top, bottom } in the frame's own pixels
function seenRange() {
var fe = null, pw = null;
try { fe = window.frameElement; pw = window.parent; } catch (err) { return null; }
if (!fe || !pw || pw === window) return null;
try {
var r = fe.getBoundingClientRect(), k = r.width / (window.innerWidth || r.width) || 1;
var top = 0, bottom = pw.innerHeight;
for (var n = fe.parentElement; n; n = n.parentElement) {
if (/(auto|scroll|hidden|clip)/.test(pw.getComputedStyle(n).overflowY)) {
var nr = n.getBoundingClientRect();
top = Math.max(top, nr.top); bottom = Math.min(bottom, nr.bottom);
}
}
return { top: Math.max(0, top - r.top) / k, bottom: (Math.min(bottom, r.bottom) - r.top) / k };
} catch (err) { return null; }
}
function fit() {
if (!viewer) return;
var range = window.ST_STILL || window.ST_PREVIEW ? seenRange() : null;
if (!range || range.bottom - range.top < 120) { viewer.style.top = ''; viewer.style.bottom = ''; viewer.style.removeProperty('--lb-h'); return; }
viewer.style.top = range.top + 'px';
viewer.style.bottom = Math.max(0, window.innerHeight - range.bottom) + 'px';
viewer.style.setProperty('--lb-h', (range.bottom - range.top) + 'px');
}
function watch(on) {
try { var w = window.parent; if (!w || w === window) return; var f = on ? 'addEventListener' : 'removeEventListener'; w[f]('scroll', fit, true); w[f]('resize', fit); } catch (err) { /* cross-origin parent */ }
}
function open(list, i, from) {
build();
items = list; opener = from;
show(i);
viewer.hidden = false;
fit(); watch(true);
document.documentElement.classList.add('stg-open');
viewer.querySelector('.stg-lb-close').focus();
}
function close() {
viewer.hidden = true;
watch(false);
document.documentElement.classList.remove('stg-open');
if (opener) opener.focus();
}
document.querySelectorAll('.st').forEach(function (sec) {
var grid = sec.querySelector('[data-gallery]');
if (!grid) return;
var all = [].slice.call(grid.querySelectorAll('.gg-item'));
var bar = sec.querySelector('[data-gallery-filters]');
if (bar && !window.ST_STILL) {
var tags = [];
all.forEach(function (it) { var t = (it.getAttribute('data-tag') || '').trim(); if (t && tags.indexOf(t) < 0) tags.push(t); });
if (tags.length > 1) {
var label = bar.getAttribute('data-all') || 'All';
var buttons = [];
[''].concat(tags).forEach(function (t) {
var b = document.createElement('button');
b.type = 'button';
b.className = 'gg-chip';
b.textContent = t || label;
b.setAttribute('aria-pressed', t ? 'false' : 'true');
b.addEventListener('click', function () {
buttons.forEach(function (x) { x.setAttribute('aria-pressed', String(x === b)); });
all.forEach(function (it) { it.hidden = !!t && (it.getAttribute('data-tag') || '').trim() !== t; });
});
buttons.push(b);
bar.appendChild(b);
});
bar.hidden = false;
}
}
var editing = window.ST_STILL || window.ST_PREVIEW;
all.forEach(function (it) {
var img = it.querySelector('img');
if (!img) return;
function go() {
var visible = all.filter(function (x) { return !x.hidden; });
open(visible, visible.indexOf(it), it);
}
if (editing) {
// In the editor the click also selects the photo in the panel (the editor handles that),
// and the viewer opens on top so you can check it
it.style.cursor = 'zoom-in';
it.addEventListener('click', go);
return;
}
it.setAttribute('tabindex', '0');
it.setAttribute('role', 'button');
it.setAttribute('aria-label', 'View larger: ' + (img.alt || 'image'));
it.addEventListener('click', go);
it.addEventListener('keydown', function (e) { if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); go(); } });
});
});
})();
(function () {
var G = window.gsap;
if (G && window.Draggable) G.registerPlugin(Draggable);
if (G && window.InertiaPlugin) G.registerPlugin(InertiaPlugin);
if (G && window.ScrollToPlugin) G.registerPlugin(ScrollToPlugin);
var reduce = window.matchMedia && window.matchMedia('(prefers-reduced-motion: reduce)').matches;
var fine = window.matchMedia && window.matchMedia('(pointer: fine)').matches;
document.querySelectorAll('.st').forEach(function (sec) {
var track = sec.querySelector('[data-carousel]');
if (!track) return;
var prev = sec.querySelector('[data-carousel-prev]');
var next = sec.querySelector('[data-carousel-next]');
var max = function () { return Math.max(0, track.scrollWidth - track.clientWidth); };
var points = function () {
var first = track.children[0];
if (!first) return [0];
return Array.prototype.map.call(track.children, function (c) { return Math.min(max(), c.offsetLeft - first.offsetLeft); });
};
var nearest = function (x) { return points().reduce(function (a, p) { return Math.abs(p - x) < Math.abs(a - x) ? p : a; }, 0); };
var update = function () {
var x = track.scrollLeft;
if (prev) prev.disabled = x <= 2;
if (next) next.disabled = x >= max() - 2;
};
var go = function (dir) {
var ps = points(), x = track.scrollLeft, target = x;
if (dir > 0) { for (var i = 0; i < ps.length; i++) if (ps[i] > x + 4) { target = ps[i]; break; } }
else { for (var j = ps.length - 1; j >= 0; j--) if (ps[j] < x - 4) { target = ps[j]; break; } }
if (G && window.ScrollToPlugin && !reduce) G.to(track, { scrollTo: { x: target }, duration: 0.6, ease: 'power3.out', onUpdate: update });
else track.scrollTo({ left: target, behavior: reduce ? 'auto' : 'smooth' });
};
if (prev) prev.addEventListener('click', function () { go(-1); });
if (next) next.addEventListener('click', function () { go(1); });
track.addEventListener('scroll', update, { passive: true });
window.addEventListener('resize', update);
update();
// Mouse drag with momentum on desktop; touch keeps native scrolling and snap.
// An invisible proxy is dragged and its x is mapped onto the track's native scrollLeft,
// so the slides' markup and layout never change.
if (G && window.Draggable && fine) {
track.classList.add('is-draggable');
var proxy = document.createElement('div');
var start = 0;
var apply = function () { track.scrollLeft = start - this.x; update(); };
Draggable.create(proxy, {
type: 'x',
trigger: track,
inertia: !!window.InertiaPlugin && !reduce,
dragClickables: false,
onPress: function () { G.killTweensOf(track); start = track.scrollLeft; G.set(proxy, { x: 0 }); this.update(); },
onDrag: apply,
onThrowUpdate: apply,
snap: { x: function (v) { return start - nearest(Math.max(0, Math.min(max(), start - v))); } },
onRelease: function () { if (!this.tween) { G.to(track, { scrollTo: window.ScrollToPlugin ? { x: nearest(track.scrollLeft) } : undefined, duration: 0.4, ease: 'power3.out', onUpdate: update }); } }
});
}
});
})();
(function () {
var G = window.gsap;
var reduce = window.matchMedia && window.matchMedia('(prefers-reduced-motion: reduce)').matches;
var anim = G && !reduce;
document.querySelectorAll('.st [data-accordion]').forEach(function (list) {
var mode = list.getAttribute('data-accordion') || '';
var items = Array.prototype.slice.call(list.querySelectorAll('details'));
var body = function (d) { return d.querySelector('.st-acc-a'); };
var close = function (d) {
if (!d.open || d.classList.contains('is-closing')) return;
if (!anim) { d.open = false; return; }
d.classList.add('is-closing');
G.to(body(d), { height: 0, duration: 0.32, ease: 'power2.inOut', onComplete: function () {
d.open = false; d.classList.remove('is-closing'); G.set(body(d), { clearProps: 'height' });
} });
};
var open = function (d) {
d.open = true;
if (!anim) return;
var b = body(d);
G.fromTo(b, { height: 0 }, { height: 'auto', duration: 0.4, ease: 'power2.out', clearProps: 'height' });
G.fromTo(b.children, { y: -8, opacity: 0 }, { y: 0, opacity: 1, duration: 0.35, delay: 0.06, ease: 'power2.out', clearProps: 'transform,opacity' });
};
items.forEach(function (d) {
d.querySelector('summary').addEventListener('click', function (e) {
e.preventDefault();
if (d.open && !d.classList.contains('is-closing')) { close(d); return; }
if (/single/.test(mode)) items.forEach(function (o) { if (o !== d) close(o); });
open(d);
});
});
if (/first/.test(mode) && items[0]) items[0].open = true;
});
})();
(function () {
var G = window.gsap;
var reduce = window.matchMedia && window.matchMedia('(prefers-reduced-motion: reduce)').matches;
document.querySelectorAll('.st form[data-form]').forEach(function (form) {
var ok = form.querySelector('[data-form-success]');
var bad = form.querySelector('[data-form-error]');
var btn = form.querySelector('[type="submit"]');
var done = function () {
var fields = form.querySelectorAll('[data-form-fields]');
var show = function () {
Array.prototype.forEach.call(fields, function (f) { f.hidden = true; });
if (ok) { ok.hidden = false; ok.focus && ok.focus(); if (G && !reduce) G.from(ok, { y: 16, opacity: 0, duration: 0.5, ease: 'power3.out', clearProps: 'transform,opacity' }); }
};
if (G && !reduce && fields.length) G.to(fields, { opacity: 0, y: -10, duration: 0.25, onComplete: show }); else show();
};
form.addEventListener('submit', function (e) {
if (!window.fetch) return;
e.preventDefault();
if (bad) bad.hidden = true;
if (btn) { btn.disabled = true; btn.setAttribute('aria-busy', 'true'); }
var finish = function () { if (btn) { btn.disabled = false; btn.removeAttribute('aria-busy'); } };
if (window.ST_PREVIEW) { setTimeout(function () { finish(); done(); }, 600); return; }
fetch(form.action, { method: 'POST', body: new FormData(form), headers: { Accept: 'application/json' } })
.then(function (r) { finish(); if (r.ok) done(); else if (bad) bad.hidden = false; })
.catch(function () { finish(); if (bad) bad.hidden = false; });
});
});
})();
(function () {
var d = new Date();
var pad = function (n) { return (n < 10 ? '0' : '') + n; };
var today = d.getFullYear() + '-' + pad(d.getMonth() + 1) + '-' + pad(d.getDate());
document.querySelectorAll('.st [data-booking-date]').forEach(function (input) { input.min = today; });
})();
(function () {
var inline = window.ST_STILL || window.ST_PREVIEW || window.ST_POPUP_INLINE;
document.querySelectorAll('.st [data-pu]').forEach(function (root) {
var dlg = root.querySelector('.pu-dialog');
var back = root.querySelector('.pu-backdrop');
if (!dlg || root.getAttribute('data-pu-ready')) return;
root.setAttribute('data-pu-ready', '1');
var reduce = window.matchMedia && window.matchMedia('(prefers-reduced-motion: reduce)').matches;
root.querySelectorAll('[data-pu-carousel]').forEach(function (car) {
var track = car.querySelector('.pu-track');
if (!track) return;
var slides = track.children, n = slides.length;
if (n < 2) { car.classList.add('is-single'); return; }
var mk = function (cls, label, svg) { var b = document.createElement('button'); b.type = 'button'; b.className = cls; b.setAttribute('aria-label', label); if (svg) b.innerHTML = svg; return b; };
var arrow = function (d) { return '<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.6" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="' + d + '"/></svg>'; };
var prev = mk('pu-nav pu-prev', 'Previous slide', arrow('m15 18-6-6 6-6'));
var next = mk('pu-nav pu-next', 'Next slide', arrow('m9 18 6-6-6-6'));
var dots = document.createElement('div'); dots.className = 'pu-dots';
var dotEls = [];
for (var i = 0; i < n; i++) { (function (k) { var d = mk('pu-dot', 'Go to slide ' + (k + 1)); d.addEventListener('click', function () { go(k); stop(); }); dots.appendChild(d); dotEls.push(d); })(i); }
car.appendChild(prev); car.appendChild(next); car.appendChild(dots);
var idx = function () { return Math.round(track.scrollLeft / Math.max(1, track.clientWidth)); };
var mark = function () { var c = idx(); dotEls.forEach(function (d, k) { d.setAttribute('aria-current', k === c ? 'true' : 'false'); }); };
var go = function (k) { k = (k + n) % n; track.scrollTo({ left: k * track.clientWidth, behavior: reduce ? 'auto' : 'smooth' }); };
var ticking = false;
track.addEventListener('scroll', function () { if (ticking) return; ticking = true; requestAnimationFrame(function () { ticking = false; mark(); }); }, { passive: true });
prev.addEventListener('click', function () { go(idx() - 1); stop(); });
next.addEventListener('click', function () { go(idx() + 1); stop(); });
mark();
var secs = parseFloat(root.getAttribute('data-autoplay')) || 0;
var timer = 0, paused = false;
var stop = function () { clearInterval(timer); timer = 0; };
if (secs > 0 && !reduce) {
car.addEventListener('mouseenter', function () { paused = true; });
car.addEventListener('mouseleave', function () { paused = false; });
car.addEventListener('focusin', function () { paused = true; });
car.addEventListener('focusout', function () { paused = false; });
timer = setInterval(function () { var d = root.querySelector('.pu-dialog'); if (!paused && d && !d.hidden && !document.hidden) go(idx() + 1); }, secs * 1000);
}
});
if (inline) {
root.classList.add('is-preview');
dlg.hidden = false;
if (back) back.hidden = true;
root.querySelectorAll('[data-pu-close]').forEach(function (b) { b.addEventListener('click', function (e) { e.preventDefault(); }); });
return;
}
var trigger = root.getAttribute('data-trigger') || 'delay';
var delay = Math.max(0, parseFloat(root.getAttribute('data-delay')) || 0);
var pct = Math.min(100, Math.max(1, parseFloat(root.getAttribute('data-scroll')) || 50));
var days = parseFloat(root.getAttribute('data-days')) || 0;
var KEY = 'pu-' + (root.getAttribute('data-pu-id') || 'x');
try {
var seen = parseInt(localStorage.getItem(KEY), 10);
if (days > 0 && seen && Date.now() - seen < days * 86400000) return;
} catch (e) {}
var modal = (root.getAttribute('data-pos') || 'center') === 'center'; // only the centre popup dims the page and traps focus
dlg.setAttribute('aria-modal', modal ? 'true' : 'false');
var shown = false, last = null, undo = [];
var focusables = function () { return Array.prototype.filter.call(dlg.querySelectorAll('a[href],button:not([disabled]),input,select,textarea,[tabindex]:not([tabindex="-1"])'), function (el) { return el.offsetParent !== null; }); };
var onKey = function (e) {
if (e.key === 'Escape') { e.preventDefault(); hide(); return; }
if (e.key !== 'Tab' || !modal) return;
var f = focusables();
if (!f.length) return;
var first = f[0], end = f[f.length - 1];
if (e.shiftKey && document.activeElement === first) { e.preventDefault(); end.focus(); }
else if (!e.shiftKey && document.activeElement === end) { e.preventDefault(); first.focus(); }
};
function show() {
if (shown) return;
shown = true;
undo.forEach(function (fn) { fn(); });
last = document.activeElement;
dlg.hidden = false;
if (back) back.hidden = false;
void dlg.offsetWidth;
root.classList.add('is-open');
if (modal) {
var f = focusables();
var target = dlg.querySelector('input') || f[1] || f[0] || dlg;
try { target.focus({ preventScroll: true }); } catch (e) {}
}
document.addEventListener('keydown', onKey);
try { if (days > 0) localStorage.setItem(KEY, String(Date.now())); } catch (e) {}
}
function hide() {
root.classList.remove('is-open');
root.querySelectorAll('.vs-embed').forEach(function (v) { var box = v.parentNode; v.remove(); if (box) box.classList.remove('is-playing'); });
document.removeEventListener('keydown', onKey);
setTimeout(function () { dlg.hidden = true; if (back) back.hidden = true; }, 320);
if (last && last.focus) { try { last.focus({ preventScroll: true }); } catch (e) {} }
}
root.querySelectorAll('[data-pu-close]').forEach(function (b) { b.addEventListener('click', hide); });
var on = function (target, ev, fn, opts) { target.addEventListener(ev, fn, opts); undo.push(function () { target.removeEventListener(ev, fn, opts); }); };
var started = Date.now();
if (trigger === 'scroll') {
var check = function () {
var h = document.documentElement.scrollHeight - window.innerHeight;
var p = h > 0 ? (window.scrollY / h) * 100 : 100;
if (p >= pct) show();
};
on(window, 'scroll', check, { passive: true });
} else if (trigger === 'exit' && window.matchMedia && window.matchMedia('(pointer: fine)').matches) {
on(document, 'mouseout', function (e) { if (!e.relatedTarget && e.clientY <= 0 && Date.now() - started > 2000) show(); });
} else {
var timer = setTimeout(show, Math.max(delay, trigger === 'exit' ? 10 : 0) * 1000);
undo.push(function () { clearTimeout(timer); });
}
});
})();
(function () {
var editing = window.ST_STILL || window.ST_PREVIEW;
function embed(url) {
var m;
// Character classes instead of backslashes: this code lives inside a template literal
if ((m = url.match(/(?:youtube[.]com[/](?:watch[?](?:.*&)?v=|embed[/]|shorts[/])|youtu[.]be[/])([A-Za-z0-9_-]{11})/))) return { type: 'iframe', src: 'https://www.youtube-nocookie.com/embed/' + m[1] + '?autoplay=1&rel=0' };
if ((m = url.match(/vimeo[.]com[/](?:video[/])?([0-9]+)/))) return { type: 'iframe', src: 'https://player.vimeo.com/video/' + m[1] + '?autoplay=1&dnt=1' };
if (/[.](mp4|webm|ogg)([?].*)?$/i.test(url)) return { type: 'video', src: url };
return null;
}
document.querySelectorAll('.st [data-video-box]').forEach(function (box) {
var btn = box.querySelector('[data-video]');
if (!btn) return;
function start(e) {
var info = embed(btn.getAttribute('data-video') || '');
if (!info) return;
e.preventDefault();
// In the editor the click also selects the section, so the editor still gets it
if (!editing) e.stopPropagation();
var title = box.getAttribute('data-title') || 'Video';
var el;
if (info.type === 'iframe') {
el = document.createElement('iframe');
el.src = info.src;
el.title = title;
el.allow = 'accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; fullscreen';
el.allowFullscreen = true;
el.referrerPolicy = 'strict-origin-when-cross-origin';
} else {
el = document.createElement('video');
el.src = info.src;
el.controls = true;
el.autoplay = true;
el.setAttribute('playsinline', '');
el.setAttribute('aria-label', title);
}
el.className = 'vs-embed';
box.appendChild(el);
box.classList.add('is-playing');
if (el.focus) el.focus();
}
btn.addEventListener('click', start);
});
})();
(function () {
if (!window.gsap) return;
if (window.matchMedia && window.matchMedia('(prefers-reduced-motion: reduce)').matches) return;
if (window.ScrollTrigger) gsap.registerPlugin(ScrollTrigger);
var TEXT = window.SplitText ? {"split":"words","part":"words","mask":"words","vars":{"yPercent":110,"stagger":0.06,"duration":0.8}} : null;
if (TEXT) gsap.registerPlugin(SplitText);
function run() {
document.querySelectorAll('.st:not([data-scroll])').forEach(function (section) {
var heads = TEXT ? section.querySelectorAll('[data-anim-text]') : [];
var items = section.querySelectorAll(heads.length ? '[data-anim="item"]:not([data-anim-text])' : '[data-anim="item"]');
var media = section.querySelectorAll('[data-anim="media"]');
var tl = gsap.timeline({
defaults: { ease: 'power3.out', duration: 0.80 },
scrollTrigger: window.ScrollTrigger ? (window.ST_PREVIEW ? { trigger: section, start: 'top 80%', toggleActions: 'play reset play reset' } : { trigger: section, start: 'top 80%', once: true }) : undefined
});
Array.prototype.forEach.call(heads, function (el, i) {
var opts = { type: TEXT.split };
if (TEXT.mask) opts.mask = TEXT.mask;
var parts = SplitText.create(el, opts)[TEXT.part];
// The mask clips each line or word to its line box, which cuts off descenders (g, y, p):
// give the mask a little room below and take it back with a negative margin
if (TEXT.mask) Array.prototype.forEach.call(parts, function (p) { var m = p.parentElement; if (m && m !== el) { m.style.paddingBottom = '.22em'; m.style.marginBottom = '-.22em'; } });
tl.from(parts, Object.assign({}, TEXT.vars), i ? '<0.1' : 0);
});
if (items.length) tl.from(items, {"y":28,"opacity":0,"stagger":0.09,"clearProps":"transform,opacity"}, heads.length ? '<0.2' : 0);
if (media.length) tl.from(media, {"y":40,"opacity":0,"duration":1.1,"clearProps":"transform,opacity"}, items.length || heads.length ? '<0.15' : 0);
});
}
// Split text only after the fonts load, so lines break where they finally will
if (TEXT && document.fonts && document.fonts.ready) document.fonts.ready.then(run); else run();
})();
(function () {
var G = window.gsap, reduce = window.matchMedia && window.matchMedia('(prefers-reduced-motion: reduce)').matches;
if (!G || reduce || window.ST_STILL) return;
if (window.ScrollTrigger) G.registerPlugin(ScrollTrigger);
document.querySelectorAll('.st-art[data-art-anim]').forEach(function (layer) {
var mode = layer.getAttribute('data-art-anim'), sec = layer.closest('.st'), svg = layer.querySelector('svg');
if (mode === 'float') layer.querySelectorAll('[data-float]').forEach(function (el, i) {
G.to(el, { x: (i % 3 - 1) * 24, y: (i % 2 ? -1 : 1) * 22, duration: 5 + (i % 3), ease: 'sine.inOut', yoyo: true, repeat: -1, delay: i * 0.4 });
});
if (mode === 'spin') layer.querySelectorAll('[data-spin]').forEach(function (el, i) {
G.to(el, { rotation: i % 2 ? -360 : 360, duration: 60 + i * 8, ease: 'none', repeat: -1, transformOrigin: '50% 50%' });
});
if (mode === 'draw' && window.ScrollTrigger) layer.querySelectorAll('[data-draw]').forEach(function (p, i) {
var len = p.getTotalLength ? p.getTotalLength() : 0;
if (!len) return;
G.fromTo(p, { strokeDasharray: len, strokeDashoffset: len }, { strokeDashoffset: 0, ease: 'none', scrollTrigger: { trigger: sec, start: 'top 90%', end: 'bottom 40%', scrub: 0.6 } });
});
if (mode === 'parallax' && window.ScrollTrigger && svg) {
G.set(svg, { scale: 1.15 });
G.fromTo(svg, { yPercent: -6 }, { yPercent: 6, ease: 'none', scrollTrigger: { trigger: sec, start: 'top bottom', end: 'bottom top', scrub: true } });
}
});
})();




