Hair & Beauty Salon Website HTML Template — Free Snippet
Hair & Beauty Salon Website template · 12 website sections · Plain HTML, CSS & JS · Customise it in the Website Builder
Copy & paste
Source Code
<section class="st st-navbar-simple" data-uid="smvw6s7vyz5l3">
<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="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>Bloom Studio</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="#menu"><span>Services</span></a></li>
<li data-menu-item><a class="nb-link" href="#team"><span>Stylists</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>Visit</span></a></li>
</ul>
<div class="nb-actions" data-menu-item>
<a class="st-btn nb-cta" href="#contact"><span>Book now</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="smvw6s7vyj3sp">
<div class="ib-bg" role="img" aria-label="Background photo" style="background-image:url('https://webdevpuneet.com/images/section-templates/tpl-salon.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">Hair · Colour · Beauty · Hackney</span>
<h1 class="ib-title" data-anim="item" data-anim-text>Leave feeling <span class="hl">like yourself, only better</span></h1>
<p class="st-lead ib-lead" data-anim="item">Cuts, colour and care from a friendly team who listen first. Open late on Thursdays and Fridays.</p>
<div class="st-btns" data-anim="item">
<a class="st-btn" href="#contact"><span>Book an appointment</span></a>
<a class="st-btn st-btn--ghost ib-ghost" href="#menu"><span>Services & prices</span></a>
</div>
</div>
<div class="ib-stats" data-anim="media">
<div><strong>4.9★</strong><span>Google rating</span></div>
<div><strong>12</strong><span>stylists</span></div>
<div><strong>Since 2012</strong><span>in Hackney</span></div>
</div>
</div>
</section>
<section id="menu" class="st st-restaurant-menu" data-uid="smvw6s7vyhalo">
<div class="st-art" aria-hidden="true" style="color:var(--st-brand);opacity:0.08" data-art-anim="float"><svg viewBox="0 0 1200 800" preserveAspectRatio="xMidYMid slice"><defs><filter id="art-blur-smvw6s7vyhalo" x="-50%" y="-50%" width="200%" height="200%"><feGaussianBlur stdDeviation="60"/></filter></defs><g filter="url(#art-blur-smvw6s7vyhalo)" fill="currentColor"><circle data-float cx="180" cy="160" r="190"/><circle data-float cx="1040" cy="260" r="220"/><circle data-float cx="640" cy="720" r="200"/></g></svg></div>
<div class="st-wrap">
<header class="st-head">
<p class="st-eyebrow" data-anim="item">Services & prices</p>
<h2 class="st-h2" data-anim="item" data-anim-text>Cut, colour <span class="hl">and care</span></h2>
<p class="st-lead" data-anim="item">Every appointment starts with a consultation. Prices vary with hair length and stylist level.</p>
</header>
<ul class="rm-list">
<li class="rm-dish" data-anim="item">
<div class="rm-line">
<span class="rm-name">Cut & finish</span>
<span class="rm-dots" aria-hidden="true"></span>
<span class="rm-price">from £55</span>
</div>
<p class="rm-desc">Wash, cut, blow-dry and styling advice.</p>
</li>
<li class="rm-dish" data-anim="item">
<div class="rm-line">
<span class="rm-name">Men’s cut</span>
<span class="rm-dots" aria-hidden="true"></span>
<span class="rm-price">from £32</span>
</div>
<p class="rm-desc">Scissor or clipper cut with a hot towel finish.</p>
</li>
<li class="rm-dish" data-anim="item">
<div class="rm-line">
<span class="rm-name">Full colour</span>
<span class="rm-dots" aria-hidden="true"></span>
<span class="rm-price">from £85</span>
</div>
<p class="rm-desc">Root-to-tip colour with a gloss and finish.</p>
</li>
<li class="rm-dish" data-anim="item">
<div class="rm-line">
<span class="rm-name">Balayage</span>
<span class="rm-tag">Most booked</span>
<span class="rm-dots" aria-hidden="true"></span>
<span class="rm-price">from £140</span>
</div>
<p class="rm-desc">Hand-painted, sun-kissed highlights.</p>
</li>
<li class="rm-dish" data-anim="item">
<div class="rm-line">
<span class="rm-name">Blow-dry</span>
<span class="rm-dots" aria-hidden="true"></span>
<span class="rm-price">£35</span>
</div>
<p class="rm-desc">Smooth, bouncy or curly: your choice.</p>
</li>
<li class="rm-dish" data-anim="item">
<div class="rm-line">
<span class="rm-name">Gloss treatment</span>
<span class="rm-tag">New</span>
<span class="rm-dots" aria-hidden="true"></span>
<span class="rm-price">£40</span>
</div>
<p class="rm-desc">Shine and tone refresh between colours.</p>
</li>
</ul>
<div class="rm-foot" data-anim="item">
<p class="rm-note">Free colour consultation and patch test 48 hours before any colour service.</p>
<a class="st-btn" href="#contact"><span>Book online</span></a>
</div>
</div>
</section>
<section id="zoom" class="st st-scroll-zoom" data-uid="smvw6s7vzmlw0">
<div class="st-wrap">
<header class="st-head">
<p class="st-eyebrow" data-anim="item">The studio</p>
<h2 class="st-h2" data-anim="item" data-anim-text>A calm place <span class="hl">to take your time</span></h2>
<p class="st-lead" data-anim="item">Soft light, arched mirrors and chairs by the window. Keep scrolling: each room arrives as a small photograph and zooms up to fill the screen, one after another.</p>
</header>
<div class="zs" data-zs data-zoom="45" data-dir="in" data-affect="both" data-per="100" data-smooth="0.6" data-drift="on">
<ul class="zs-list">
<li class="zs-layer">
<img class="zs-img" width="1600" height="900" loading="lazy" src="https://webdevpuneet.com/images/section-templates/tpl-salon.jpg" alt="A bright salon with arched mirrors">
<div class="zs-cap">
<h3 class="zs-title">Inside Bloom Studio</h3>
<p class="zs-text">Soft light and arched mirrors</p>
</div>
</li>
<li class="zs-layer">
<img class="zs-img" width="1600" height="900" loading="lazy" src="https://webdevpuneet.com/images/section-templates/room-1.jpg" alt="A bright room with tall windows and soft light">
<div class="zs-cap">
<h3 class="zs-title">The colour bar</h3>
<p class="zs-text">Where every colour starts with a chat</p>
</div>
</li>
<li class="zs-layer">
<img class="zs-img" width="1600" height="900" loading="lazy" src="https://webdevpuneet.com/images/section-templates/room-2.jpg" alt="A calm room with natural light">
<div class="zs-cap">
<h3 class="zs-title">The quiet room</h3>
<p class="zs-text">Treatments without the noise</p>
</div>
</li>
<li class="zs-layer">
<img class="zs-img" width="1600" height="900" loading="lazy" src="https://webdevpuneet.com/images/section-templates/room-4.jpg" alt="A warm room with wooden floors">
<div class="zs-cap">
<h3 class="zs-title">The window seats</h3>
<p class="zs-text">Tea while the colour sets</p>
</div>
</li>
</ul>
<div class="zs-ui" aria-hidden="true"><span class="zs-count">01</span><span class="zs-bar"><i></i></span></div>
</div>
</div>
</section>
<section id="gallery" class="st st-before-after-slider" data-uid="smvw6s7vznr2g">
<div class="st-wrap">
<header class="st-head">
<p class="st-eyebrow" data-anim="item">Results</p>
<h2 class="st-h2" data-anim="item" data-anim-text>Colour and cut, <span class="hl">before and after</span></h2>
<p class="st-lead" data-anim="item">Drag the handle to see what a consultation, a colour and a cut can do. Shared with our clients’ permission.</p>
</header>
<ul class="ba-grid">
<li class="ba-item" data-anim="item">
<div class="ba-compare" data-compare>
<img class="ba-img ba-after" width="1200" height="800" loading="lazy" src="https://webdevpuneet.com/images/section-templates/room-4.jpg" alt="After photo (sample image)">
<img class="ba-img ba-before" width="1200" height="800" loading="lazy" src="https://webdevpuneet.com/images/section-templates/room-2.jpg" alt="Before photo (sample image)">
<span class="ba-tag ba-tag-before">Before</span>
<span class="ba-tag ba-tag-after">After</span>
<span class="ba-handle" aria-hidden="true"><span class="ba-knob"><svg viewBox="0 0 24 24" width="22" height="22" fill="none" stroke="currentColor" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round"><path d="m9 7-5 5 5 5M15 7l5 5-5 5"/></svg></span></span>
<input class="ba-range" type="range" min="0" max="100" value="50" aria-label="Drag to compare before and after">
</div>
<h3 class="ba-title">Warm balayage refresh</h3>
<p class="ba-cap">Three hours with Amara, including a gloss and a blow-dry.</p>
</li>
<li class="ba-item" data-anim="item">
<div class="ba-compare" data-compare>
<img class="ba-img ba-after" width="1200" height="800" loading="lazy" src="https://webdevpuneet.com/images/section-templates/wed-dinner.jpg" alt="After photo (sample image)">
<img class="ba-img ba-before" width="1200" height="800" loading="lazy" src="https://webdevpuneet.com/images/section-templates/tpl-restaurant.jpg" alt="Before photo (sample image)">
<span class="ba-tag ba-tag-before">Before</span>
<span class="ba-tag ba-tag-after">After</span>
<span class="ba-handle" aria-hidden="true"><span class="ba-knob"><svg viewBox="0 0 24 24" width="22" height="22" fill="none" stroke="currentColor" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round"><path d="m9 7-5 5 5 5M15 7l5 5-5 5"/></svg></span></span>
<input class="ba-range" type="range" min="0" max="100" value="50" aria-label="Drag to compare before and after">
</div>
<h3 class="ba-title">Layered cut with movement</h3>
<p class="ba-cap">A restyle with soft layers that dries well at home.</p>
</li>
</ul>
</div>
</section>
<section id="team" class="st st-team-accordion" data-uid="smvw6s7vzt2gd">
<div class="st-wrap">
<header class="st-head">
<p class="st-eyebrow" data-anim="item">The team</p>
<h2 class="st-h2" data-anim="item" data-anim-text>Meet the <span class="hl">hands behind Bloom</span></h2>
<p class="st-lead" data-anim="item">Click a stylist to read about their speciality and how they like to work.</p>
</header>
<div class="ta" data-ta data-open="1" data-gray="on">
<ul class="ta-strips">
<li class="ta-item" data-anim="item">
<button type="button" class="ta-trigger" aria-expanded="false" aria-label="Amara Osei"></button>
<div class="ta-info">
<div class="ta-inner">
<h3 class="ta-name">Amara Osei</h3>
<p class="ta-role">Founder & Creative Director</p>
<div class="ta-social">
</div>
<p class="ta-bio">Colour specialist with 18 years of experience.</p>
</div>
</div>
<div class="ta-photo"><img width="600" height="800" loading="lazy" src="https://webdevpuneet.com/images/section-templates/avatar-2.jpg" alt="Amara Osei"></div>
</li>
<li class="ta-item" data-anim="item">
<button type="button" class="ta-trigger" aria-expanded="false" aria-label="Theo Grant"></button>
<div class="ta-info">
<div class="ta-inner">
<h3 class="ta-name">Theo Grant</h3>
<p class="ta-role">Senior Stylist</p>
<div class="ta-social">
</div>
<p class="ta-bio">Precision cuts and men’s grooming.</p>
</div>
</div>
<div class="ta-photo"><img width="600" height="800" loading="lazy" src="https://webdevpuneet.com/images/section-templates/avatar-4.jpg" alt="Theo Grant"></div>
</li>
<li class="ta-item" data-anim="item">
<button type="button" class="ta-trigger" aria-expanded="false" aria-label="Lucia Romano"></button>
<div class="ta-info">
<div class="ta-inner">
<h3 class="ta-name">Lucia Romano</h3>
<p class="ta-role">Colourist</p>
<div class="ta-social">
</div>
<p class="ta-bio">Balayage and lived-in blondes.</p>
</div>
</div>
<div class="ta-photo"><img width="600" height="800" loading="lazy" src="https://webdevpuneet.com/images/section-templates/avatar-5.jpg" alt="Lucia Romano"></div>
</li>
<li class="ta-item" data-anim="item">
<button type="button" class="ta-trigger" aria-expanded="false" aria-label="Mei Tanaka"></button>
<div class="ta-info">
<div class="ta-inner">
<h3 class="ta-name">Mei Tanaka</h3>
<p class="ta-role">Beauty Therapist</p>
<div class="ta-social">
</div>
<p class="ta-bio">Brows, lashes and skin.</p>
</div>
</div>
<div class="ta-photo"><img width="600" height="800" loading="lazy" src="https://webdevpuneet.com/images/section-templates/avatar-8.jpg" alt="Mei Tanaka"></div>
</li>
</ul>
</div>
</div>
</section>
<section id="customers" class="st st-reviews-summary" data-uid="smvw6s7vzh0vy">
<div class="st-wrap">
<header class="st-head">
<p class="st-eyebrow" data-anim="item">Client love</p>
<h2 class="st-h2" data-anim="item" data-anim-text>Rated <span class="hl">4.9 out of 5</span> by our clients</h2>
<p class="st-lead" data-anim="item">Kind words from regulars and first-timers. Tap a bar to read only the reviews with that rating.</p>
</header>
<div class="rs" data-revfilter data-filter-text="Showing {n} of {t} reviews rated {s} stars" data-clear-label="Show all reviews">
<aside class="rs-sum" data-anim="item">
<p class="rs-score"><span class="rs-avg">4.9</span><span class="rs-of">/5</span></p>
<span class="rs-stars rs-stars--big" style="--r:4.9" role="img" aria-label="Rated 4.9 out of 5">★★★★★</span>
<p class="rs-count"><span>640</span> <span>Google reviews</span></p>
<ul class="rs-bars">
<li class="rs-bar">
<button type="button" class="rs-barbtn" data-filter-star aria-pressed="false" data-star="5" aria-label="Show only {s}-star reviews">
<span class="rs-lab"><span>5</span>★</span>
<span class="rs-track"><span class="rs-fill" style="--w:92%"></span></span>
<span class="rs-n">590</span>
</button>
</li>
<li class="rs-bar">
<button type="button" class="rs-barbtn" data-filter-star aria-pressed="false" data-star="4" aria-label="Show only {s}-star reviews">
<span class="rs-lab"><span>4</span>★</span>
<span class="rs-track"><span class="rs-fill" style="--w:6%"></span></span>
<span class="rs-n">38</span>
</button>
</li>
<li class="rs-bar">
<button type="button" class="rs-barbtn" data-filter-star aria-pressed="false" data-star="3" aria-label="Show only {s}-star reviews">
<span class="rs-lab"><span>3</span>★</span>
<span class="rs-track"><span class="rs-fill" style="--w:1%"></span></span>
<span class="rs-n">8</span>
</button>
</li>
<li class="rs-bar">
<button type="button" class="rs-barbtn" data-filter-star aria-pressed="false" data-star="2" aria-label="Show only {s}-star reviews">
<span class="rs-lab"><span>2</span>★</span>
<span class="rs-track"><span class="rs-fill" style="--w:0%"></span></span>
<span class="rs-n">3</span>
</button>
</li>
<li class="rs-bar">
<button type="button" class="rs-barbtn" data-filter-star aria-pressed="false" data-star="1" aria-label="Show only {s}-star reviews">
<span class="rs-lab"><span>1</span>★</span>
<span class="rs-track"><span class="rs-fill" style="--w:0%"></span></span>
<span class="rs-n">1</span>
</button>
</li>
</ul>
<a class="st-btn" href="#contact"><span>Leave a review</span></a>
</aside>
<div class="rs-main">
<p class="rs-status" data-filter-status role="status" hidden><span data-filter-message></span> <button type="button" class="rs-clear" data-filter-clear></button></p>
<ul class="rs-list">
<li class="rs-card" data-anim="item" data-rating="5">
<div class="rs-top"><span class="rs-stars" style="--r:5" role="img" aria-label="Rated 5 out of 5">★★★★★</span><span class="rs-date">October 2026</span></div>
<h3 class="rs-title">Finally the right colour</h3>
<p class="rs-text">Amara finally got my colour right after years of trying elsewhere. I leave smiling every time.</p>
<div class="rs-by">
<img class="rs-av" src="https://webdevpuneet.com/images/section-templates/avatar-3.jpg" alt="">
<span class="rs-name">Jess P.</span>
<span class="rs-badge"><span aria-hidden="true">✓</span> <span>Verified client</span></span>
</div>
</li>
<li class="rs-card" data-anim="item" data-rating="5">
<div class="rs-top"><span class="rs-stars" style="--r:5" role="img" aria-label="Rated 5 out of 5">★★★★★</span><span class="rs-date">September 2026</span></div>
<h3 class="rs-title">Best fade in East London</h3>
<p class="rs-text">Best fade in East London, and they always remember how I like it.</p>
<div class="rs-by">
<img class="rs-av" src="https://webdevpuneet.com/images/section-templates/avatar-7.jpg" alt="">
<span class="rs-name">Kwame A.</span>
<span class="rs-badge"><span aria-hidden="true">✓</span> <span>Verified client</span></span>
</div>
</li>
<li class="rs-card" data-anim="item" data-rating="5">
<div class="rs-top"><span class="rs-stars" style="--r:5" role="img" aria-label="Rated 5 out of 5">★★★★★</span><span class="rs-date">September 2026</span></div>
<h3 class="rs-title">Exactly what I asked for</h3>
<p class="rs-text">Warm, relaxed and so talented. The balayage is exactly what I asked for.</p>
<div class="rs-by">
<img class="rs-av" src="https://webdevpuneet.com/images/section-templates/avatar-6.jpg" alt="">
<span class="rs-name">Sofia L.</span>
<span class="rs-badge"><span aria-hidden="true">✓</span> <span>Verified client</span></span>
</div>
</li>
<li class="rs-card" data-anim="item" data-rating="4">
<div class="rs-top"><span class="rs-stars" style="--r:4" role="img" aria-label="Rated 4 out of 5">★★★★★</span><span class="rs-date">August 2026</span></div>
<p class="rs-text">Lovely studio and a great cut. Popular days book up quickly, so plan ahead.</p>
<div class="rs-by">
<img class="rs-av" src="https://webdevpuneet.com/images/section-templates/avatar-2.jpg" alt="">
<span class="rs-name">Nadia R.</span>
<span class="rs-badge"><span aria-hidden="true">✓</span> <span>Verified client</span></span>
</div>
</li>
<li class="rs-card" data-anim="item" data-rating="5">
<div class="rs-top"><span class="rs-stars" style="--r:5" role="img" aria-label="Rated 5 out of 5">★★★★★</span><span class="rs-date">August 2026</span></div>
<h3 class="rs-title">A calm place</h3>
<p class="rs-text">Nobody rushes you here. Tea, a chat and a cut I did not have to fix at home.</p>
<div class="rs-by">
<img class="rs-av" src="https://webdevpuneet.com/images/section-templates/avatar-4.jpg" alt="">
<span class="rs-name">Chris M.</span>
<span class="rs-badge"><span aria-hidden="true">✓</span> <span>Verified client</span></span>
</div>
</li>
<li class="rs-card" data-anim="item" data-rating="3">
<div class="rs-top"><span class="rs-stars" style="--r:3" role="img" aria-label="Rated 3 out of 5">★★★★★</span><span class="rs-date">July 2026</span></div>
<h3 class="rs-title">Great result, long wait</h3>
<p class="rs-text">Beautiful colour, though my appointment started a little late. Worth it in the end.</p>
<div class="rs-by">
<img class="rs-av" src="https://webdevpuneet.com/images/section-templates/avatar-5.jpg" alt="">
<span class="rs-name">Beth O.</span>
<span class="rs-badge"><span aria-hidden="true">✓</span> <span>Verified client</span></span>
</div>
</li>
</ul>
</div>
</div>
</div>
</section>
<section id="contact" class="st st-booking-form" data-uid="smvw6s7vzzm7b">
<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</p>
<h2 class="st-h2" data-anim="item" data-anim-text>Request <span class="hl">your appointment</span></h2>
<p class="st-lead" data-anim="item">Choose the service, the day and a time that suits you. We confirm every request by text or email.</p>
</header>
<div class="bk-block" data-anim="item">
<h3 class="bk-sub">Opening hours</h3>
<dl class="bk-hours">
<div class="bk-row"><dt>Tuesday – Wednesday</dt><dd>9:30 am – 6:00 pm</dd></div>
<div class="bk-row"><dt>Thursday – Friday</dt><dd>9:30 am – 8:00 pm</dd></div>
<div class="bk-row"><dt>Saturday</dt><dd>9:00 am – 5:00 pm</dd></div>
<div class="bk-row"><dt>Sunday – Monday</dt><dd>Closed</dd></div>
</dl>
</div>
<div class="bk-block" data-anim="item">
<h3 class="bk-sub">Before you come</h3>
<ul class="st-checks"><li>Every visit starts with a free consultation</li><li>Patch tests are done 48 hours before colour</li><li>Free cancellation up to 24 hours before</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>Service</span><select name="service" required>
<option value="Consultation">Consultation</option>
<option value="Cut and blow-dry">Cut and blow-dry</option>
<option value="Colour">Colour</option>
<option value="Balayage">Balayage</option>
<option value="Treatment">Treatment</option>
</select></label>
<div class="st-form-row">
<label class="st-field"><span>Preferred day</span><input name="date" type="date" required data-booking-date></label>
<label class="st-field"><span>Preferred time</span><select name="time" required>
<option value="Morning (9 am – 12 pm)">Morning (9 am – 12 pm)</option>
<option value="Lunchtime (12 pm – 2 pm)">Lunchtime (12 pm – 2 pm)</option>
<option value="Afternoon (2 pm – 5 pm)">Afternoon (2 pm – 5 pm)</option>
<option value="Evening (after 5 pm)">Evening (after 5 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 appointment</span></button>
<p class="st-form-note">This is a request, not a confirmed booking. We reply to confirm.</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 confirm your appointment by email shortly.</p>
</div>
</form>
</div>
</div>
</section>
<section id="contact-2" class="st st-opening-hours" data-uid="smvw6s7vzxmj5">
<div class="st-wrap">
<header class="st-head">
<p class="st-eyebrow" data-anim="item">Visit</p>
<h2 class="st-h2" data-anim="item" data-anim-text>Find <span class="hl">the studio</span></h2>
<p class="st-lead" data-anim="item">On Broadway Market, two minutes from London Fields.</p>
</header>
<div class="oh" data-opennow data-tz="Europe/London" data-open-label="Open now" data-closes-label="closes at" data-shut-label="Closed now" data-opens-label="opens">
<div class="oh-card oh-hours" data-anim="item">
<div class="oh-top">
<h3 class="oh-title">Opening hours</h3>
<p class="oh-badge" data-open-badge role="status" hidden><span class="oh-dot" aria-hidden="true"></span><span class="oh-badge-text"></span></p>
</div>
<ol class="oh-list">
<li class="oh-row" data-hours-row data-day="Monday" data-open="09:00" data-close="17:00" data-closed="closed">
<span class="oh-day">Monday</span>
<span class="oh-shut">Closed</span>
</li>
<li class="oh-row" data-hours-row data-day="Tuesday" data-open="09:30" data-close="18:00" data-closed="">
<span class="oh-day">Tuesday</span>
<span class="oh-time"><time>09:30</time> <span aria-hidden="true">–</span> <time>18:00</time></span>
</li>
<li class="oh-row" data-hours-row data-day="Wednesday" data-open="09:30" data-close="18:00" data-closed="">
<span class="oh-day">Wednesday</span>
<span class="oh-time"><time>09:30</time> <span aria-hidden="true">–</span> <time>18:00</time></span>
</li>
<li class="oh-row" data-hours-row data-day="Thursday" data-open="09:30" data-close="20:00" data-closed="">
<span class="oh-day">Thursday</span>
<span class="oh-time"><time>09:30</time> <span aria-hidden="true">–</span> <time>20:00</time></span>
<span class="oh-note">Late night</span>
</li>
<li class="oh-row" data-hours-row data-day="Friday" data-open="09:30" data-close="20:00" data-closed="">
<span class="oh-day">Friday</span>
<span class="oh-time"><time>09:30</time> <span aria-hidden="true">–</span> <time>20:00</time></span>
<span class="oh-note">Late night</span>
</li>
<li class="oh-row" data-hours-row data-day="Saturday" data-open="09:00" data-close="17:00" data-closed="">
<span class="oh-day">Saturday</span>
<span class="oh-time"><time>09:00</time> <span aria-hidden="true">–</span> <time>17:00</time></span>
</li>
<li class="oh-row" data-hours-row data-day="Sunday" data-open="09:00" data-close="17:00" data-closed="closed">
<span class="oh-day">Sunday</span>
<span class="oh-shut">Closed</span>
</li>
</ol>
<p class="oh-special">Walk-ins are welcome when there is a free chair. Booking is the best way to get your stylist.</p>
</div>
<div class="oh-side">
<div class="oh-map" data-anim="media">
<iframe class="oh-frame" loading="lazy" referrerpolicy="no-referrer-when-downgrade" src="https://www.openstreetmap.org/export/embed.html?bbox=-0.0663%2C51.5341%2C-0.0563%2C51.5391&layer=mapnik&marker=51.5366%2C-0.0613" title="Map showing Bloom Studio on Broadway Market"></iframe>
</div>
<div class="oh-card oh-contact" data-anim="item">
<ul class="oh-info">
<li class="oh-item"><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>
<address class="oh-addr">
<span class="oh-line oh-name">Bloom Studio</span>
<span class="oh-line">41 Broadway Market</span>
<span class="oh-line"><span>E8 4PH</span> <span>London</span></span>
<span class="oh-line">United Kingdom</span>
</address>
</li>
<li class="oh-item"><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="M22 16.92v3a2 2 0 0 1-2.18 2 19.79 19.79 0 0 1-8.63-3.07 19.5 19.5 0 0 1-6-6 19.79 19.79 0 0 1-3.07-8.67A2 2 0 0 1 4.11 2h3a2 2 0 0 1 2 1.72 12.84 12.84 0 0 0 .7 2.81 2 2 0 0 1-.45 2.11L8.09 9.91a16 16 0 0 0 6 6l1.27-1.27a2 2 0 0 1 2.11-.45 12.84 12.84 0 0 0 2.81.7A2 2 0 0 1 22 16.92z" /></svg></span><a class="oh-link" href="tel:+442079460456">020 7946 0456</a></li>
<li class="oh-item"><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"><rect width="20" height="16" x="2" y="4" rx="2" /><path d="m22 7-8.97 5.7a1.94 1.94 0 0 1-2.06 0L2 7" /></svg></span><a class="oh-link" href="mailto:[email protected]">[email protected]</a></li>
</ul>
<div class="st-btns">
<a class="st-btn" href="https://www.google.com/maps/search/?api=1&query=41%20Broadway%20Market%2C%20London%20E8%204PH"><span>Get directions</span></a>
<a class="st-btn st-btn--ghost" href="tel:+442079460456"><span>Call to book</span></a>
</div>
</div>
</div>
</div>
</div>
</section>
<section class="st st-popup-modal" data-uid="smvw6s7vz36oz">
<div class="pu" data-pu data-trigger="delay" data-delay="10" data-scroll="50" data-days="7" data-pos="bottom-right" data-layout="left" data-autoplay="0" data-pu-id="1pcpcek">
<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-salon.jpg" alt="A stylist at work in the salon">
</div>
<div class="pu-body">
<p class="st-eyebrow">New clients</p>
<h2 class="pu-h" id="pu-heading"><span class="hl">20% off</span> your first visit</h2>
<p class="pu-lead">Book a cut, colour or treatment this month and your first visit is on us.</p>
<div class="pu-ctas">
<a class="st-btn pu-cta" href="#contact"><span>Book now</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="smvw6s7vzxgje">
<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="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>Bloom Studio</span></span>
</a>
<nav aria-label="Footer"><ul class="fm-links"><li><a href="#menu">Services</a></li><li><a href="#team">Stylists</a></li><li><a href="#customers">Reviews</a></li><li><a href="#contact">Book</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 Bloom Studio</p>
</footer>
</section>
<section class="st st-back-to-top" data-uid="smvw6s7vzodbe">
<div class="btt" data-btt data-enabled="on" data-distance="500" data-pos="right" data-appear="fade" data-speed="0.8" data-mobile="on" data-shadow="on" style="--btt-size:52px;--btt-off:24px;--btt-radius:50%;--btt-speed:0.8s">
<div class="btt-demo" aria-hidden="true">
<span class="btt-bar btt-bar--lg"></span><span class="btt-bar"></span><span class="btt-bar btt-bar--md"></span><span class="btt-bar"></span><span class="btt-bar btt-bar--sm"></span>
<span class="btt-note">The button appears here once the page has scrolled</span>
</div><!--/btt-demo-->
<button type="button" class="btt-btn" aria-label="Back to top" title="Back to top"><svg class="btt-svg" viewBox="0 0 24 24" width="24" height="24" fill="none" stroke="currentColor" stroke-width="2.400" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" focusable="false"><path d="M12 19V5M5 12l7-7 7 7"/></svg></button>
</div>
</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:#fff8f7}
html{scroll-behavior:smooth}section[id]{scroll-margin-top:84px}
@media (prefers-reduced-motion:reduce){html{scroll-behavior:auto}}
.st{--st-brand:#be185d;--st-btn-text:#ffffff;--st-bg:#fff8f7;--st-surface:#f8e9e6;--st-text:#3b1d24;--st-muted:#7b5960;--st-radius:18;--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)}}
/* Restaurant Menu */
.st-restaurant-menu{padding:clamp(64px,8cqi,112px) 0}
.rm-list{list-style:none;display:grid;grid-template-columns:1fr 1fr;gap:clamp(24px,3cqi,36px) clamp(32px,6cqi,80px);max-width:1040px;margin:0 auto}
.rm-dish{display:flex;flex-direction:column;gap:6px}
.rm-line{display:flex;align-items:baseline;gap:10px}
.rm-name{font:700 clamp(18px,.6cqi + 14px,21px)/1.3 var(--st-font-heading)}
.rm-tag{flex:none;padding:2px 8px;border-radius:999px;background:color-mix(in srgb,var(--st-brand) 14%,transparent);color:var(--st-brand);font-size:11.5px;font-weight:700;letter-spacing:.04em}
.rm-dots{flex:1;min-width:24px;border-bottom:2px dotted color-mix(in srgb,var(--st-text) 28%,transparent);transform:translateY(-5px)}
.rm-price{flex:none;font:700 18px/1 var(--st-font-heading);color:var(--st-brand)}
.rm-desc{color:var(--st-muted);font-size:15.5px;line-height:1.55;max-width:34em}
.rm-foot{display:flex;flex-direction:column;align-items:center;gap:18px;margin-top:clamp(40px,5cqi,64px);text-align:center}
.rm-note{color:var(--st-muted);font-size:14px;max-width:44em}
@container st (max-width:720px){.rm-list{grid-template-columns:1fr}}
/* Scroll Zoom Image Stack (Ken Burns) */
.st-scroll-zoom{padding:clamp(56px,7cqi,104px) 0}
.zs{position:relative}
.zs-list{list-style:none;display:grid;gap:clamp(16px,2.4cqi,28px);margin:0;padding:0}
.zs-layer{position:relative;overflow:hidden;aspect-ratio:16/9;border-radius:calc(var(--st-radius) * 1.2px);background:var(--st-surface)}
.zs-img{display:block;width:100%;height:100%;object-fit:cover;transform-origin:50% 50%;will-change:transform}
.zs-cap{position:absolute;left:0;right:0;bottom:0;padding:clamp(40px,8cqi,96px) clamp(18px,3cqi,40px) clamp(18px,3cqi,36px);background:linear-gradient(to top,rgba(6,9,13,.78),rgba(6,9,13,0));color:#fff;pointer-events:none}
.zs-title{font-size:clamp(22px,2.6cqi + 8px,40px);color:#fff;letter-spacing:-.02em}
.zs-text{margin-top:6px;color:rgba(255,255,255,.82);font-size:clamp(14px,1cqi + 10px,18px)}
.zs-text:empty{display:none}
.zs-ui{display:none}
.zs.is-zs .zs-list{display:block;position:relative;height:clamp(420px,calc(100vh - 170px),760px);gap:0;overflow:hidden;border-radius:calc(var(--st-radius) * 1.2px);background:var(--st-surface);box-shadow:0 30px 70px -30px rgba(0,0,0,.6)}
.zs.is-zs .zs-layer{position:absolute;inset:0;aspect-ratio:auto;border-radius:0;will-change:transform;transform-origin:50% 50%}
.zs.is-zs .zs-ui{position:absolute;right:clamp(16px,3cqi,32px);bottom:clamp(16px,3cqi,32px);z-index:60;display:flex;align-items:center;gap:12px;color:#fff;font:700 13px/1 var(--st-font-heading);letter-spacing:.08em}
.zs-bar{display:block;width:clamp(60px,10cqi,120px);height:3px;border-radius:2px;background:rgba(255,255,255,.3);overflow:hidden}
.zs-bar i{display:block;width:100%;height:100%;background:#fff;transform:scaleX(0);transform-origin:0 50%}
/* The frozen frame used for previews and thumbnails: no heading, just the stack part way through its zoom */
.st-scroll-zoom:has(.zs.is-zs-still) .st-head{display:none}
@container st (max-width:560px){.zs.is-zs .zs-list{height:clamp(380px,calc(100vh - 150px),620px)}.zs-layer{aspect-ratio:4/3}}
/* Before & After Slider */
.st-before-after-slider{padding:clamp(56px,7cqi,104px) 0}
.ba-grid{list-style:none;display:grid;grid-template-columns:repeat(auto-fit,minmax(min(100%,420px),1fr));gap:clamp(24px,3cqi,40px)}
.ba-item{display:flex;flex-direction:column;gap:8px}
.ba-compare{--pos:50%;position:relative;overflow:hidden;aspect-ratio:3/2;margin-bottom:8px;border-radius:calc(var(--st-radius) * 1px);background:var(--st-surface);box-shadow:0 30px 60px -36px color-mix(in srgb,var(--st-text) 55%,transparent);touch-action:pan-y;user-select:none}
.ba-img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;pointer-events:none}
.ba-before{clip-path:inset(0 calc(100% - var(--pos)) 0 0)}
.ba-tag{position:absolute;top:14px;padding:5px 12px;border-radius:999px;background:rgba(10,12,20,.62);color:#fff;font:700 12.5px/1 var(--st-font-body);letter-spacing:.04em;text-transform:uppercase;backdrop-filter:blur(4px);pointer-events:none}
.ba-tag-before{left:14px}
.ba-tag-after{right:14px}
.ba-handle{position:absolute;top:0;bottom:0;left:var(--pos);width:3px;margin-left:-1.5px;background:#fff;box-shadow:0 0 0 1px rgba(10,12,20,.12);pointer-events:none}
.ba-knob{position:absolute;top:50%;left:50%;display:grid;place-items:center;width:46px;height:46px;margin:-23px 0 0 -23px;border-radius:50%;background:#fff;color:var(--st-brand);box-shadow:0 8px 22px -6px rgba(10,12,20,.5)}
.ba-range{position:absolute;inset:0;width:100%;height:100%;margin:0;opacity:0;cursor:ew-resize;-webkit-appearance:none;appearance:none}
.ba-compare:has(.ba-range:focus-visible){outline:3px solid var(--st-brand);outline-offset:3px}
.ba-compare.is-static .ba-range{display:none}
.ba-compare.is-static .ba-handle{pointer-events:auto;cursor:ew-resize;touch-action:none}
.ba-compare.is-static .ba-handle::before{content:"";position:absolute;top:0;bottom:0;left:-18px;right:-18px}
.ba-title{font-size:19px;line-height:1.3;letter-spacing:-.015em}
.ba-cap{color:var(--st-muted);font-size:15.5px}
/* Interactive Team Accordion */
.st-team-accordion{padding:clamp(64px,8cqi,112px) 0;background:radial-gradient(60% 70% at 15% 20%,color-mix(in srgb,var(--st-brand) 14%,transparent),transparent 70%),radial-gradient(50% 60% at 90% 80%,color-mix(in srgb,#ec4899 12%,transparent),transparent 70%),var(--st-bg)}
.ta-strips{list-style:none;display:flex;gap:clamp(8px,1.2cqi,16px);height:clamp(380px,40cqi,500px);margin:0;padding:clamp(8px,1.2cqi,14px);border-radius:calc(var(--st-radius) * 1.4px);background:color-mix(in srgb,var(--st-surface) 78%,transparent);box-shadow:0 30px 70px -30px color-mix(in srgb,var(--st-text) 35%,transparent),0 0 0 1px color-mix(in srgb,var(--st-text) 6%,transparent)}
.ta-item{position:relative;display:flex;flex:1 1 0;min-width:0;overflow:hidden;border-radius:calc(var(--st-radius) * 1px);background:var(--st-surface);transition:flex-grow .65s cubic-bezier(.4,0,.2,1)}
.ta-item.is-open,.ta:not([data-ta-ready]) .ta-item:first-child{flex-grow:7}
.ta-trigger{position:absolute;inset:0;z-index:1;padding:0;border:0;background:transparent;cursor:pointer;border-radius:inherit}
.ta-item.is-open .ta-trigger{cursor:default}
.ta-trigger:focus-visible{outline:3px solid var(--st-brand);outline-offset:-4px}
.ta-info{position:relative;z-index:2;flex:0 1 0;min-width:0;overflow:hidden;visibility:hidden;opacity:0;transition:flex-grow .65s cubic-bezier(.4,0,.2,1),opacity .35s ease,visibility 0s .65s}
.ta-item.is-open .ta-info,.ta:not([data-ta-ready]) .ta-item:first-child .ta-info{flex-grow:1.15;visibility:visible;opacity:1;transition:flex-grow .65s cubic-bezier(.4,0,.2,1),opacity .45s ease .2s,visibility 0s}
.ta-inner{box-sizing:border-box;display:flex;flex-direction:column;justify-content:center;gap:10px;width:clamp(260px,26cqi,360px);height:100%;padding:clamp(22px,3cqi,40px)}
.ta-name{font-size:clamp(22px,2cqi + 8px,30px);letter-spacing:-.02em}
.ta-role{color:var(--st-brand);font-size:15px;font-weight:600}
.ta-social{display:flex;gap:8px;margin:4px 0 6px}
.ta-social a{display:grid;place-items:center;width:36px;height:36px;border-radius:50%;background:color-mix(in srgb,var(--st-brand) 12%,transparent);color:var(--st-brand);transition:background .2s ease,color .2s ease,transform .2s ease}
.ta-social a:hover{background:var(--st-brand);color:var(--st-btn-text);transform:translateY(-2px)}
.ta-social a:focus-visible{outline:3px solid var(--st-brand);outline-offset:2px}
.ta-social:not(:has(a:not([hidden]))){display:none}
.ta-social .st-icon{display:inline-grid;place-items:center;width:17px;height:17px}
.ta-social svg{width:17px;height:17px}
.ta-bio{color:var(--st-muted);font-size:15.5px;line-height:1.65}
.ta-bio:empty{display:none}
.ta-photo{position:relative;flex:1 1 0;min-width:0;background:var(--st-surface)}
.ta-photo img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;object-position:center 22%;transition:filter .5s ease,transform .8s ease}
.ta[data-gray=on] .ta-item:not(.is-open) .ta-photo img{filter:grayscale(1) contrast(1.05)}
.ta[data-gray=on]:not([data-ta-ready]) .ta-item:not(:first-child) .ta-photo img{filter:grayscale(1) contrast(1.05)}
.ta-item:not(.is-open):hover .ta-photo img{transform:scale(1.05)}
@container st (max-width:760px){
.ta-strips{flex-direction:column;height:clamp(600px,178cqi,830px)}
.ta-item{flex-direction:column;min-height:56px}
.ta-info{flex:0 1 0;width:100%}
.ta-item.is-open .ta-info,.ta:not([data-ta-ready]) .ta-item:first-child .ta-info{flex-grow:2.6}
.ta-inner{width:100%;gap:6px;padding:16px 20px;justify-content:flex-start;overflow-y:auto}
.ta-bio{font-size:14.5px;line-height:1.55}
.ta-photo{flex:1 1 0;min-height:96px}
.ta-photo img{object-position:center 18%}
}
@media (prefers-reduced-motion:reduce){.ta-item,.ta-info,.ta-photo img{transition:none}}
/* Reviews Summary & Rating */
.st-reviews-summary{padding:clamp(64px,8cqi,112px) 0}
.rs{display:grid;grid-template-columns:minmax(260px,.42fr) minmax(0,1fr);gap:clamp(22px,3.4cqi,48px);align-items:start}
.rs-sum{position:sticky;top:24px;display:flex;flex-direction:column;align-items:flex-start;gap:8px;padding:clamp(22px,2.6cqi,32px);border-radius:calc(var(--st-radius) * 1.2px);background:var(--st-surface);border:1px solid color-mix(in srgb,var(--st-text) 9%,transparent)}
.rs-score{display:flex;align-items:baseline;gap:6px}
.rs-avg{font:800 clamp(52px,6cqi,72px)/1 var(--st-font-heading);letter-spacing:-.03em}
.rs-of{color:var(--st-muted);font-size:20px;font-weight:600}
.rs-stars{--star:#f59e0b;--empty:color-mix(in srgb,var(--st-text) 18%,transparent);display:inline-block;font-size:18px;line-height:1;letter-spacing:1px;white-space:nowrap;background:linear-gradient(90deg,var(--star) calc(var(--r,0) / 5 * 100%),var(--empty) 0);-webkit-background-clip:text;background-clip:text;color:transparent}
.rs-stars--big{font-size:26px}
.rs-count{color:var(--st-muted);font-size:15px;margin-bottom:8px}
.rs-count span:first-child{color:var(--st-text);font-weight:700}
.rs-bars{list-style:none;display:grid;gap:4px;width:100%;margin-bottom:12px}
.rs-barbtn{display:grid;grid-template-columns:34px 1fr 44px;align-items:center;gap:10px;width:100%;padding:7px 8px;border:1px solid transparent;border-radius:10px;background:transparent;color:inherit;font:inherit;font-size:14px;text-align:left;cursor:pointer;transition:background .15s ease,border-color .15s ease}
.rs-barbtn:hover{background:color-mix(in srgb,var(--st-text) 6%,transparent)}
.rs-barbtn:focus-visible{outline:3px solid color-mix(in srgb,var(--st-brand) 55%,transparent);outline-offset:1px}
.rs-barbtn[aria-pressed=true]{background:color-mix(in srgb,var(--st-brand) 12%,transparent);border-color:color-mix(in srgb,var(--st-brand) 50%,transparent)}
.rs-lab{font-weight:700;white-space:nowrap}
.rs-lab::after{content:""}
.rs-track{position:relative;height:9px;border-radius:99px;background:color-mix(in srgb,var(--st-text) 11%,transparent);overflow:hidden}
.rs-fill{position:absolute;inset:0 auto 0 0;width:var(--w,0%);border-radius:99px;background:#f59e0b}
.rs-n{color:var(--st-muted);text-align:right;font-variant-numeric:tabular-nums}
.rs-status{display:flex;flex-wrap:wrap;align-items:center;gap:6px 12px;margin-bottom:14px;padding:10px 14px;border-radius:12px;background:color-mix(in srgb,var(--st-brand) 10%,transparent);font-size:14.5px;font-weight:600}
.rs-status[hidden]{display:none}
.rs-clear{padding:0;border:0;background:none;color:var(--st-brand);font:inherit;font-weight:700;text-decoration:underline;text-underline-offset:3px;cursor:pointer}
.rs-list{list-style:none;display:grid;gap:clamp(12px,1.6cqi,18px)}
.rs-card[hidden]{display:none}
.rs-card{display:flex;flex-direction:column;gap:8px;padding:clamp(18px,2.2cqi,26px);border-radius:calc(var(--st-radius) * 1.1px);background:var(--st-bg);border:1px solid color-mix(in srgb,var(--st-text) 10%,transparent)}
.rs-top{display:flex;align-items:center;justify-content:space-between;gap:10px}
.rs-date{color:var(--st-muted);font-size:13.5px}
.rs-title{font-size:17.5px}
.rs-text{color:var(--st-muted);font-size:15.5px;line-height:1.65}
.rs-by{display:flex;flex-wrap:wrap;align-items:center;gap:8px 12px;margin-top:4px}
.rs-av{width:38px;height:38px;border-radius:50%;object-fit:cover;background:var(--st-surface)}
.rs-name{font-weight:700;font-size:15px}
.rs-badge{color:#15803d;font-size:13px;font-weight:600}
@container st (max-width:860px){.rs{grid-template-columns:1fr}.rs-sum{position:static}}
/* 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}}
/* Opening Hours & Location */
.st-opening-hours{padding:clamp(64px,8cqi,112px) 0}
.oh{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1.15fr);gap:clamp(18px,2.6cqi,32px);align-items:stretch}
.oh-card{padding:clamp(22px,2.8cqi,34px);border-radius:calc(var(--st-radius) * 1.1px);background:var(--st-surface);border:1px solid color-mix(in srgb,var(--st-text) 9%,transparent);box-shadow:0 24px 60px -44px color-mix(in srgb,var(--st-text) 55%,transparent)}
.oh-top{display:flex;flex-wrap:wrap;align-items:center;justify-content:space-between;gap:10px 16px;margin-bottom:6px}
.oh-title{font-size:clamp(21px,2.3cqi,26px)}
.oh-badge{display:inline-flex;align-items:center;gap:8px;padding:6px 13px;border-radius:999px;background:color-mix(in srgb,var(--st-text) 7%,transparent);color:var(--st-text);font-size:13.5px;font-weight:700}
.oh-badge[hidden]{display:none}
.oh-dot{width:9px;height:9px;border-radius:50%;background:#94a3b8}
.oh-badge.is-open{background:rgba(34,197,94,.15);color:color-mix(in srgb,#16a34a 78%,var(--st-text))}
.oh-badge.is-open .oh-dot{background:#22c55e;box-shadow:0 0 0 3px rgba(34,197,94,.25)}
.oh-badge.is-shut{background:rgba(239,68,68,.12);color:color-mix(in srgb,#dc2626 78%,var(--st-text))}
.oh-badge.is-shut .oh-dot{background:#ef4444}
.oh-list{list-style:none;margin:0;padding:0}
.oh-row{display:grid;grid-template-columns:minmax(96px,auto) 1fr;gap:3px 16px;align-items:baseline;padding:13px 12px;margin:0 -12px;border-bottom:1px dashed color-mix(in srgb,var(--st-text) 14%,transparent);font-size:16px}
.oh-row:last-child{border-bottom:0}
.oh-day{font-weight:700}
.oh-time,.oh-shut{justify-self:end;font-variant-numeric:tabular-nums}
.oh-shut{color:var(--st-muted)}
.oh-note{grid-column:1 / -1;justify-self:end;color:var(--st-muted);font-size:13.5px}
.oh-row.is-today{background:color-mix(in srgb,var(--st-brand) 10%,transparent);border-radius:10px;border-bottom-color:transparent}
.oh-row.is-today .oh-day{color:var(--st-brand)}
.oh-row.is-today .oh-day::before{content:"";display:inline-block;width:8px;height:8px;margin-right:9px;border-radius:50%;background:var(--st-brand)}
.oh-special{margin-top:14px;padding-top:14px;border-top:1px solid color-mix(in srgb,var(--st-text) 9%,transparent);color:var(--st-muted);font-size:14.5px}
.oh-side{display:flex;flex-direction:column;gap:clamp(14px,2cqi,20px);min-width:0}
.oh-map{flex:1;min-height:280px;overflow:hidden;border-radius:calc(var(--st-radius) * 1.1px);background:var(--st-surface) url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 600 420' preserveAspectRatio='xMidYMid slice'%3E%3Crect width='600' height='420' fill='%23e9eef0'/%3E%3Cpath d='M0 90H600M0 250H600M0 350H600M110 0V420M300 0V420M470 0V420' stroke='%23ffffff' stroke-width='16'/%3E%3Cpath d='M0 190L600 150M200 0L330 420' stroke='%23ffffff' stroke-width='10'/%3E%3Crect x='330' y='110' width='110' height='80' rx='8' fill='%23d9e6dc'/%3E%3Cpath d='M300 150c-28 0-50 22-50 50 0 36 50 82 50 82s50-46 50-82c0-28-22-50-50-50z' fill='%23ef4444'/%3E%3Ccircle cx='300' cy='200' r='17' fill='%23ffffff'/%3E%3C/svg%3E") center/cover no-repeat;border:1px solid color-mix(in srgb,var(--st-text) 9%,transparent)}
.oh-frame{display:block;width:100%;height:100%;min-height:280px;border:0}
.oh-info{list-style:none;margin:0 0 18px;padding:0;display:grid;gap:14px}
.oh-item{display:flex;align-items:flex-start;gap:14px}
.oh-item .st-icon{width:42px;height:42px;background:color-mix(in srgb,var(--st-brand) 14%,transparent)}
.oh-item .st-icon svg{width:20px;height:20px}
.oh-addr{display:flex;flex-direction:column;font-style:normal;font-size:16px;line-height:1.5;padding-top:2px}
.oh-name{font-weight:700}
.oh-link{align-self:center;color:var(--st-text);font-size:16.5px;font-weight:600;text-decoration:none;word-break:break-word}
.oh-link:hover{color:var(--st-brand);text-decoration:underline}
.oh-contact .st-btns{display:flex;flex-wrap:wrap;gap:12px}
@container st (max-width:860px){.oh{grid-template-columns:1fr}.oh-map,.oh-frame{min-height:260px}}
@media (prefers-reduced-motion:reduce){.oh-dot{box-shadow:none!important}}
/* 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}}
/* Back to Top Button */
.st-back-to-top{overflow:visible;container-type:normal;height:0;min-height:0;padding:0;background:transparent}
.st-back-to-top:has(.btt.is-preview){height:auto;padding:clamp(20px,3vw,40px) var(--st-pad);background:color-mix(in srgb,var(--st-text) 6%,var(--st-bg))}
.btt{--btt-size:52px;--btt-off:24px;--btt-radius:50%;--btt-speed:.8s;--btt-bg:var(--st-brand);--btt-fg:var(--st-btn-text)}
.btt-btn{position:fixed;bottom:var(--btt-off);z-index:2147482500;display:grid;place-items:center;width:var(--btt-size);height:var(--btt-size);padding:0;border:0;border-radius:var(--btt-radius);background:var(--btt-bg);color:var(--btt-fg);cursor:pointer;opacity:0;visibility:hidden;pointer-events:none;transition:opacity .3s ease,transform .3s ease,visibility 0s .3s,box-shadow .2s ease,background .2s ease}
.btt[data-pos=right] .btt-btn{right:var(--btt-off)}
.btt[data-pos=left] .btt-btn{left:var(--btt-off)}
.btt[data-appear=slide] .btt-btn{transform:translateY(28px)}
.btt[data-appear=zoom] .btt-btn{transform:scale(.5)}
.btt[data-shadow=on] .btt-btn{box-shadow:0 12px 28px -8px rgba(15,23,42,.45)}
.btt.is-visible .btt-btn{opacity:1;visibility:visible;pointer-events:auto;transform:none;transition:opacity .3s ease,transform .3s ease,visibility 0s,box-shadow .2s ease,background .2s ease}
.btt.is-visible .btt-btn:hover{transform:translateY(-3px)}
.btt.is-visible .btt-btn:active{transform:translateY(0) scale(.96)}
.btt-btn:focus-visible{outline:3px solid color-mix(in srgb,var(--btt-bg) 55%,#fff);outline-offset:3px}
.btt-svg{width:calc(var(--btt-size) * .46);height:calc(var(--btt-size) * .46)}
@media (max-width:899px){.btt[data-mobile=off] .btt-btn{display:none}}
.btt[data-enabled=off] .btt-btn{display:none}
.btt-demo{display:none}
.btt.is-preview .btt-demo{position:relative;display:flex;flex-direction:column;gap:14px;min-height:320px;padding:34px 30px;border-radius:calc(var(--st-radius) * 1.2px);background:var(--st-bg);box-shadow:0 20px 50px -24px color-mix(in srgb,var(--st-text) 40%,transparent)}
.btt-bar{display:block;height:14px;width:100%;border-radius:7px;background:color-mix(in srgb,var(--st-text) 12%,transparent)}
.btt-bar--lg{height:22px;width:62%;background:color-mix(in srgb,var(--st-text) 22%,transparent)}
.btt-bar--md{width:84%}.btt-bar--sm{width:46%}
.btt-note{margin-top:auto;font-size:13px;color:var(--st-muted)}
.btt.is-preview .btt-btn{position:absolute;right:calc(var(--st-pad) + 18px);bottom:calc(clamp(20px,3vw,40px) + 18px);opacity:1;visibility:visible;pointer-events:auto;transform:none}
.btt.is-preview[data-pos=left] .btt-btn{right:auto;left:calc(var(--st-pad) + 18px)}
@media (prefers-reduced-motion:reduce){.btt-btn{transition:none}}
@media print{.btt{display:none}}
.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)}
.st-art[data-pos=top]{inset:0 0 50% 0}
.st-art[data-pos=bottom]{inset:50% 0 0 0}
.st-art[data-pos=left]{inset:0 50% 0 0}
.st-art[data-pos=right]{inset:0 0 0 50%}
.st-art--corner[data-pos=c]>svg{top:var(--art-y,50%);left:var(--art-x,50%);right:auto;bottom:auto;translate:-50% -50%}
.st-art--corner[data-pos=tl]>svg{right:auto;left:-8%}
.st-art--corner[data-pos=br]>svg{top:auto;bottom:-12%}
.st-art--corner[data-pos=bl]>svg{top:auto;right:auto;bottom:-12%;left:-8%}
.st-art--corners[data-pos=tl]>svg{right:auto;left:0;transform:scaleX(-1)}
.st-art--corners[data-pos=tl]>svg+svg{left:auto;right:0;transform:scaleY(-1)}
(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;
var still = window.ST_STILL && !window.ST_SCROLL_FX;
var pad = function (n) { return (n < 10 ? '0' : '') + n; };
var SHADOW_ON = '0 30px 80px rgba(0,0,0,0.55)', SHADOW_OFF = '0 30px 80px rgba(0,0,0,0)';
document.querySelectorAll('.st [data-zs]').forEach(function (root) {
if (root.getAttribute('data-zs-ready')) return;
root.setAttribute('data-zs-ready', '1');
var layers = Array.prototype.slice.call(root.querySelectorAll('.zs-layer'));
var n = layers.length;
if (n < 2 || reduce) return;
var num = function (name, d) { var v = parseFloat(root.getAttribute(name)); return isNaN(v) ? d : v; };
var zoom = Math.min(100, Math.max(5, num('data-zoom', 45)));
var s0 = Math.max(0.22, 1 - 0.7 * zoom / 100); // the size an image starts at, as a share of the stage
var dir = root.getAttribute('data-dir') === 'out' ? 'out' : 'in';
var both = root.getAttribute('data-affect') !== 'moving';
var per = Math.max(30, num('data-per', 100)), smooth = num('data-smooth', 0.6);
var drift = root.getAttribute('data-drift') !== 'off';
var imgs = layers.map(function (l) { return l.querySelector('.zs-img'); });
var caps = layers.map(function (l) { return l.querySelector('.zs-cap'); });
var RADIUS = 30;
layers.forEach(function (l, i) { l.style.zIndex = String(dir === 'in' ? i + 1 : n - i); });
var count = root.querySelector('.zs-count'), bar = root.querySelector('.zs-bar i');
var label = function (i) { return pad(i + 1) + ' / ' + pad(n); };
if (still || !G || !window.ScrollTrigger) {
if (!still) return;
// A frame from the effect for previews and thumbnails: the back image fills the stage and the next image is a slightly
// smaller card with a shadow in front of it, part way through its zoom, with the counter and progress bar. No heading, no captions.
root.classList.add('is-zs', 'is-zs-still');
layers.forEach(function (l, i) { l.style.zIndex = String(i + 1); if (i > 1) l.style.visibility = 'hidden'; });
if (layers[1]) {
layers[1].style.transform = 'scale(0.88)';
layers[1].style.borderRadius = '24px';
layers[1].style.boxShadow = SHADOW_ON;
}
caps.forEach(function (c) { if (c) c.style.opacity = '0'; });
if (count) count.textContent = label(1);
if (bar) bar.style.transform = 'scaleX(' + Math.min(1, 1.45 / (n - 1)).toFixed(3) + ')';
return;
}
G.registerPlugin(ScrollTrigger);
root.classList.add('is-zs');
var steps = n - 1, HOLD = 0.3;
// A sticky header stays on screen, so the stage pins just below it instead of under it
var head = function () { var h = 0; document.querySelectorAll('.st').forEach(function (s) { if (s.querySelector('[data-sticky-flag]')) h = Math.max(h, s.offsetHeight); }); return h; };
var tl = G.timeline({
defaults: { ease: 'none' },
scrollTrigger: {
trigger: root,
start: function () { return 'top ' + (head() + 16); },
end: function () { return '+=' + Math.round(window.innerHeight * per / 100 * (steps + HOLD)); },
pin: true, scrub: smooth > 0 ? smooth : true, anticipatePin: 1, invalidateOnRefresh: true,
onUpdate: function (self) {
var i = Math.min(n - 1, Math.floor(self.progress * (steps + HOLD) + 0.5));
if (count) count.textContent = label(i);
if (bar) bar.style.transform = 'scaleX(' + Math.min(1, self.progress * (steps + HOLD) / steps).toFixed(3) + ')';
}
}
});
if (count) count.textContent = label(0);
var kb = 1 + (1 - s0) * 0.2; // how far the image beneath drifts closer
var kbx = drift ? -(kb - 1) * 35 : 0;
G.set(caps.slice(1), { opacity: 0 });
if (dir === 'in') {
layers.forEach(function (layer, i) {
if (!i) return;
var t = i - 1;
G.set(layer, { scale: s0, autoAlpha: 0, borderRadius: RADIUS, boxShadow: SHADOW_ON });
G.set(imgs[i], { scale: 1.22 });
tl.to(layer, { autoAlpha: 1, duration: 0.14 }, t);
tl.to(layer, { scale: 1, borderRadius: 0, boxShadow: SHADOW_OFF, duration: 1, ease: 'power1.inOut' }, t);
tl.to(imgs[i], { scale: 1, duration: 1, ease: 'power1.inOut' }, t);
if (both) tl.to(imgs[i - 1], { scale: kb, xPercent: kbx, duration: 1 }, t);
if (caps[i - 1]) tl.to(caps[i - 1], { opacity: 0, duration: 0.2 }, t);
if (caps[i]) tl.to(caps[i], { opacity: 1, duration: 0.25 }, t + 0.75);
});
} else {
layers.forEach(function (layer, i) {
if (i === n - 1) return;
G.set(layer, { boxShadow: SHADOW_OFF });
tl.to(layer, { scale: s0, borderRadius: RADIUS, boxShadow: SHADOW_ON, duration: 0.86, ease: 'power1.inOut' }, i);
tl.to(layer, { autoAlpha: 0, duration: 0.14 }, i + 0.86);
if (both) tl.fromTo(imgs[i + 1], { scale: kb, xPercent: kbx }, { scale: 1, xPercent: 0, duration: 1 }, i);
if (caps[i]) tl.to(caps[i], { opacity: 0, duration: 0.2 }, i);
if (caps[i + 1]) tl.to(caps[i + 1], { opacity: 1, duration: 0.25 }, i + 0.75);
});
}
tl.to({}, { duration: HOLD }, steps);
});
window.addEventListener('load', function () { if (window.ScrollTrigger) ScrollTrigger.refresh(); });
})();
(function () {
document.querySelectorAll('.st [data-compare]').forEach(function (box) {
var input = box.querySelector('.ba-range');
if (!input) return;
if (window.ST_STILL || window.ST_PREVIEW) {
// The editor: clicking a photo edits it, so the full-size input is off; the handle itself
// can still be dragged to try the slider
box.classList.add('is-static');
var handle = box.querySelector('.ba-handle');
if (handle) handle.addEventListener('pointerdown', function (e) {
e.preventDefault();
e.stopPropagation();
var rect = box.getBoundingClientRect();
var move = function (ev) {
var p = Math.max(0, Math.min(100, (ev.clientX - rect.left) / rect.width * 100));
box.style.setProperty('--pos', p + '%');
};
var up = function () { window.removeEventListener('pointermove', move); window.removeEventListener('pointerup', up); };
window.addEventListener('pointermove', move);
window.addEventListener('pointerup', up);
move(e);
});
return;
}
function set() { box.style.setProperty('--pos', input.value + '%'); }
input.addEventListener('input', set);
set();
});
})();
(function () {
document.querySelectorAll('.st [data-ta]').forEach(function (root) {
if (root.getAttribute('data-ta-ready')) return;
root.setAttribute('data-ta-ready', '1');
var items = Array.prototype.slice.call(root.querySelectorAll('.ta-item'));
if (!items.length) return;
function open(i) {
items.forEach(function (it, k) {
var on = k === i;
it.classList.toggle('is-open', on);
var b = it.querySelector('.ta-trigger');
if (b) b.setAttribute('aria-expanded', on ? 'true' : 'false');
});
}
var start = parseInt(root.getAttribute('data-open'), 10);
open(isNaN(start) ? 0 : Math.min(items.length - 1, Math.max(0, start - 1)));
items.forEach(function (it, k) {
var b = it.querySelector('.ta-trigger');
if (!b) return;
b.addEventListener('click', function () { open(k); });
b.addEventListener('keydown', function (e) {
var to = -1;
if (e.key === 'ArrowRight' || e.key === 'ArrowDown') to = (k + 1) % items.length;
else if (e.key === 'ArrowLeft' || e.key === 'ArrowUp') to = (k - 1 + items.length) % items.length;
else if (e.key === 'Home') to = 0;
else if (e.key === 'End') to = items.length - 1;
if (to < 0) return;
e.preventDefault();
var nb = items[to].querySelector('.ta-trigger');
if (nb) nb.focus();
open(to);
});
});
});
})();
(function () {
document.querySelectorAll('.st [data-revfilter]').forEach(function (root) {
var btns = root.querySelectorAll('[data-filter-star]');
var cards = root.querySelectorAll('[data-rating]');
var status = root.querySelector('[data-filter-status]');
var msg = status && status.querySelector('[data-filter-message]');
var clear = status && status.querySelector('[data-filter-clear]');
if (!btns.length || !cards.length) return;
var tpl = root.getAttribute('data-filter-text') || 'Showing {n} of {t} reviews rated {s} stars';
if (clear) clear.textContent = root.getAttribute('data-clear-label') || 'Show all reviews';
Array.prototype.forEach.call(btns, function (b) {
var label = b.getAttribute('aria-label');
if (label) b.setAttribute('aria-label', label.replace('{s}', b.getAttribute('data-star')));
});
var current = '';
function apply(star) {
current = star;
var shown = 0;
Array.prototype.forEach.call(cards, function (c) {
var show = !star || String(Math.round(parseFloat(c.getAttribute('data-rating')) || 0)) === star;
c.hidden = !show;
if (show) shown++;
});
Array.prototype.forEach.call(btns, function (b) { b.setAttribute('aria-pressed', String(b.getAttribute('data-star') === star)); });
if (status) {
status.hidden = !star;
if (msg && star) msg.textContent = tpl.replace('{n}', shown).replace('{t}', cards.length).replace('{s}', star);
}
}
Array.prototype.forEach.call(btns, function (b) {
b.addEventListener('click', function () { var s = b.getAttribute('data-star'); apply(current === s ? '' : s); });
});
if (clear) clear.addEventListener('click', function () { apply(''); });
});
})();
(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 KEYS = ['sun', 'mon', 'tue', 'wed', 'thu', 'fri', 'sat'];
function mins(v) {
var m = String(v || '').trim().toLowerCase().match(/^(\d{1,2})(?::(\d{2}))?\s*(am|pm)?$/);
if (!m) return null;
var h = +m[1], mi = +(m[2] || 0);
if (m[3] === 'pm' && h < 12) h += 12;
if (m[3] === 'am' && h === 12) h = 0;
return h > 24 || mi > 59 ? null : h * 60 + mi;
}
function clock(total) {
var h = Math.floor(total / 60) % 24, mi = total % 60;
return (h < 10 ? '0' : '') + h + ':' + (mi < 10 ? '0' : '') + mi;
}
function nowIn(tz) {
var o = { weekday: 'short', hour: '2-digit', minute: '2-digit', hourCycle: 'h23' };
if (tz) o.timeZone = tz;
var parts;
try { parts = new Intl.DateTimeFormat('en-GB', o).formatToParts(new Date()); }
catch (e) { delete o.timeZone; parts = new Intl.DateTimeFormat('en-GB', o).formatToParts(new Date()); }
var p = {};
parts.forEach(function (x) { p[x.type] = x.value; });
return { day: KEYS.indexOf(String(p.weekday).slice(0, 3).toLowerCase()), min: (parseInt(p.hour, 10) % 24) * 60 + parseInt(p.minute, 10) };
}
document.querySelectorAll('.st').forEach(function (sec) {
var root = sec.querySelector('[data-opennow]');
if (!root) return;
var badge = root.querySelector('[data-open-badge]');
var text = badge && badge.querySelector('.oh-badge-text');
var rows = Array.prototype.map.call(root.querySelectorAll('[data-hours-row]'), function (r) {
var d = KEYS.indexOf(String(r.getAttribute('data-day') || '').slice(0, 3).toLowerCase());
var o = mins(r.getAttribute('data-open')), c = mins(r.getAttribute('data-close'));
var label = r.querySelector('.oh-day');
return { el: r, day: d, open: o, close: c, shut: r.getAttribute('data-closed') === 'closed' || o === null || c === null, name: label ? label.textContent : '' };
});
if (!rows.length) return;
var tz = root.getAttribute('data-tz') || '';
function attr(n, d) { return root.getAttribute(n) || d; }
function update() {
var n = nowIn(tz), prev = (n.day + 6) % 7, open = null;
rows.forEach(function (r) {
r.el.classList.toggle('is-today', r.day === n.day);
if (r.day === n.day) r.el.setAttribute('aria-current', 'date'); else r.el.removeAttribute('aria-current');
if (r.shut) return;
var over = r.close <= r.open;
if (r.day === n.day && n.min >= r.open && (over || n.min < r.close)) open = open || r;
if (r.day === prev && over && n.min < r.close) open = open || r;
});
if (!badge || !text) return;
badge.hidden = false;
badge.classList.toggle('is-open', !!open);
badge.classList.toggle('is-shut', !open);
if (open) { text.textContent = attr('data-open-label', 'Open now') + ' \u00b7 ' + attr('data-closes-label', 'closes at') + ' ' + clock(open.close); return; }
var next = null;
for (var i = 0; i < 8 && !next; i++) {
var dd = (n.day + i) % 7;
rows.forEach(function (r) {
if (r.shut || r.day !== dd || (i === 0 && r.open <= n.min)) return;
if (!next || r.open < next.open) next = r;
});
if (next) next.when = i === 0 ? '' : next.name + ' ';
}
text.textContent = attr('data-shut-label', 'Closed now') + (next ? ' \u00b7 ' + attr('data-opens-label', 'opens') + ' ' + next.when + clock(next.open) : '');
}
update();
setInterval(update, 60000);
});
})();
(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);
}
});
var btnMode = !!window.ST_POPUP_BUTTON; // Website Builder preview: a floating button opens the popup instead of showing it inline
if (inline && !btnMode) {
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 (!btnMode && 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 = [], quiet = btnMode; // in the builder preview the popup never pulls focus out of the side panel
var setOpenFlag = function (v) { if (!btnMode) return; try { if (v) window.parent.__wbPuOpen = KEY; else if (window.parent.__wbPuOpen === KEY) window.parent.__wbPuOpen = ''; } catch (e) {} };
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');
setOpenFlag(true);
if (modal && !quiet) {
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 && !btnMode) localStorage.setItem(KEY, String(Date.now())); } catch (e) {}
}
function hide() {
setOpenFlag(false);
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 (btnMode) {
// The popup follows its own trigger (delay, exit intent, scroll) exactly like the published page; a floating
// button also opens and closes it on demand, and it stays open across preview reloads while it is being edited
var btn = document.createElement('button');
btn.type = 'button';
btn.className = 'wb-pu-btn';
btn.textContent = 'Popup preview';
btn.setAttribute('aria-label', 'Open the popup');
btn.style.cssText = 'position:fixed;left:16px;bottom:' + (16 + document.querySelectorAll('.wb-pu-btn').length * 48) + 'px;z-index:999;padding:0 16px;height:38px;border:0;border-radius:999px;background:#4f46e5;color:#fff;font:700 13px/1 system-ui,sans-serif;box-shadow:0 8px 22px rgba(15,23,42,.35);cursor:pointer';
btn.addEventListener('click', function () { if (root.classList.contains('is-open')) hide(); else { shown = false; show(); } });
document.body.appendChild(btn);
try { if (window.parent.__wbPuOpen === KEY) show(); } catch (e) {}
}
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 () {
var inline = window.ST_STILL || window.ST_PREVIEW || window.ST_POPUP_INLINE;
var reduce = window.matchMedia && window.matchMedia('(prefers-reduced-motion: reduce)').matches;
document.querySelectorAll('.st [data-btt]').forEach(function (root) {
if (root.getAttribute('data-btt-ready')) return;
root.setAttribute('data-btt-ready', '1');
var btn = root.querySelector('.btt-btn');
var demo = root.querySelector('.btt-demo');
if (!btn || root.getAttribute('data-enabled') === 'off') { if (demo && !inline) demo.parentNode.removeChild(demo); return; }
if (!inline && demo) demo.parentNode.removeChild(demo);
if (inline) {
root.classList.add('is-preview', 'is-visible');
btn.addEventListener('click', function (e) { e.preventDefault(); });
return;
}
var dist = parseFloat(root.getAttribute('data-distance')) || 0;
var secs = parseFloat(root.getAttribute('data-speed'));
if (isNaN(secs)) secs = 0.8;
var ticking = false;
function check() { ticking = false; root.classList.toggle('is-visible', (window.pageYOffset || document.documentElement.scrollTop) > dist); }
window.addEventListener('scroll', function () { if (!ticking) { ticking = true; requestAnimationFrame(check); } }, { passive: true });
check();
var stopped = false;
['wheel', 'touchstart', 'keydown'].forEach(function (ev) { window.addEventListener(ev, function () { stopped = true; }, { passive: true }); });
btn.addEventListener('click', function () {
var from = window.pageYOffset || document.documentElement.scrollTop;
if (reduce || secs <= 0 || from < 2) { window.scrollTo({ top: 0, left: 0, behavior: 'instant' }); return; }
stopped = false;
var t0 = performance.now(), dur = secs * 1000;
(function step(t) {
var p = Math.min(1, (t - t0) / dur);
var e = p < 0.5 ? 4 * p * p * p : 1 - Math.pow(-2 * p + 2, 3) / 2;
window.scrollTo({ top: from * (1 - e), left: 0, behavior: 'instant' });
if (p < 1 && !stopped) requestAnimationFrame(step);
})(t0);
});
});
})();
(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%', end: function () { var pin = ScrollTrigger.getAll().filter(function (t) { return t.pin === section; })[0]; return pin ? pin.end + section.offsetHeight : 'bottom top'; }, 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%' });
});
// window.ST_ART_PLAY (the section editor's preview): draw and parallax play once by themselves,
// so picking them shows the effect without scrolling. Exports and pages keep the scroll-driven version.
if (mode === 'draw' && (window.ScrollTrigger || window.ST_ART_PLAY)) layer.querySelectorAll('[data-draw]').forEach(function (p, i) {
var len = p.getTotalLength ? p.getTotalLength() : 0;
if (!len) return;
if (window.ST_ART_PLAY) G.fromTo(p, { strokeDasharray: len, strokeDashoffset: len }, { strokeDashoffset: 0, duration: 2.4, delay: i * 0.12, ease: 'power2.out' });
else 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' && svg && (window.ScrollTrigger || window.ST_ART_PLAY)) {
G.set(svg, { scale: 1.15 });
if (window.ST_ART_PLAY) G.fromTo(svg, { yPercent: -6 }, { yPercent: 6, duration: 2.4, ease: 'sine.inOut', yoyo: true, repeat: 1 });
else G.fromTo(svg, { yPercent: -6 }, { yPercent: 6, ease: 'none', scrollTrigger: { trigger: sec, start: 'top bottom', end: 'bottom top', scrub: true } });
}
});
})();
Extend with AI
Take This Template Further With AI
Give this prompt to an AI assistant to generate your own version of the Hair & Beauty Salon Website template: swap in your business name, services and tone, add or remove sections, translate it, or turn the page into a Next.js project or a WordPress theme. Use the template above as the visual reference, so you and the AI start from a design that already works.
Prompt to recreate it
Copy this into your AI assistant of choice to build the effect from scratch, or as a jumping-off point for your own variant:
Build a complete hair & beauty salon website for “Bloom Studio” as clean HTML, CSS and a little JavaScript.
Page structure, top to bottom:
1. Simple Sticky Navbar
2. Image Background Hero: “Leave feeling like yourself, only better”
3. Restaurant Menu: “Cut, colour and care”
4. Scroll Zoom Image Stack (Ken Burns): “A calm place to take your time”
5. Before & After Slider: “Colour and cut, before and after”
6. Interactive Team Accordion: “Meet the hands behind Bloom”
7. Reviews Summary & Rating: “Rated 4.9 out of 5 by our clients”
8. Booking Request Form: “Request your appointment”
9. Opening Hours & Location: “Find the studio”
10. Popup & Promo Modal
11. Minimal Footer
12. Back to Top Button
Look and feel:
- Colours as CSS custom properties: brand #be185d, page background #fff8f7, cards #f8e9e6, text #3b1d24, muted text #7b5960. Corner radius 18px, content width 1200px.
- Headings in Playfair Display, body text in DM Sans (load both from Google Fonts with display=swap).
- Mobile first. Sections use CSS grid or flexbox and stack cleanly below 700px.
Content:
- Write real, believable health & beauty copy for every section instead of lorem ipsum: specific offers, numbers, names and calls to action.
- One clear primary action in the hero and again near the end.
Quality:
- Semantic HTML (header, main, section, footer) with exactly one h1, the hero headline, and one h2 per section.
- Accessible: alt text on every image, visible focus states, labelled form fields, buttons and links with clear text, and prefers-reduced-motion respected.
- SEO: title “Bloom Studio: Hair, Colour and Beauty Salon in Hackney”, a meta description of 150 to 160 characters, Open Graph tags and JSON-LD that suits a health & beauty business.
- Optional: a subtle GSAP ScrollTrigger fade-up on section headings, with content visible without JavaScript.
Also create these pages with the same navbar, footer and theme, and link them from the menu:
- Services (services.html)
- Stylists (team.html)
- Book (book.html)
- Privacy (privacy.html)Want to tighten it up first? Run this prompt through the AI Prompt Studio to score it across 8 quality dimensions, catch anti-patterns, and tune the wording for Claude, ChatGPT, or Gemini before you paste it in.
What's included
Features
About this UI Snippet
A Salon Website That Books Appointments: Services Menu, Stylists and Before-and-After Proof

Clients choose a salon on three things: the work, the price and the person who will do it. The services are therefore laid out like a menu, with prices, so the cost of a cut and colour is clear before anyone books. A before-and-after slider shows transformations that no description can convey, and the stylist grid lets a client pick someone by name, which is how most salon bookings really work.
Reviews from regulars confirm the experience, a booking request form takes the service, preferred stylist and date, and a map shows where to find you. A popup can promote a new-client offer or a quiet-day discount without restructuring the page.
Replace the sample menu and stylists with your own, and photograph your real work. It is the layout of the Hair & Beauty Salon Website template, which also comes as a multi-page site with Services, Stylists and Book pages; open it in the Website Builder to edit and export.
Interactive extras built in
Beyond the core sections, this template adds a pinned stack of studio photographs that each arrive small and zoom up to fill the screen as you scroll, room by room; an interactive team accordion where each stylist is a grayscale strip that opens on click; a reviews summary with the 4.9 average and a star breakdown that filters the client reviews; an opening hours table with a live Open now badge, late-night Thursdays and Fridays and a map of the studio; and a floating back to top button that appears after the visitor scrolls, so a long page is easy to leave and return. Each one has its own page in the Website Section Templates library (Scroll Zoom Image Stack, Interactive Team Accordion, Reviews Summary & Rating, Opening Hours & Location, Back to Top Button), where you can try its settings on their own, and you can edit, move or remove any of them in the Website Builder.
Built from website section templates
The 12 Sections Behind This Hair & Beauty Salon 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 now button for visitors who already know what they want
- Image Background Heroa soft hero with your best review and a booking button, tone first
- Restaurant Menuservices and prices laid out like a menu, so the cost is clear before anyone books
- Scroll Zoom Image Stack (Ken Burns)a pinned stack of studio photographs that each arrive small and zoom up to fill the screen as you scroll, room by room
- Before & After Sliderbefore-and-after results, the proof of skill that words cannot give
- Interactive Team Accordionan interactive team accordion where each stylist is a grayscale strip that opens on click
- Reviews Summary & Ratinga reviews summary with the 4.9 average and a star breakdown that filters the client reviews
- Booking Request Forma booking request form for service, stylist, date and contact details
- Opening Hours & Locationan opening hours table with a live Open now badge, late-night Thursdays and Fridays and a map of the studio
- Popup & Promo Modalan optional popup for a new-client offer or a quiet-day discount
- Minimal Footera minimal footer with socials and legal links
- Back to Top Buttona floating back to top button that appears after the visitor scrolls, so a long page is easy to leave and return
Step by step
How to Use
- 1Open the template in the Website BuilderPress "Start using this template" to open the Hair & Beauty Salon Website in the Website Builder. Everything is edited with forms in a side panel; no code is needed.
- 2Turn your price list into the menuEnter each service with its real price or "from" price and duration, grouped by cut, colour and treatments, so clients know what to expect before they book.
- 3Introduce each stylistAdd a photo, speciality and booking link for each stylist; many clients ask for someone by name.
- 4Show real transformationsUse your own before-and-after images in the slider, with the client's permission, to demonstrate the work you most want to be booked for.
- 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
Services with prices, the stylists, before-and-after photos, reviews, a booking method and your address and hours.
They send a request through the form, which emails you; or link the Book now button to your online booking system.
Yes. Clear prices reduce no-shows and queries and let clients choose with confidence.
It adds a scroll zoom image stack, an interactive team accordion, a reviews summary with a star breakdown and filter, an opening hours section with a live Open now badge and a floating back to top button. Each is a section you can edit, move or remove in the Website Builder, and each has its own page in the Website Section Templates library.
It is assembled from 12 templates in the free Website Section Templates library: Simple Sticky Navbar, Image Background Hero, Restaurant Menu, Scroll Zoom Image Stack (Ken Burns), Before & After Slider, Interactive Team Accordion, Reviews Summary & Rating, Booking Request Form, Opening Hours & Location, Popup & Promo Modal, Minimal Footer, Back to Top Button. 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.