/* Homepage editorial design, using the existing brand tokens. */
.home { background:var(--vv-surface); }
/* Header, nav and buttons are deliberately NOT restyled here — they are part of
   the site-wide system in main.css and must stay identical across every page:
   translucent paper header with backdrop blur, 1fr/auto/1fr grid so the nav is
   truly page-centred, 46px wordmark, uppercase nav, and olive pill buttons.
   Overrides for all of those were removed on 2026-09-12.
   The active-state rules below are a genuine addition and are kept. */
.home .nav a[aria-current] { color:var(--vv-plum); }
.home .nav a[aria-current]::after { transform:scaleX(1); }
.vn-home { --vn-border:var(--vv-line); }
.vn-home h1,.vn-home h2,.vn-home h3 { font-style:normal; font-weight:var(--vv-weight-head); }
.vn-home h2 { font-size:clamp(calc(38px * var(--vv-scale)),calc(4.4vw * var(--vv-scale)),calc(62px * var(--vv-scale))); line-height:1.06; letter-spacing:-.035em; }
.vn-home p { line-height:1.75; }
.vn-hero { overflow:hidden; padding:55px 0 68px; }
.vn-hero__grid { display:grid; grid-template-columns:1.03fr 1fr; gap:40px; align-items:center; }
.vn-hero__copy { padding:15px 0 0; }
.vn-hero .vn-kicker { display:flex; align-items:center; gap:10px; margin-bottom:25px; }
.vn-spark { font-size:26px; font-weight:400; }
.vn-home h1 { font-size:clamp(calc(58px * var(--vv-scale)),calc(6.7vw * var(--vv-scale)),calc(96px * var(--vv-scale))); line-height:.98; letter-spacing:-.048em; margin:0 0 26px; text-wrap:nowrap; }
.vn-home h1 span { color:var(--vv-plum); }
.vn-intro { max-width:440px; font-size:15px; color:var(--vv-ink-soft); }
.vn-actions { display:flex; flex-wrap:wrap; align-items:center; gap:22px; margin-top:30px; }
/* Homepage buttons adopt the shared pill system (main.css .btn) rather than a
   parallel square style — same shape, type, casing and travelling arrow. Their
   inline arrow glyphs are hidden because the arrow is now drawn by .btn's
   pseudo-elements. */
.vn-hero__signature { display:flex; gap:18px; align-items:center; margin-top:50px; padding-top:21px; border-top:1px solid var(--vv-line); max-width:430px; font-family:var(--vv-display); font-size:20px; }
.vn-signature-mark { display:block; width:36px; color:var(--vv-olive); }
.vn-hero__signature small { display:block; font:10px/1.7 var(--vv-body); color:var(--vv-mute); margin-top:3px; }
.vn-hero__art { position:relative; height:505px; padding:0 0 32px 35px; }
.vn-photo { position:relative; overflow:hidden; background:var(--vv-paper-2); border-radius:4px; isolation:isolate; }
.vn-photo img { position:absolute; width:130%; max-width:none; height:130%; left:-15%; top:-10%; object-fit:cover; border-radius:4px; }
.vn-hero__main { width:100%; height:100%; border-radius:140px 4px 4px 4px; }
.vn-hero__inset { position:absolute; width:180px; left:-16px; bottom:-10px; padding:9px 9px 0; background:var(--vv-surface); transform:rotate(-7deg); box-shadow:var(--vv-sh-lg); }
.vn-hero__inset .vn-photo { height:183px; }
.vn-hero__inset>span { display:block; text-align:center; font-size:7px; font-weight:600; letter-spacing:.12em; padding:10px 0; }
.vn-hero__stamp { position:absolute; right:-17px; top:-20px; width:101px; height:101px; display:grid; place-items:center; padding:9px; border-radius:50%; background:var(--vv-butter); color:var(--vv-plum-deep); transform:rotate(12deg); }
.vn-hero__asterisk { position:absolute; bottom:-16px; right:12px; color:var(--vv-olive); font-size:83px; line-height:1; }
.vn-ribbon { background:var(--vv-olive); color:var(--vv-surface); padding:17px 20px; text-align:center; }
.vn-ribbon p { font-size:11px; letter-spacing:.16em; word-spacing:.2em; text-transform:uppercase; margin:0; }
.vn-section { padding:90px 0; }
.vn-section-head { display:flex; justify-content:space-between; align-items:flex-end; gap:50px; margin-bottom:36px; }
.vn-section-head>div { max-width:670px; }
.vn-section-head h2 { margin:0; }
.vn-section-head>p { max-width:285px; font-size:13px; color:var(--vv-ink-soft); margin:0 0 4px; }
.vn-service-grid { display:grid; grid-template-columns:repeat(3,1fr); border-top:1px solid var(--vv-line); border-bottom:1px solid var(--vv-line); }
.vn-service { padding:29px 32px 30px; border-right:1px solid var(--vv-line); transition:background .25s; }
.vn-service:first-child { padding-left:0; }
.vn-service:last-child { border:0; }
.vn-service:hover { background:var(--vv-paper); }
.vn-service__top { display:flex; justify-content:space-between; align-items:center; margin-bottom:27px; font-size:11px; text-transform:uppercase; letter-spacing:.08em; color:var(--vv-plum); }
.vn-service__top>span:last-child { font-size:24px; }
.vn-service h3 { font-size:calc(38px * var(--vv-scale)); letter-spacing:-.03em; margin-bottom:12px; }
.vn-service p { max-width:280px; color:var(--vv-ink-soft); font-size:13px; }
.vn-services__foot { display:flex; justify-content:space-between; gap:30px; align-items:center; margin-top:25px; }
.vn-services__foot p { max-width:490px; margin:0; font-size:11px; color:var(--vv-mute); }
.vn-gallery { background:var(--vv-paper); }
.vn-gallery__grid { display:grid; grid-template-columns:repeat(4,1fr); gap:20px; margin:40px 0 30px; }
.vn-gallery figure { margin:0; }
.vn-gallery figure:nth-child(even) { padding-top:38px; }
.vn-gallery .vn-photo { aspect-ratio: .86; }
.vn-gallery figcaption { display:flex; justify-content:space-between; font-size:10px; margin-top:13px; color:var(--vv-ink-soft); }
.vn-story__grid { display:grid; grid-template-columns:.92fr 1fr; gap:95px; align-items:center; }
.vn-story__visual { position:relative; padding:0 45px 45px 0; }
.vn-story__visual>.vn-photo { aspect-ratio:.94; border-radius:4px 120px 4px 4px; }
.vn-story__label { position:absolute; bottom:0; right:0; width:240px; padding:30px; background:var(--vv-butter); color:var(--vv-ink); text-align:center; }
.vn-story__label span { display:block; font:19px var(--vv-display); margin-top:12px; }
.vn-story h2 { white-space:pre-line; }
.vn-story__copy>p { color:var(--vv-ink-soft); font-size:13px; }
.vn-story__copy>.vn-lead { font-size:18px; line-height:1.55; margin:23px 0 16px; }
.vn-story__copy .vn-link { margin-top:9px; }
.vn-stats { display:flex; gap:40px; margin-top:30px; padding-top:20px; border-top:1px solid var(--vv-line); }
.vn-stats>div { display:flex; align-items:center; gap:14px; }
.vn-stats strong { font:52px/1 var(--vv-display); color:var(--vv-plum); }
.vn-stats span { font-size:10px; max-width:80px; }
.vn-care { display:grid; grid-template-columns:repeat(3,1fr); gap:35px; padding-top:70px; }
.vn-care>div { display:flex; gap:18px; }
.vn-care__n { color:var(--vv-plum); font:24px var(--vv-display); }
.vn-care h3 { font:500 15px var(--vv-body); margin-bottom:9px; }
.vn-care p { font-size:12px; color:var(--vv-mute); }
.vn-education { background:var(--vv-plum-deep); color:var(--vv-surface); padding:75px 0; overflow:hidden; }
.vn-education__grid { display:grid; grid-template-columns:1.1fr 1fr; gap:90px; align-items:center; }
.vn-education .vn-kicker { color:var(--vv-butter); }
.vn-education h2 { color:var(--vv-surface); white-space:pre-line; }
.vn-education__grid>div>p:not(.vn-kicker) { font-size:13px; max-width:440px; color:var(--vv-on-dark); }
.vn-button--light { background:var(--vv-butter); border-color:var(--vv-butter); color:var(--vv-ink); margin-top:10px; }
.vn-button--light:hover { background:var(--vv-on-dark); border-color:var(--vv-on-dark); }
.vn-education__grid>div>p.vn-education__note { font-size:10px; margin-top:17px; }
.vn-education__art { position:relative; border:1px solid var(--vv-on-dark-mute); border-radius:180px 180px 4px 4px; padding:48px 40px; text-align:center; }
.vn-education__art>span { display:block; font-size:45px; line-height:1; color:var(--vv-butter); }
.vn-education__art>p { font:calc(74px * var(--vv-scale))/.95 var(--vv-display)!important; white-space:pre-line; color:var(--vv-butter)!important; letter-spacing:-.035em; margin:20px auto!important; }
.vn-education__art>div { width:42px; margin:20px auto 0; color:var(--vv-on-dark); }
.home .site-footer { padding-top:45px; }
/* .home .footer-grid was display:none — restored in 0.16.0, see end of file. */
.home .footer-bottom { margin-top:0; border-top:0; padding-top:0; }
@media(min-width:1450px) { .vn-hero__art { height:580px; } }
@media(max-width:1100px) { .home .nav ul { gap:16px; } .home .header-inner { gap:20px; } .vn-hero__grid { gap:24px; } .vn-hero__art { height:460px; padding-left:20px; } .vn-home h1 { font-size:calc(7.2vw * var(--vv-scale)); } .vn-hero__inset { width:150px; } .vn-hero__inset .vn-photo { height:153px; } .vn-story__grid { gap:45px; } .vn-actions { gap:14px; } }
@media(max-width:900px) { .home .nav,.home .header-cta { display:none; } .home .burger { display:flex; } .vn-hero__grid { grid-template-columns:1fr 1fr; } .vn-button { padding:.85rem 2.7rem .85rem 1.4rem; } .vn-intro { font-size:13px; } .vn-hero__signature { margin-top:25px; } .vn-hero__art { height:410px; } .vn-gallery__grid { gap:13px; } .vn-story__grid { gap:30px; } .vn-education__grid { gap:40px; } .vn-section-head { gap:25px; } .vn-section-head>p { max-width:240px; } }
@media(max-width:650px) {

 .vn-hero { padding:28px 0 42px; } .vn-hero__grid { grid-template-columns:1fr; gap:35px; } .vn-hero__copy { padding:0; }
 .vn-home h1 { font-size:clamp(calc(48px * var(--vv-scale)),calc(11.8vw * var(--vv-scale)),calc(76px * var(--vv-scale))); } .vn-hero .vn-kicker { font-size:calc(9px * var(--vv-scale)); margin-bottom:20px; }
 .vn-intro { font-size:14px; max-width:440px; } .vn-actions { margin-top:24px; gap:20px; } 
 .vn-hero__signature { display:none; } .vn-hero__art { height:380px; margin:0 10px; padding:0 0 22px 30px; } .vn-hero__main { border-top-left-radius:110px; }
 .vn-hero__inset { left:-5px; bottom:-8px; width:142px; } .vn-hero__inset .vn-photo { height:147px; } .vn-hero__stamp { width:77px; height:77px; top:-13px; right:-12px; }
 .vn-hero__asterisk { font-size:60px; bottom:-9px; } .vn-ribbon { padding:14px 22px; } .vn-ribbon p { font-size:9px; line-height:1.9; letter-spacing:.1em; word-spacing:0; }
 .vn-section { padding:55px 0; } .vn-section-head { display:block; margin-bottom:25px; } .vn-section-head>p { margin-top:18px; max-width:100%; }
 .vn-kicker { font-size:9px; margin-bottom:16px; } .vn-service-grid { grid-template-columns:1fr; } .vn-service,.vn-service:first-child { padding:22px 0; border-right:0; border-bottom:1px solid var(--vv-line); }
 .vn-service__top { margin-bottom:10px; } .vn-service h3 { font-size:calc(32px * var(--vv-scale)); } .vn-service p { max-width:100%; } .vn-services__foot { display:block; } .vn-services__foot p { margin-top:18px; }
 .vn-gallery__grid { grid-template-columns:repeat(2,1fr); gap:20px 12px; margin:28px 0; } .vn-gallery figure:nth-child(even) { padding-top:24px; } .vn-gallery figcaption { font-size:9px; gap:4px; }
 .vn-story__grid { grid-template-columns:1fr; gap:35px; } .vn-story__visual { padding:0 35px 30px 0; } .vn-story__label { width:190px; padding:23px; } .vn-story__label span { font-size:16px; }
 .vn-care { grid-template-columns:1fr; gap:23px; padding-top:36px; } .vn-stats { gap:32px; }
 .vn-education { padding:50px 0; } .vn-education__grid { grid-template-columns:1fr; gap:35px; } .vn-education__art { padding:35px 25px; max-width:310px; width:100%; margin:auto; } .vn-education__art>p { font-size:65px!important; }
 .vn-visit__details { grid-template-columns:1fr; gap:23px; margin-top:38px; } .vn-visit h2 { font-size:calc(62px * var(--vv-scale)); }
 .home .site-footer { padding:25px 0; }
}
@media(prefers-reduced-motion:reduce) { .vn-home * { transition:none!important; } }

/* Logo-inspired display lettering and photo-led service selection. */
/* Display face reverted to Cormorant Garamond (the brand pairing) on
   2026-09-12. The Italiana @font-face is kept commented rather than deleted so
   it is one line to restore if it is ever chosen deliberately; the file is
   still at assets/fonts/italiana.ttf.
   @font-face { font-family:Italiana; src:url('../fonts/italiana.ttf') format('truetype'); font-weight:400; font-style:normal; font-display:swap; }

   Codex's sizes are kept, but the letter-spacing was tightened for Italiana's
   narrow metrics (-.055em / -.045em) and reads cramped in Cormorant, so both
   relax to the theme's own heading tracking. */
.vn-home h1 { font-size:clamp(calc(54px * var(--vv-scale)),calc(6vw * var(--vv-scale)),calc(86px * var(--vv-scale))); letter-spacing:var(--vv-ls-head); line-height:1.08; }
.vn-home h2 { letter-spacing:var(--vv-ls-head); line-height:1.12; }
/* Scoped to this page's own components only. It previously also set the global
   nav and header button, overriding their letter-spacing and size. */
.vn-home .vn-button,.vn-home .vn-link { letter-spacing:var(--vv-ls-tight); }

.vn-service-grid { border:0; gap:24px; }
.vn-service,.vn-service:first-child,.vn-service:last-child { padding:0; border:0; background:var(--vv-paper); border-radius:4px; overflow:hidden; }
.vn-service__photo { aspect-ratio:.88; border-radius:4px 4px 0 0; }
.vn-service__photo img { transition:transform .6s var(--vv-ease); }
.vn-service:hover .vn-service__photo img { transform:scale(1.045); }
.vn-service__body { padding:23px 25px 26px; }
.vn-service__top { margin-bottom:12px; }
.vn-service h3 { font-size:calc(38px * var(--vv-scale)); line-height:1.15; }
.vn-service p { font-size:12px; max-width:100%; }
.vn-section-head>div { flex:1; }
.vn-section-head h2 { max-width:700px; }
@media(max-width:900px) { .vn-service-grid { gap:15px; } .vn-service__body { padding:20px 17px; } .vn-service h3 { font-size:calc(30px * var(--vv-scale)); } .vn-hero__grid { gap:24px; } }
@media(max-width:650px) { .vn-home h1 { font-size:clamp(calc(40px * var(--vv-scale)),calc(10.8vw * var(--vv-scale)),calc(66px * var(--vv-scale))); } .vn-service-grid { gap:26px; } .vn-service__photo { aspect-ratio:1; } .vn-service__body { padding:21px 23px; } .vn-service h3 { font-size:calc(36px * var(--vv-scale)); } .vn-actions { gap:14px; } .vn-visit h2 { font-size:calc(54px * var(--vv-scale)); } }

/* Photographic hero and focused service flow. */
.vn-home { --vn-hero-shade:rgba(25,22,24,.93); --vn-hero-mid:rgba(25,22,24,.60); --vn-hero-clear:rgba(25,22,24,.04); }
.vn-hero { position:relative; padding:0; background:var(--vv-ink); isolation:isolate; }
/* Full width. This used to be inset 29% from the left, so the photograph
   simply did not exist over the first quarter of the hero — that area was the
   section's flat ink, and the join showed as a hard vertical edge because the
   gradient above it had already begun to fade. The shade is the gradient's job
   alone now. */
.vn-hero__backdrop { position:absolute; inset:0; z-index:-2; overflow:hidden; }
.vn-hero__backdrop img { width:100%; height:130%; max-width:none; object-fit:cover; object-position:center 42%; margin-top:-6%; }
/* Three stops, so the ramp is smooth rather than a long straight fade that
   still looks like a band. Effectively gone by the midpoint. */
.vn-hero::after { content:''; position:absolute; inset:0; background:linear-gradient(90deg,var(--vn-hero-shade) 0%,var(--vn-hero-shade) 24%,var(--vn-hero-mid) 40%,var(--vn-hero-clear) 58%); z-index:-1; }
.vn-hero__grid { display:flex; position:relative; min-height:670px; align-items:center; padding-block:65px; }
.vn-hero__copy { max-width:670px; padding:0; }
.vn-hero__brand { width:58px; color:var(--vv-butter); margin-bottom:28px; }
.vn-hero .vn-kicker { color:var(--vv-butter); margin-bottom:20px; }
.vn-hero h1 { color:var(--vv-surface); font-size:clamp(calc(60px * var(--vv-scale)),calc(6.5vw * var(--vv-scale)),calc(96px * var(--vv-scale))); line-height:1.03; }
.vn-hero h1 span { color:var(--vv-butter); }
.vn-hero .vn-intro { color:var(--vv-on-dark); max-width:390px; font-size:14px; }
/* Contextual button rules set COLOUR ONLY. Padding is reserved for the arrow
   slot — overriding it here collapsed the slot and the arrow landed on the
   label. On the dark hero the outline button needs an on-dark border too; the
   default ink-tinted one is invisible there. */
.vn-hero .vn-button { background:var(--vv-butter); border-color:var(--vv-butter); color:var(--vv-ink); }
.vn-hero .vn-button:hover { background:var(--vv-on-dark); border-color:var(--vv-on-dark); }
.vn-hero .vn-link { color:var(--vv-on-dark); border-color:rgba(241,236,232,.45); }
.vn-hero .vn-link:hover { background:var(--vv-butter); border-color:var(--vv-butter); color:var(--vv-ink); }
.vn-hero__location { position:absolute; right:var(--vv-gutter); bottom:42px; text-align:right; color:var(--vv-surface); }
.vn-hero__location>span { font:calc(26px * var(--vv-scale))/1.1 var(--vv-display); }
.vn-hero__location p { font-size:10px; text-transform:uppercase; letter-spacing:.12em; margin:8px 0 0; }
.vn-ribbon { background:var(--vv-olive); padding:21px; }
.vn-section { padding-block:75px; }
.vn-services { background:var(--vv-olive); color:var(--vv-surface); }
.vn-services h2,.vn-services .vn-kicker,.vn-services .vn-section-head>p,.vn-services__foot p { color:var(--vv-on-dark); }
.vn-services .vn-link { color:var(--vv-on-dark); border-color:rgba(241,236,232,.45); }
.vn-services .vn-link:hover { background:var(--vv-butter); border-color:var(--vv-butter); color:var(--vv-ink); }
.vn-services .vn-kicker { color:var(--vv-butter); }
.vn-service { color:var(--vv-ink); }
.vn-service-grid { gap:22px; }
.vn-service__photo { aspect-ratio:.98; }
.vn-service__body { padding:20px 23px; }
.vn-service p { margin-bottom:0; }
.vn-services__foot>p { display:none; }
.vn-pricing { background:var(--vv-paper-2); scroll-margin-top:110px; }
.vn-price-tabs { display:flex; gap:0; border-bottom:1px solid var(--vv-line); overflow-x:auto; margin:30px 0 0; }
.vn-price-tabs button { white-space:nowrap; flex:1; padding:18px 23px; font:600 11px var(--vv-body); text-transform:uppercase; letter-spacing:.07em; border-bottom:3px solid transparent; }
.vn-price-tabs button[aria-selected=true] { background:var(--vv-olive); color:var(--vv-surface); border-color:var(--vv-butter); }
.vn-price-tabs button:not([aria-selected=true]):hover { color:var(--vv-plum-deep); background:var(--vv-paper); }
.vn-price-panel { padding:23px 30px 10px; background:var(--vv-surface); min-height:330px; }
.vn-price-panel[hidden] { display:none; }
.vn-price-description { font-size:12px; color:var(--vv-mute); min-height:21px; margin-bottom:18px; }
.vn-price-panel table { table-layout:fixed; }
.vn-price-panel th,.vn-price-panel td { text-align:left; padding:15px 0; border-bottom:1px solid var(--vv-line); }
.vn-price-panel thead th { text-transform:uppercase; font:500 10px var(--vv-body); color:var(--vv-mute); padding-top:0; }
.vn-price-panel th:first-child { width:65%; }
.vn-price-panel th:last-child,.vn-price-panel td:last-child { text-align:right; }
.vn-price-panel tbody th { font:400 22px var(--vv-display); }
.vn-price-panel td { font-size:13px; }
.vn-price-panel tbody tr:last-child>* { border-bottom:0; }
.vn-price-book { display:inline-block; font:500 9px var(--vv-body); text-transform:uppercase; letter-spacing:.05em; color:var(--vv-plum); margin-left:22px; }
.vn-price-panel a:hover { color:var(--vv-plum); }
.vn-price-note { font-size:11px; color:var(--vv-mute); margin:18px 0 0; }
.vn-gallery { background:var(--vv-surface); }
.vn-gallery__grid { gap:18px; }
.vn-gallery figure:nth-child(even) { padding-top:0; }
.vn-gallery .vn-photo { aspect-ratio:.8; }
.vn-story { background:var(--vv-paper); }
.vn-care { display:none; }
.vn-story__visual { padding:0; }
.vn-story__visual>.vn-photo { border-radius:4px; aspect-ratio:1; }
.vn-story__label { display:none; }
.vn-education__art { border:0; border-left:1px solid var(--vv-on-dark-mute); border-radius:0; padding:20px 35px; }
.vn-education__art>span,.vn-education__art>div { display:none; }
.vn-education__art>p { font-size:calc(65px * var(--vv-scale))!important; }
.home .site-footer { background:var(--vv-ink); }
@media(max-width:900px) { .vn-hero__grid { min-height:600px; } .vn-hero__location { display:none; } .vn-price-book { display:block; margin:8px 0 0; } }
@media(max-width:650px) {
 .vn-hero__grid { min-height:690px; align-items:flex-end; padding-block:35px; }
 .vn-hero__backdrop { inset:0; }
 .vn-hero__backdrop img { height:100%; margin-top:-22%; object-fit:cover; clip-path:inset(0 0 14% 0); }
 .vn-hero::after { background:linear-gradient(0deg,var(--vv-ink) 0%,var(--vv-ink) 30%,var(--vn-hero-clear) 85%); }
 .vn-hero__brand { width:38px; margin-bottom:15px; }
 .vn-hero h1 { font-size:calc(11.2vw * var(--vv-scale)); }
 .vn-hero .vn-kicker { font-size:8px; margin-bottom:15px; }
 .vn-hero .vn-intro { font-size:12px; max-width:320px; }

 .vn-section { padding-block:50px; }
 .vn-price-tabs button { flex:0 0 auto; padding:16px 18px; font-size:10px; }
 .vn-price-panel { padding:20px 17px 8px; min-height:360px; }
 .vn-price-panel th:first-child { width:60%; }
 .vn-price-panel tbody th { font-size:19px; }
 .vn-price-panel td { font-size:11px; }
 .vn-price-book { font-size:8px; }
 .vn-education__art { display:none; }
 .vn-education__grid { gap:0; }
 .vn-gallery .vn-photo { aspect-ratio:.8; }
}

/* ===================================================================
   HERO HEIGHT · RIBBON · SERVICE MENU
   =================================================================== */

/* Hero fills 85% of the viewport, with a floor so short laptop windows
   don't crush the copy and a ceiling so tall monitors don't strand the
   ribbon below the fold. */
.vn-hero {
  min-height: 85vh;
  display: flex;
  align-items: center;
  padding-block: clamp(2.5rem, 5vh, 5rem);
}
.vn-hero > .container { width: 100%; }
@media (max-width: 900px) {
  .vn-hero { min-height: 0; padding-block: clamp(2rem, 6vh, 3.5rem); }
}

/* The ribbon was the same olive as the services band below it, so the two
   read as one block and the strip lost its job as a divider. Plum separates
   them and puts another of the brand's six colours on the page. */
.vn-ribbon {
  background: var(--vv-plum);
  color: var(--vv-on-dark);
}
.vn-ribbon p { color: var(--vv-on-dark); }

/* ---- Service menu: light ground, cards carry the weight ---- */
.vn-services { background: var(--vv-surface); color: var(--vv-ink); }
.vn-services h2,
.vn-services .vn-section-head > div > p,
.vn-services__foot p { color: var(--vv-ink); }
.vn-services .vn-section-head > p { color: var(--vv-ink-soft); }
.vn-services .vn-kicker { color: var(--vv-moss-deep); }
.vn-services .vn-link { color: var(--vv-ink); border-color: var(--vv-line); }
.vn-services .vn-link:hover { background: var(--vv-ink); border-color: var(--vv-ink); color: var(--vv-on-dark); }

.vn-service-grid { gap: clamp(1.25rem, 2vw, 2rem); }

/* Cards in the Tralē manner: photo on top, body beneath, a hairline border
   rather than a fill, and an accent bar that wipes in on hover. */
.vn-service,
.vn-service:first-child,
.vn-service:last-child {
  position: relative;
  overflow: hidden;
  background: var(--vv-paper);
  border: 1px solid var(--vv-line-soft);
  border-radius: var(--vv-r-lg);
  box-shadow: var(--vv-sh-sm);
  transition: transform var(--vv-normal) var(--vv-ease),
              box-shadow var(--vv-normal) var(--vv-ease),
              border-color var(--vv-normal) var(--vv-ease);
}
.vn-service::before {
  content: "";
  position: absolute;
  inset: 0 0 auto 0;
  height: 3px;
  background: var(--vv-moss);
  transform: scaleX(0);
  transform-origin: left;
  transition: transform var(--vv-normal) var(--vv-ease);
  z-index: 2;
}
.vn-service:hover {
  transform: translateY(-6px);
  box-shadow: var(--vv-sh-lg);
  border-color: var(--vv-line);
  background: var(--vv-paper);
}
.vn-service:hover::before { transform: scaleX(1); }

.vn-service__photo { aspect-ratio: 4 / 5; border-radius: 0; }
.vn-service__body { padding: clamp(1.25rem, 2vw, 1.75rem); }

/* Price line reads as a label + figure, not as body text. */
.vn-service__top {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--vv-sp-3);
  margin-bottom: var(--vv-sp-3);
  padding-bottom: var(--vv-sp-3);
  border-bottom: 1px solid var(--vv-line-soft);
  font-size: var(--vv-tiny);
  text-transform: uppercase;
  letter-spacing: var(--vv-ls-wide);
  color: var(--vv-mute);
}
/* The markup is <span>From $60</span><span aria-hidden>↗</span> — the PRICE is
   the first child, not the last. Styling :last-child dressed the arrow as the
   headline figure and left the price in small caps. */
.vn-service__top > span:first-child {
  font-family: var(--vv-display);
  font-size: 1.45rem;
  letter-spacing: 0;
  text-transform: none;
  color: var(--vv-moss-deep);
  font-variant-numeric: lining-nums tabular-nums;
}
.vn-service__top > span[aria-hidden] {
  font-size: 1rem;
  color: var(--vv-mute);
  transition: transform var(--vv-normal) var(--vv-ease), color var(--vv-normal) var(--vv-ease);
}
.vn-service:hover .vn-service__top > span[aria-hidden] {
  transform: translate(3px, -3px);
  color: var(--vv-moss-deep);
}
.vn-service h3 { color: var(--vv-ink); margin-bottom: var(--vv-sp-2); }
.vn-service p  { color: var(--vv-ink-soft); }

/* ---- Service cards: square photo, white body, price as a pill ---- */
.vn-service__photo { aspect-ratio: 1; }

.vn-service,
.vn-service:first-child,
.vn-service:last-child,
.vn-service:hover { background: var(--vv-surface); }
.vn-service__body { background: var(--vv-surface); }

/* The price moves out of the body and sits on the photo, top right. The rule
   and bottom margin that separated it from the title are no longer needed. */
.vn-service { position: relative; }
.vn-service__top {
  position: absolute;
  top: var(--vv-sp-4);
  right: var(--vv-sp-4);
  z-index: 3;
  margin: 0;
  padding: .3rem .8rem;
  border: 0;
  border-radius: var(--vv-r-full);
  background: color-mix(in srgb, var(--vv-surface) 92%, transparent);
  backdrop-filter: blur(6px);
  box-shadow: var(--vv-sh-sm);
  gap: 0;
}
.vn-service__top > span:first-child {
  font-family: var(--vv-body);
  font-size: var(--vv-tiny);
  font-weight: 600;
  letter-spacing: var(--vv-ls-tight);
  text-transform: uppercase;
  color: var(--vv-moss-deep);
}
/* The whole card is a link and lifts on hover, so a separate arrow in the
   badge only crowds it. */
.vn-service__top > span[aria-hidden] { display: none; }

.vn-service__body > h3 { margin-top: 0; }

/* ===================================================================
   PRICING TABS — review fixes
   =================================================================== */

/* #2 Tabs hug their labels instead of stretching across 1340px, and sit on a
      visible track so the strip reads as a tab bar rather than one dark block
      and four floating words. */
.vn-price-tabs {
  gap: var(--vv-sp-1);
  border-bottom: 1px solid var(--vv-line);
  scrollbar-width: none;
}
.vn-price-tabs::-webkit-scrollbar { display: none; }
.vn-price-tabs button {
  flex: 0 0 auto;
  padding: 1rem 1.5rem;
  border-radius: var(--vv-r-md) var(--vv-r-md) 0 0;
  color: var(--vv-ink-soft);
}

/* #1 No fixed floor — the wrapper animates to the active panel instead. */
.vn-price-panels {
  overflow: hidden;
  transition: height var(--vv-normal) var(--vv-ease);
}
.vn-price-panel { min-height: 0; padding-bottom: var(--vv-sp-6); }
.vn-price-description { min-height: 0; margin-bottom: var(--vv-sp-5); }

/* #6 Tighter columns — 65% for the name pushed Time and Price far apart. */
.vn-price-panel th:first-child  { width: 56%; }
.vn-price-panel th:nth-child(2) { width: 22%; text-align: right; }
.vn-price-panel th:last-child   { width: 22%; }
.vn-price-panel td:nth-child(2) { text-align: right; }

/* #3 The price is what people scan for, so it carries the display face — the
      service name was set in Cormorant at 22px while the price sat in 13px
      sans, which inverted the hierarchy and broke with the cards and pills. */
.vn-price-amount {
  font-family: var(--vv-display);
  font-size: calc(1.35rem * var(--vv-scale));
  line-height: 1;
  color: var(--vv-moss-deep);
  font-variant-numeric: lining-nums tabular-nums;
}
.vn-price-from {
  font-size: var(--vv-tiny);
  font-style: italic;
  color: var(--vv-mute);
}
.vn-price-panel td:nth-child(2) {
  font-size: var(--vv-tiny);
  text-transform: uppercase;
  letter-spacing: var(--vv-ls-wide);
  color: var(--vv-mute);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

/* #4 "Book this service" was printed on every row, starting at a different x
      each time. It is screen-reader text now; the arrow appears on hover or
      keyboard focus, and the whole row highlights. */
.vn-price-panel tbody tr { transition: background var(--vv-fast) var(--vv-ease); }
.vn-price-panel tbody tr:hover { background: color-mix(in srgb, var(--vv-butter) 22%, transparent); }
.vn-price-panel tbody th a { display: inline-flex; align-items: baseline; gap: .5rem; }
.vn-price-arrow {
  font-size: .85em;
  color: var(--vv-moss-deep);
  opacity: 0;
  transform: translate(-4px, 4px);
  transition: opacity var(--vv-fast) var(--vv-ease), transform var(--vv-fast) var(--vv-ease);
}
.vn-price-panel tbody tr:hover .vn-price-arrow,
.vn-price-panel tbody th a:focus-visible .vn-price-arrow { opacity: 1; transform: none; }

/* #5 The deposit is the first thing a new client asks about, and it was
      nowhere near the prices. Text comes from the Customizer booking section. */
.vn-price-notes {
  display: flex;
  flex-wrap: wrap;
  gap: var(--vv-sp-3) var(--vv-sp-8);
  align-items: baseline;
  margin-top: var(--vv-sp-5);
}
.vn-price-deposit {
  margin: 0;
  font-size: var(--vv-small);
  color: var(--vv-ink);
  padding-left: var(--vv-sp-4);
  border-left: 2px solid var(--vv-moss);
}
.vn-price-note { margin: 0; max-width: 42rem; }

@media (max-width: 640px) {
  .vn-price-panel th:first-child  { width: 50%; }
  .vn-price-panel th:nth-child(2) { width: 24%; }
  .vn-price-panel th:last-child   { width: 26%; }
  .vn-price-notes { flex-direction: column; gap: var(--vv-sp-4); }
}

/* ===================================================================
   GALLERY CAROUSEL
   Same mechanism as the Avalon build: a scroll-snap filmstrip rather than a
   transform slider, so native touch, trackpad and keyboard scrolling all work
   for free and there is no JS position state to drift. JS only draws the dots
   and drives the arrows.
   =================================================================== */
.vn-gallery { overflow: hidden; }

.vn-gallery__carousel {
  position: relative;
  /* Break out of .container so slides can bleed to the viewport edge. */
  margin-inline: calc(50% - 50vw);
  margin-top: var(--vv-sp-10);
}

.vn-gal-track {
  --vn-gal-edge: max(var(--vv-gutter), calc((100vw - var(--vv-container)) / 2 + var(--vv-gutter)));
  display: flex;
  gap: clamp(.9rem, 1.4vw, 1.35rem);
  list-style: none;
  margin: 0;
  padding: .5rem var(--vn-gal-edge) 1.5rem;
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  scroll-behavior: smooth;
  scrollbar-width: none;
  -webkit-overflow-scrolling: touch;
}
.vn-gal-track::-webkit-scrollbar { display: none; }

.vn-gal-slide {
  flex: 0 0 auto;
  width: clamp(230px, 24vw, 330px);
  scroll-snap-align: center;
  list-style: none;
}

.vn-gal-card {
  aspect-ratio: 4 / 5;
  border-radius: var(--vv-r-lg);
  overflow: hidden;
  background: var(--vv-paper-2);
  box-shadow: var(--vv-sh-md);
  transition: transform var(--vv-normal) var(--vv-ease), box-shadow var(--vv-normal) var(--vv-ease);
}
/* .vn-photo img is absolutely positioned at width/height 130% with a -15%/-10%
   offset (a zoom hack). Overriding only the size left the offset in place, so
   the image sat 10% high and a band of the card showed through underneath.
   Reset the box outright. */
.vn-gal-card img {
  position: absolute;
  inset: 0;
  width: 100%; height: 100%;
  max-width: none;
  object-fit: cover;
  object-position: center top;
  transition: transform var(--vv-slow) var(--vv-ease);
}
.vn-gal-slide:hover .vn-gal-card { transform: translateY(-4px); box-shadow: var(--vv-sh-lg); }
.vn-gal-slide:hover .vn-gal-card img { transform: scale(1.04); }

/* ---- Arrows ---- */
.vn-gal-arrow {
  position: absolute;
  top: calc(50% - 1.5rem);
  transform: translateY(-50%);
  z-index: 3;
  width: 48px; height: 48px;
  display: grid; place-items: center;
  border-radius: var(--vv-r-full);
  background: var(--vv-surface);
  color: var(--vv-ink);
  border: 1px solid var(--vv-line-soft);
  box-shadow: var(--vv-sh-lg);
  transition: background var(--vv-fast) var(--vv-ease), color var(--vv-fast) var(--vv-ease),
              transform var(--vv-fast) var(--vv-ease), opacity var(--vv-fast) var(--vv-ease);
}
.vn-gal-arrow svg { width: 20px; height: 20px; }
.vn-gal-arrow:hover { background: var(--vv-olive); color: var(--vv-on-dark); border-color: var(--vv-olive); }
.vn-gal-arrow--prev { left: clamp(.5rem, 2vw, 1.75rem); }
.vn-gal-arrow--next { right: clamp(.5rem, 2vw, 1.75rem); }
.vn-gal-arrow[hidden] { display: none; }

/* ---- Dots ---- */
.vn-gal-dots {
  display: flex; justify-content: center; align-items: center; gap: 2px;
  list-style: none; padding: 0; margin: var(--vv-sp-4) 0 var(--vv-sp-8);
}
.vn-gal-dots li { display: flex; list-style: none; }
.vn-gal-dots button {
  width: 30px; height: 30px;
  display: grid; place-items: center;
  background: none; border: 0; padding: 0;
  -webkit-tap-highlight-color: transparent;
}
.vn-gal-dots button::before {
  content: ""; display: block;
  width: 7px; height: 7px;
  border-radius: var(--vv-r-full);
  background: var(--vv-line);
  transition: width var(--vv-normal) var(--vv-ease), background var(--vv-normal) var(--vv-ease);
}
.vn-gal-dots button:hover::before { background: var(--vv-mute); }
.vn-gal-dots button.is-active::before { width: 24px; background: var(--vv-moss); }

@media (max-width: 640px) {
  .vn-gal-arrow { display: none; }   /* swipe is the affordance on touch */
  .vn-gal-slide { width: 72vw; }
}

/* =========================================================================
   0.14.0 — EDITORIAL RHYTHM PASS
   The page had run four near-identical cream sections back to back
   (services → pricing → gallery → story, over half its height). The
   reference build never lets two sections share a ground. Two changes fix
   it: a new dark pillar band, and the gallery flipped to dark — giving
   light / dark / light / dark / light / dark from the ribbon down.
   ====================================================================== */

/* --- Italic accent -------------------------------------------------------
   One italicised word per headline. Without it a page of identical serif
   heads reads flat no matter how good the type is. */
.vn-hero .vn-em,
.section--dark .vn-em,
.vn-pillars .vn-em,
.vn-gallery .vn-em,
.vn-quotes .vn-em,
.vn-education .vn-em,
.vn-visit .vn-em { color: var(--vv-butter); }

/* --- Section heads -------------------------------------------------------
   A hairline above the eyebrow gives each section a deliberate top edge. */
.vn-section-head .vn-kicker { position: relative; padding-top: 18px; }
.vn-section-head .vn-kicker::before {
  content: ""; position: absolute; top: 0; left: 0;
  width: 46px; height: 1px; background: currentColor; opacity: .55;
}
.vn-section-head--center { justify-content: center; text-align: center; }
.vn-section-head--center > div { max-width: 640px; }
.vn-section-head--center .vn-kicker::before { left: 50%; transform: translateX(-50%); }

/* --- 02 · The Vivid standard (dark pillar band) --------------------------
   Restored from the hidden .vn-care grid. Three numbered promises on dark,
   the same device the reference uses for "why clients stay with us". */
.vn-pillars {
  background: var(--vv-ink);
  color: var(--vv-on-dark);
  position: relative;
}
.vn-pillars h2 { color: var(--vv-surface); }
.vn-pillars .vn-kicker { color: var(--vv-butter); }
.vn-pillars .vn-section-head { margin-bottom: 54px; }

.vn-pillars .vn-care { display: grid; grid-template-columns: repeat(3, 1fr); gap: 0; padding-top: 0; }
.vn-pillars .vn-care > div {
  display: block;
  padding: 38px 40px 42px;
  border-left: 1px solid rgba(248, 245, 243, .16);
  transition: background var(--vv-normal) var(--vv-ease);
}
.vn-pillars .vn-care > div:last-child { border-right: 1px solid rgba(248, 245, 243, .16); }
.vn-pillars .vn-care > div:hover { background: rgba(248, 245, 243, .05); }
.vn-pillars .vn-care__n {
  display: block;
  font-family: var(--vv-display);
  font-size: calc(72px * var(--vv-scale));
  font-weight: 400;
  line-height: 1;
  color: var(--vv-butter);
  margin-bottom: 26px;
  letter-spacing: -.02em;
}
.vn-pillars .vn-care h3 {
  font-family: var(--vv-display);
  font-size: calc(34px * var(--vv-scale));
  font-weight: var(--vv-weight-head);
  line-height: 1.2;
  color: var(--vv-surface);
  letter-spacing: -.02em;
  margin: 0 0 14px;
  text-transform: none;
}
.vn-pillars .vn-care p {
  font-size: 13px; line-height: 1.65;
  color: var(--vv-on-dark-mute);
  margin: 0; max-width: 30ch;
}

/* --- 03 · Gallery on dark ------------------------------------------------
   Flipped from cream so the run of light sections breaks, and so the work
   itself is what carries the band. */
.vn-gallery { background: var(--vv-ink); color: var(--vv-on-dark); }
.vn-gallery h2 { color: var(--vv-surface); }
.vn-gallery .vn-kicker { color: var(--vv-butter); }
.vn-gallery .vn-section-head > p { color: var(--vv-on-dark-mute); }
.vn-gallery .vn-gal-card { background: rgba(248, 245, 243, .07); }
.vn-gallery .vn-gal-arrow {
  background: rgba(248, 245, 243, .1);
  border-color: rgba(248, 245, 243, .22);
  color: var(--vv-surface);
}
.vn-gallery .vn-gal-arrow:hover {
  background: var(--vv-butter); border-color: var(--vv-butter); color: var(--vv-ink);
}
.vn-gallery .vn-gal-dots button::before { background: rgba(248, 245, 243, .3); }
.vn-gallery .vn-gal-dots button:hover::before { background: rgba(248, 245, 243, .55); }
.vn-gallery .vn-gal-dots button.is-active::before { background: var(--vv-butter); }
.vn-gallery .vn-link { border-color: rgba(248, 245, 243, .3); color: var(--vv-surface); }
.vn-gallery .vn-link:hover {
  background: var(--vv-butter); border-color: var(--vv-butter); color: var(--vv-ink);
}

/* --- 04 · Story stats ----------------------------------------------------
   Were 52px numerals crammed beside 10px labels. Given room, they read as
   a deliberate statement rather than a footnote. */
.vn-stats { gap: 0; margin-top: 42px; padding-top: 0; border-top: 0; }
.vn-stats > div {
  display: block;
  flex: 1;
  padding: 24px 28px 4px 0;
  border-top: 1px solid var(--vv-ink);
}
.vn-stats > div + div { padding-left: 28px; border-left: 1px solid var(--vv-line); }
.vn-stats strong {
  display: block;
  font: 400 calc(62px * var(--vv-scale))/.9 var(--vv-display);
  color: var(--vv-plum-deep);
  letter-spacing: -.03em;
  margin-bottom: 10px;
}
.vn-stats span {
  display: block; max-width: 14ch;
  font-size: 11px; letter-spacing: .08em; text-transform: uppercase;
  color: var(--vv-mute); line-height: 1.5;
}

@media (max-width: 900px) {
  .vn-pillars .vn-care { grid-template-columns: 1fr; }
  .vn-pillars .vn-care > div {
    border-left: 0; border-top: 1px solid rgba(248, 245, 243, .16);
    padding: 28px 0 30px;
  }
  .vn-pillars .vn-care > div:last-child { border-right: 0; }
  .vn-pillars .vn-care > div:hover { background: none; }
  .vn-pillars .vn-care__n { margin-bottom: 16px; }
  .vn-pillars .vn-section-head { margin-bottom: 30px; }
  .vn-stats > div { padding: 18px 0 4px; }
  .vn-stats > div + div { padding-left: 0; border-left: 0; }
}

/* --- 06 · Before you book (FAQ) ------------------------------------------
   Light ground on purpose: it sits between the education band and the closing
   CTA, which are both dark, and keeps them from running together.
   Centred head — every other section on the page is left-aligned or split,
   so this reads as a deliberate change of pace before the close. */
.vn-faq { background: var(--vv-surface); }
.vn-faq .vn-section-head { margin-bottom: 42px; }
.vn-faq__intro {
  margin: 18px auto 0;
  max-width: 46ch;
  font-size: 14px;
  line-height: 1.7;
  color: var(--vv-ink-soft);
}

.vn-faq__list {
  max-width: 860px;
  margin: 0 auto;
  border-top: 1px solid var(--vv-line);
}
.vn-faq__item { border-bottom: 1px solid var(--vv-line); }

.vn-faq__q {
  list-style: none;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 28px;
  padding: 22px 4px;
  font-family: var(--vv-display);
  font-size: calc(26px * var(--vv-scale));
  font-weight: var(--vv-weight-head);
  line-height: 1.35;
  letter-spacing: -.02em;
  color: var(--vv-ink);
  text-transform: none;
  transition: color var(--vv-fast) var(--vv-ease);
}
.vn-faq__q::-webkit-details-marker { display: none; }
.vn-faq__q::marker { content: ""; }
.vn-faq__q:hover { color: var(--vv-plum-deep); }
.vn-faq__item:focus-within .vn-faq__q { color: var(--vv-plum-deep); }

/* Plus that becomes a minus. Rotating rather than swapping glyphs keeps the
   open/closed states visually continuous. */
.vn-faq__icon {
  flex: none;
  position: relative;
  width: 34px;
  height: 34px;
  border: 1px solid var(--vv-line);
  border-radius: 50%;
  transition: background var(--vv-normal) var(--vv-ease),
              border-color var(--vv-normal) var(--vv-ease),
              transform var(--vv-normal) var(--vv-ease);
}
.vn-faq__icon::before,
.vn-faq__icon::after {
  content: "";
  position: absolute;
  inset: 50% auto auto 50%;
  width: 13px;
  height: 1.4px;
  background: var(--vv-ink);
  transform: translate(-50%, -50%);
  transition: opacity var(--vv-fast) var(--vv-ease),
              transform var(--vv-normal) var(--vv-ease),
              background var(--vv-normal) var(--vv-ease);
}
.vn-faq__icon::after { transform: translate(-50%, -50%) rotate(90deg); }
.vn-faq__q:hover .vn-faq__icon { border-color: var(--vv-plum-deep); }
.vn-faq__item[open] .vn-faq__icon {
  background: var(--vv-plum-deep);
  border-color: var(--vv-plum-deep);
  transform: rotate(180deg);
}
.vn-faq__item[open] .vn-faq__icon::before,
.vn-faq__item[open] .vn-faq__icon::after { background: var(--vv-surface); }
.vn-faq__item[open] .vn-faq__icon::after { transform: translate(-50%, -50%) rotate(0deg); opacity: 0; }

.vn-faq__a {
  padding: 0 68px 26px 4px;
  color: var(--vv-ink-soft);
  font-size: 14px;
  line-height: 1.75;
  max-width: 68ch;
}
.vn-faq__a > :last-child { margin-bottom: 0; }

.vn-faq__foot { margin: 40px 0 0; text-align: center; }

@media (prefers-reduced-motion: reduce) {
  .vn-faq__icon,
  .vn-faq__icon::before,
  .vn-faq__icon::after { transition: none; }
  .vn-faq__item[open] .vn-faq__icon { transform: none; }
}

@media (max-width: 720px) {
  .vn-faq__q { gap: 18px; padding: 18px 0; }
  .vn-faq__icon { width: 28px; height: 28px; }
  .vn-faq__icon::before, .vn-faq__icon::after { width: 11px; }
  .vn-faq__a { padding: 0 40px 22px 0; font-size: 13px; }
  .vn-faq__foot { margin-top: 30px; }
}

/* --- Closing CTA + footer (0.16.0) ---------------------------------------
   The homepage footer grid was display:none, so below the CTA there was
   nothing but a copyright strip: no brand mark, no navigation, no Instagram,
   and a wide band of dead olive. The grid is restored, with the two columns
   that would have repeated the CTA's own address and hours suppressed
   instead of the whole thing. */
.home .footer-grid { display: grid; }
.home .footer-col--visit,
.home .footer-col--hours { display: none; }
.home .footer-grid { grid-template-columns: minmax(0, 1.4fr) minmax(0, 1fr); gap: 60px; }
.home .site-footer { padding-top: 78px; }
.footer-social__label {
  display: block;
  font-size: 10px;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--vv-on-dark-mute);
  margin-bottom: 8px;
}
.footer-social__handle {
  display: flex;
  align-items: center;
  gap: 9px;
  font-family: var(--vv-display);
  font-size: calc(30px * var(--vv-scale));
  line-height: 1.2;
  color: var(--vv-surface);
  transition: color var(--vv-fast) var(--vv-ease);
}
.footer-social__handle > span {
  font-family: var(--vv-body);
  font-size: .62em;
  transition: transform var(--vv-normal) var(--vv-ease);
}
.home .footer-bottom { margin-top: 0; border-top: 1px solid rgba(248, 245, 243, .13); padding-top: 26px; }

@media (max-width: 900px) {
  .home .footer-grid,
  .site-footer .footer-grid { grid-template-columns: 1fr; gap: 42px; }
  .site-footer { padding-top: 54px; }
  .home .site-footer { padding-top: 54px; }
  .vn-visit__details { margin-top: 42px; padding-top: 34px; }
}

@media (max-width: 560px) {
  .footer-col--explore ul { grid-template-columns: 1fr; gap: 12px; }
}

@supports not (background: color-mix(in srgb, red 50%, transparent)) {
  .vn-visit::before { background: rgba(74, 78, 46, .82); }
}

/* --- 05 · In their own words (testimonials) ------------------------------
   Photo-backed dark band, matching the reference's review section. It sits
   between the story (light) and the education band (plum), so the backdrop
   is doing the work of telling two dark sections apart — without it they
   would read as one slab.

   Overlay measured the same way as the closing CTA: lightest pixel behind
   each text band, checked against both text colours. */
.vn-quotes {
  position: relative;
  isolation: isolate;
  overflow: hidden;
  color: var(--vv-on-dark);
}
.vn-quotes__backdrop { position: absolute; inset: 0; z-index: -2; }
.vn-quotes__backdrop img {
  width: 100%; height: 100%; max-width: none;
  object-fit: cover; object-position: center 35%;
}
.vn-quotes::before {
  content: "";
  position: absolute; inset: 0; z-index: -1;
  background:
    linear-gradient(180deg,
      color-mix(in srgb, var(--vv-ink) 88%, transparent) 0%,
      color-mix(in srgb, var(--vv-ink) 82%, transparent) 50%,
      color-mix(in srgb, var(--vv-ink) 90%, transparent) 100%),
    linear-gradient(180deg, rgba(16,13,15,.34), rgba(16,13,15,.46));
}
@supports not (background: color-mix(in srgb, red 50%, transparent)) {
  .vn-quotes::before { background: rgba(28, 24, 27, .93); }
}

.vn-quotes h2 { color: var(--vv-surface); }
.vn-quotes .vn-kicker { color: var(--vv-butter); }
.vn-quotes .vn-section-head { margin-bottom: 52px; }
.vn-quotes__intro {
  margin: 18px auto 0;
  max-width: 44ch;
  font-size: 14px;
  line-height: 1.7;
  color: var(--vv-on-dark-mute);
}

.vn-quotes__grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(275px, 1fr));
  gap: 24px;
  list-style: none;
  margin: 0;
  padding: 0;
}
.vn-quote {
  display: flex;
  flex-direction: column;
  padding: 34px 34px 30px;
  background: rgba(248, 245, 243, .07);
  border: 1px solid rgba(248, 245, 243, .16);
  border-radius: var(--vv-r-sm);
  backdrop-filter: blur(2px);
  transition: background var(--vv-normal) var(--vv-ease),
              border-color var(--vv-normal) var(--vv-ease),
              transform var(--vv-normal) var(--vv-ease);
}
.vn-quote:hover {
  background: rgba(248, 245, 243, .1);
  border-color: rgba(240, 232, 160, .38);
  transform: translateY(-3px);
}

.vn-quote__stars {
  margin: 0 0 18px;
  font-size: 14px;
  letter-spacing: .18em;
  color: var(--vv-butter);
  line-height: 1;
}

.vn-quote__text { margin: 0; flex: 1; }
.vn-quote__text p {
  margin: 0;
  font-family: var(--vv-display);
  font-size: calc(24px * var(--vv-scale));
  line-height: 1.5;
  letter-spacing: -.01em;
  color: var(--vv-surface);
}
/* Hanging opening quote, so the mark sits outside the text block. */
.vn-quote__text p::before {
  content: "\201C";
  margin-left: -.42em;
  color: var(--vv-butter);
}

.vn-quote__by {
  margin-top: 26px;
  padding-top: 20px;
  border-top: 1px solid rgba(248, 245, 243, .16);
}
.vn-quote__by cite {
  display: block;
  font-style: normal;
  font-size: 12px;
  font-weight: 600;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--vv-surface);
}
.vn-quote__by span {
  display: block;
  margin-top: 5px;
  font-size: 12px;
  color: var(--vv-on-dark-mute);
}

@media (prefers-reduced-motion: reduce) {
  .vn-quote, .vn-quote:hover { transition: none; transform: none; }
}

@media (max-width: 720px) {
  .vn-quotes__grid { grid-template-columns: 1fr; gap: 16px; }
  .vn-quote { padding: 26px 24px 24px; }
  .vn-quotes .vn-section-head { margin-bottom: 34px; }
}

/* --- Gallery carousel arrows (0.19.0) ------------------------------------
   Flipping the gallery to dark in 0.14.0 replaced the solid arrows with a 10%
   white wash, which made them almost invisible against the photographs. Solid
   butter instead: it is the one colour on this band nothing else uses, so the
   controls read as controls rather than as part of a slide. */
.vn-gallery .vn-gal-arrow {
  width: 58px;
  height: 58px;
  background: var(--vv-butter);
  border-color: var(--vv-butter);
  color: var(--vv-ink);
  box-shadow: 0 10px 30px rgba(16, 13, 15, .45);
}
.vn-gallery .vn-gal-arrow svg {
  width: 22px;
  height: 22px;
  stroke-width: 2;
}
.vn-gallery .vn-gal-arrow:hover,
.vn-gallery .vn-gal-arrow:focus-visible {
  background: var(--vv-surface);
  border-color: var(--vv-surface);
  color: var(--vv-ink);
  box-shadow: 0 12px 34px rgba(16, 13, 15, .55);
}
.vn-gallery .vn-gal-arrow:active { transform: translateY(-50%) scale(.94); }

/* Sit them just off the filmstrip edge rather than on top of a slide. */
.vn-gallery .vn-gal-arrow--prev { left: clamp(.35rem, 1.2vw, 1rem); }
.vn-gallery .vn-gal-arrow--next { right: clamp(.35rem, 1.2vw, 1rem); }

/* Dots stay below, and now carry a little more weight so the pair reads as
   one control group. */
.vn-gallery .vn-gal-dots { margin-top: 34px; gap: 10px; }
.vn-gallery .vn-gal-dots button::before { height: 3px; border-radius: 2px; }
.vn-gallery .vn-gal-dots button.is-active::before { width: 30px; }

/* Previously hidden outright below 640px. Kept now — the client asked for
   prominent arrows — just scaled down so they do not cover the artwork. */
@media (max-width: 640px) {
  .vn-gallery .vn-gal-arrow { display: grid; width: 44px; height: 44px; }
  .vn-gallery .vn-gal-arrow svg { width: 18px; height: 18px; }
  .vn-gallery .vn-gal-dots { margin-top: 26px; }
}

/* =========================================================================
   0.19.0 — READABILITY, CTA GRADIENT, FOOTER BALANCE
   ====================================================================== */

/* --- Body copy ------------------------------------------------------------
   `body` is 17px but the home sections overrode it down to 12–14px, so the
   page read as small everywhere below the headings. Headings scale through
   --vv-scale (0.7); these are fixed px and were never part of that, so they
   are raised directly. Nothing here goes below 14px. */
.vn-intro { font-size: 16px; line-height: 1.7; }
.vn-section-head > p,
.vn-section-head > div > p:not(.vn-kicker) { font-size: 15px; line-height: 1.65; }
.vn-service p { font-size: 14.5px; line-height: 1.65; max-width: 32ch; }
.vn-services__foot p { font-size: 13px; line-height: 1.6; }
.vn-pillars .vn-care p { font-size: 14.5px; line-height: 1.7; }
.vn-story__copy p:not(.vn-kicker) { font-size: 15px; line-height: 1.75; }
.vn-story .vn-lead { font-size: 17px; line-height: 1.65; }
.vn-education__grid > div > p:not(.vn-kicker) { font-size: 15px; line-height: 1.7; }
.vn-faq__intro,
.vn-quotes__intro { font-size: 15.5px; }
.vn-faq__a { font-size: 15.5px; line-height: 1.8; }
.vn-quote__by span { font-size: 13.5px; }
.vn-price-panel p,
.vn-price-panel td { font-size: 15px; }

@media (max-width: 720px) {
  .vn-intro, .vn-visit__intro { font-size: 15px; }
  .vn-faq__a, .vn-faq__intro, .vn-quotes__intro { font-size: 15px; }
}
@supports not (background: color-mix(in srgb, red 50%, transparent)) {
  .vn-visit .vn-link { background: rgba(248,245,243,.14); border-color: rgba(248,245,243,.55); }
}
@supports not (background: color-mix(in srgb, red 50%, transparent)) {
  .vn-visit::before { background: linear-gradient(180deg, rgba(74,78,46,.80), rgba(74,78,46,.97)); }
}

/* --- Footer balance -------------------------------------------------------
   Two short columns left a wide void above the legal bar. A third column
   carrying the booking action fills the width with something useful rather
   than repeating the address and hours printed directly above it. */
.home .footer-grid {
  grid-template-columns: minmax(0, 1.15fr) minmax(0, .95fr) minmax(0, 1.1fr);
  gap: 52px;
}
.home .site-footer { padding-top: 64px; }

@media (max-width: 980px) {
  .home .footer-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 40px; }
  .footer-col--brand { grid-column: 1 / -1; }
}
@media (max-width: 640px) {
  .home .footer-grid,
  .site-footer .footer-grid { grid-template-columns: 1fr; gap: 34px; }
  .footer-col--brand { grid-column: auto; }
}

/* The hero lead is set by `.vn-hero .vn-intro` (0,2,0), which out-specifies the
   `.vn-intro` sizing above — it stayed at 14px desktop / 12px on phones while
   everything around it grew. Matched specificity so it tracks the rest. */
.vn-hero .vn-intro { font-size: 16px; line-height: 1.7; max-width: 430px; }
@media (max-width: 720px) { .vn-hero .vn-intro { font-size: 15px; max-width: 100%; } }
@media (max-width: 480px) { .vn-hero .vn-intro { font-size: 14.5px; } }

/* --- 05 · Learn with CiCi — right panel (0.20.0) -------------------------
   An earlier override stripped this block to a bare left border and hid its
   mark and signature, leaving three words floating with nothing anchoring
   them. Rebuilt as a defined panel: the stages are a sequence, so they are
   rows with rules between them rather than one centred block of type. */
.vn-education__grid { align-items: stretch; }

.vn-education__art {
  display: flex;
  flex-direction: column;
  border: 1px solid rgba(248, 245, 243, .2);
  border-radius: var(--vv-r-sm);
  border-left-width: 1px;
  padding: 34px 38px 30px;
  text-align: left;
  background: rgba(248, 245, 243, .04);
}

.vn-education__mark {
  display: block;
  width: 34px;
  color: var(--vv-butter);
  margin-bottom: 24px;
}
.vn-education__mark svg { width: 100%; height: auto; display: block; }

.vn-education__stages {
  list-style: none;
  margin: 0;
  padding: 0;
  flex: 1;
  display: flex;
  flex-direction: column;
  justify-content: center;
  border-top: 1px solid rgba(248, 245, 243, .16);
}
.vn-education__stages li {
  padding: 20px 0;
  border-bottom: 1px solid rgba(248, 245, 243, .16);
  font-family: var(--vv-display);
  font-size: calc(52px * var(--vv-scale));
  line-height: 1.05;
  letter-spacing: -.035em;
  color: var(--vv-butter);
  display: flex;
  align-items: baseline;
  gap: 16px;
}
/* A small index keeps the three rows visually ordered without competing with
   the numbered pillars earlier on the page. */
.vn-education__stages li::before {
  content: counter(vn-stage, decimal-leading-zero);
  counter-increment: vn-stage;
  font-family: var(--vv-body);
  font-size: 11px;
  font-weight: 600;
  letter-spacing: .14em;
  color: var(--vv-on-dark-mute);
  flex: none;
}
.vn-education__stages { counter-reset: vn-stage; }

@media (max-width: 900px) {
  .vn-education__art { padding: 28px 26px 24px; max-width: none; }
  .vn-education__stages li { font-size: calc(46px * var(--vv-scale)); padding: 16px 0; }
}
/* Was hidden outright below 640px; it is the section's only visual, so it
   stays — just tightened. */
@media (max-width: 640px) {
  .vn-education__art { display: flex; }
  .vn-education__stages li { font-size: calc(42px * var(--vv-scale)); padding: 14px 0; gap: 12px; }
  .vn-education__mark { margin-bottom: 18px; }
}

/* --- FAQ questions off the display face ---------------------------------
   Playfair at question size read as another headline competing with the
   section head. The body face makes them read as controls you open. */
.vn-faq__q {
  font-family: var(--vv-body);
  font-size: 17px;
  font-weight: 500;
  line-height: 1.45;
  letter-spacing: 0;
}
@media (max-width: 720px) { .vn-faq__q { font-size: 15.5px; } }

/* --- 05 panel, second pass -----------------------------------------------
   The panel was stretching to the left column's height, so three rows sat
   centred in a tall box with dead bands above and below, and a stray rule
   top and bottom made it read like a table with an empty header and footer.
   It now hugs its content and centres as a block. */
.vn-education__grid { align-items: center; }

.vn-education__art {
  align-self: center;
  padding: 30px 34px;
}

/* `.vn-education__art > span` was set to display:none by an earlier override
   (0,2,1), which out-specified the mark's own rule and left an empty band
   where it should be. */
.vn-education__art > .vn-education__mark { display: block; }

.vn-education__stages {
  flex: none;
  justify-content: flex-start;
  border-top: 0;
}
/* Rules between the rows only — not around the whole group. */
.vn-education__stages li { border-bottom: 0; padding: 14px 0; }
.vn-education__stages li + li {
  border-top: 1px solid rgba(248, 245, 243, .16);
}
.vn-education__stages li:first-child { padding-top: 0; }
.vn-education__stages li:last-child { padding-bottom: 0; }

@media (max-width: 900px) {
  .vn-education__stages li { padding: 12px 0; }
}

/* Three short words in a 550px panel left it looking half-empty; sized to the
   content it holds and centred in its column. */
/* `margin-inline:auto` alone makes a grid item shrink to its content — the
   panel collapsed to 234px. An explicit width keeps it filling up to the cap. */
.vn-education__art { width: 100%; max-width: 430px; margin-inline: auto; }
@media (max-width: 900px) { .vn-education__art { max-width: 460px; } }

/* --- 05 panel: boxed texture ---------------------------------------------
   A flat translucent wash read as an empty box. Texture is generated in CSS —
   an inline SVG grain plus a fine diagonal hatch — so it costs no asset
   request and scales to any panel size.

   Painted on ::after with the children lifted above it, rather than as the
   element's own background, so the grain can be tuned independently of the
   panel tint and never sits over the type. */
.vn-education__art {
  position: relative;
  background-color: rgba(248, 245, 243, .05);
  overflow: hidden;
}
.vn-education__art::after {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  z-index: 0;
  /* Light pooling only. The hatch and grain that used to live here now run
     across the whole section, and two overlapping textures moiré. */
  background: radial-gradient(130% 85% at 50% 0%, rgba(248, 245, 243, .07), transparent 62%);
}
/* Keep every child above the texture layer. */
.vn-education__mark,
.vn-education__stages { position: relative; z-index: 1; }

@media (prefers-reduced-motion: no-preference) {
  .vn-education__art::after { transition: opacity var(--vv-normal) var(--vv-ease); }
}

/* The index numbers were --vv-on-dark-mute (68% alpha). At 11px they need
   4.5:1 and measured 3.36:1 over the textured panel — the texture lightens
   the ground just enough to matter. The opaque token gives 5.11:1 and stays
   visually distinct from the butter words beside it. */
.vn-education__stages li::before { color: var(--vv-on-dark); opacity: 1; }

/* --- 05 · Section lattice -------------------------------------------------
   A 30px box grid rotated 45 degrees, across the whole section.

   Two crossed repeating gradients rather than a tiled image: lines at +45 and
   -45 with a 30px period intersect to form 30px squares standing on their
   corners, and it stays crisp at any zoom or density with no asset request.

   Painted on ::before beneath the content; the section already clips its own
   overflow, so the lattice cannot bleed past the band. */
.vn-education { position: relative; isolation: isolate; }
.vn-education::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  background-image:
    /* Overlay first — background layers stack with the first on top — so the
       lattice sits under a plum wash and reads as texture rather than as a
       grid drawn over the section. */
    linear-gradient(
      color-mix(in srgb, var(--vv-plum-deep) 58%, transparent),
      color-mix(in srgb, var(--vv-plum-deep) 58%, transparent)),
    repeating-linear-gradient(45deg,
      rgba(248, 245, 243, .07) 0 1px,
      transparent 1px 30px),
    repeating-linear-gradient(-45deg,
      rgba(248, 245, 243, .07) 0 1px,
      transparent 1px 30px);
}
/* The panel sits on the lattice rather than in it, so it keeps a solid tint. */
.vn-education__art { background-color: rgba(58, 45, 52, .5); backdrop-filter: blur(1px); }

@supports not (background: color-mix(in srgb, red 50%, transparent)) {
  .vn-education::before { background-color: rgba(58, 45, 52, .58); }
}

/* Four values instead of three on the About page. */
.vn-pillars .vn-care--four { grid-template-columns: repeat(4, minmax(0, 1fr)); }
@media (max-width: 1040px) {
  .vn-pillars .vn-care--four { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .vn-pillars .vn-care--four > div:nth-child(3) { border-left: 1px solid rgba(248, 245, 243, .16); }
}
@media (max-width: 640px) {
  .vn-pillars .vn-care--four { grid-template-columns: 1fr; }
  .vn-pillars .vn-care--four > div:nth-child(3) { border-left: 0; }
}

.vn-services-note {
  margin: 42px auto 0;
  max-width: 70ch;
  text-align: center;
  font-size: 13px;
  line-height: 1.7;
  color: var(--vv-on-dark-mute);
}

/* =========================================================================
   0.25.0 — WARMTH PASS
   The page ran dark from the values band down: ink, plum, olive, ink. On a
   nail-art site that reads sombre, and her own palette had the answer sitting
   unused — butter (#F3EAA2) appears 65 times as an accent and never once as a
   ground. The teaching band takes it, which lifts the middle of both the
   homepage and About and keeps the light/dark alternation intact.
   ====================================================================== */

.vn-education {
  background: var(--vv-butter);
  color: var(--vv-ink);
}
.vn-education h2 { color: var(--vv-ink); }
/* tan-deep measures 4.01:1 on butter. That clears AA for the large accent
   in the h2 (3:1) but not for a 10px eyebrow, which needs 4.5:1. */
.vn-education .vn-kicker { color: var(--vv-plum-deep); }
.vn-education .vn-em { color: var(--vv-tan-deep); }
.vn-education__grid > div > p:not(.vn-kicker) { color: var(--vv-ink-soft); }
.vn-education__note { color: var(--vv-ink-soft) !important; }

/* The light button was butter on plum; on butter it would disappear. */
.vn-button--light {
  background: var(--vv-olive);
  border-color: var(--vv-olive);
  color: var(--vv-on-dark);
}
.vn-button--light:hover {
  background: var(--vv-ink);
  border-color: var(--vv-ink);
  color: var(--vv-on-dark);
}

/* Lattice inverted: dark lines on a warm ground, under a butter wash so it
   stays texture rather than a drawn grid. */
.vn-education::before {
  background-image:
    linear-gradient(
      color-mix(in srgb, var(--vv-butter) 56%, transparent),
      color-mix(in srgb, var(--vv-butter) 56%, transparent)),
    repeating-linear-gradient(45deg,
      rgba(44, 38, 42, .10) 0 1px,
      transparent 1px 30px),
    repeating-linear-gradient(-45deg,
      rgba(44, 38, 42, .10) 0 1px,
      transparent 1px 30px);
}
@supports not (background: color-mix(in srgb, red 50%, transparent)) {
  .vn-education::before { background-color: rgba(243, 234, 162, .56); }
}

/* Panel becomes a clean card on the warm ground. */
.vn-education__art {
  background-color: var(--vv-surface);
  border-color: var(--vv-line);
  backdrop-filter: none;
}
.vn-education__art::after {
  background: radial-gradient(130% 85% at 50% 0%, rgba(44, 38, 42, .04), transparent 62%);
}
.vn-education__mark { color: var(--vv-tan-deep); }
.vn-education__stages { border-top-color: var(--vv-line); }
.vn-education__stages li { color: var(--vv-plum-deep); }
.vn-education__stages li + li { border-top-color: var(--vv-line); }
.vn-education__stages li::before { color: var(--vv-ink-soft); opacity: 1; }

/* The mark is delicate art-deco linework; at 34px in tan it washed out against
   the now-white panel. Larger and in plum-deep it holds. */
.vn-education .vn-education__mark { width: 42px; color: var(--vv-plum-deep); }

/* =========================================================================
   0.26.0 — PROPORTION PASS
   Fixes from an honest review: colour-blocking was standing in for design,
   and two large sections were doing very little work for their height.
   ====================================================================== */

/* --- 1 · Butter as a tint, not a slab ------------------------------------
   Full-strength #F3EAA2 across a whole band made the least important section
   the loudest thing on the page. The reference uses its accent sparingly —
   a chair, a button — never a field. The ground becomes a soft cream; the
   full-strength colour stays where it was already working, on the buttons
   and the accents, and now on the panel that holds the three stages. */
.vn-education {
  background: color-mix(in srgb, var(--vv-butter) 42%, var(--vv-surface));
}
@supports not (background: color-mix(in srgb, red 50%, transparent)) {
  .vn-education { background: #F6F1D3; }
}
.vn-education::before {
  background-image:
    linear-gradient(
      color-mix(in srgb, var(--vv-butter) 24%, transparent),
      color-mix(in srgb, var(--vv-butter) 24%, transparent)),
    repeating-linear-gradient(45deg, rgba(44, 38, 42, .085) 0 1px, transparent 1px 30px),
    repeating-linear-gradient(-45deg, rgba(44, 38, 42, .085) 0 1px, transparent 1px 30px);
}
/* The panel now carries the full-strength colour — a small, deliberate area
   of it instead of a full-width field. */
.vn-education__art {
  background-color: var(--vv-butter);
  border-color: color-mix(in srgb, var(--vv-ink) 18%, transparent);
}
@supports not (border-color: color-mix(in srgb, red 50%, transparent)) {
  .vn-education__art { border-color: rgba(44, 38, 42, .18); }
}
.vn-education__art::after { background: none; }

/* --- 2 · Closing CTA cut to its content ----------------------------------
   664px — 19.7% of the About page — for a headline, one button and three
   short columns. The story section, with three paragraphs, a photo and the
   stats, was 701px. */
.vn-visit { padding-block: 62px; }
.vn-visit__details { margin-top: 44px; padding-top: 34px; }
.vn-visit__intro { margin-bottom: 28px; }

/* --- 3 · Values band: fill the cells --------------------------------------
   Cells measured 66-71% filled: 311px wide holding ~210px of text, because a
   30ch cap was wrapping the copy far short of the column. The cap is the
   cell now. */
.vn-pillars .vn-care p { max-width: none; }
.vn-pillars .vn-care > div { padding: 32px 34px 34px; }
.vn-pillars { padding-block: 74px; }
.vn-pillars .vn-section-head { margin-bottom: 44px; }

/* --- 7 · Stats alignment --------------------------------------------------
   "Years in nail artistry" wrapped to two lines while "Years teaching" sat on
   one, so the rule under them read ragged. A shared min-height settles both. */
/* 2.6em was under the two-line height, so the wrapping label still sat
   taller than its neighbour. 3em clears both. */
.vn-stats span { min-height: 3em; }

/* Measured again: against the CONTENT box the cells were already ~99% full,
   so the sparseness was padding and band height, not wrapping. */
.vn-pillars .vn-care > div { padding: 26px 28px 28px; }
.vn-pillars { padding-block: 62px; }
.vn-visit { padding-block: 52px; }
.vn-visit__details { margin-top: 38px; padding-top: 30px; }

/* --- 5/6/7 · Story photo: bleed, crop, variety ---------------------------
   Three problems in one element.

   6 — every section on the page was a centred head or a symmetrical split.
   The reference varies: photographs that run off the viewport edge, panels
   that sit proud of their column. The story photo now bleeds off the left
   edge, which is the page's one asymmetric moment.

   7 — the "Colormasterci" watermark measures at 0.77-0.94 of the image
   height. A landscape frame anchored to the top shows roughly the upper 72%,
   which is above it. That removes the watermark from this slot without
   touching the file, and the bleed makes the wider crop look deliberate.

   5 — at this width the source is displayed near 1:1 rather than upscaled. */
@media (min-width: 901px) {
  .vn-story__grid {
    grid-template-columns: minmax(0, 1.05fr) minmax(0, 1fr);
    gap: 72px;
    align-items: center;
  }
  .vn-story__visual {
    padding: 0;
    /* Out to the viewport edge, whatever the container gutter happens to be. */
    margin-left: calc((100vw - min(100vw, var(--vv-container))) / -2 - var(--vv-gutter));
  }
  /* Measured on the source: the Instagram carousel badge occupies 0-7% of the
     image height and the watermark 77-94%. A 1.56 frame shows 66%, and at
     26% vertical position that window lands 9%-75% — clear of both. */
  .vn-story__visual > .vn-photo {
    aspect-ratio: 1.56;
    border-radius: 0 4px 4px 0;
  }
  .vn-story__visual > .vn-photo img {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    max-width: none;
    object-fit: cover;
    object-position: center 26%;
    border-radius: 0;
  }
}

/* --- Teaching band on inner pages (0.27.0) -------------------------------
   White ground on About, keeping the lattice. The homepage keeps the butter
   tint, where it breaks a long run of alternating neutrals; on About it sat
   directly under a dark band and a warm field was one accent too many. */
.vn-page .vn-education { background: var(--vv-surface); }
.vn-page .vn-education::before {
  background-image:
    repeating-linear-gradient(45deg, rgba(44, 38, 42, .075) 0 1px, transparent 1px 30px),
    repeating-linear-gradient(-45deg, rgba(44, 38, 42, .075) 0 1px, transparent 1px 30px);
}

/* --- Training page (0.28.0) ----------------------------------------------
   Six curriculum topics rather than three or four, so the grid runs 3x2 and
   the cell borders have to close on both rows. */
.vn-pillars .vn-care--six { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.vn-pillars .vn-care--six > div:nth-child(3n+1) { border-left: 0; }
.vn-pillars .vn-care--six > div:last-child { border-right: 0; }
.vn-pillars .vn-care--six > div:nth-child(n+4) {
  border-top: 1px solid rgba(248, 245, 243, .16);
}
.vn-curriculum .vn-quotes__intro { color: var(--vv-on-dark-mute); }

/* --- Course details -------------------------------------------------------
   A definition list, not a table: the three unknowns are rows that exist and
   are waiting, which is the honest state until she confirms them. */
.vn-course { background: var(--vv-surface); }
.vn-course__grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1.15fr);
  gap: 80px;
  align-items: start;
}
.vn-course__note {
  font-size: 15px;
  line-height: 1.75;
  color: var(--vv-ink-soft);
  max-width: 46ch;
  margin: 0 0 30px;
}
.vn-course__table { margin: 0; border-top: 1px solid var(--vv-line); }
.vn-course__table > div {
  display: grid;
  grid-template-columns: minmax(0, 8rem) minmax(0, 1fr);
  gap: 24px;
  align-items: baseline;
  padding: 20px 0;
  border-bottom: 1px solid var(--vv-line);
}
.vn-course__table dt {
  margin: 0;
  font-size: 11px;
  font-weight: 600;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--vv-mute);
}
.vn-course__table dd {
  margin: 0;
  font-family: var(--vv-display);
  font-size: calc(26px * var(--vv-scale));
  line-height: 1.35;
  letter-spacing: -.015em;
  color: var(--vv-ink);
}
/* A pending row reads as pending — not as a value. */
.vn-course__table .is-pending dd {
  font-family: var(--vv-body);
  font-size: 14px;
  font-style: italic;
  letter-spacing: 0;
  color: var(--vv-mute);
}

@media (max-width: 1040px) {
  .vn-pillars .vn-care--six { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .vn-pillars .vn-care--six > div:nth-child(3n+1) { border-left: 1px solid rgba(248, 245, 243, .16); }
  .vn-pillars .vn-care--six > div:nth-child(2n+1) { border-left: 0; }
  .vn-pillars .vn-care--six > div:nth-child(n+3) { border-top: 1px solid rgba(248, 245, 243, .16); }
}
@media (max-width: 900px) {
  .vn-course__grid { grid-template-columns: 1fr; gap: 40px; }
}
@media (max-width: 640px) {
  .vn-pillars .vn-care--six { grid-template-columns: 1fr; }
  .vn-pillars .vn-care--six > div { border-left: 0 !important; }
  .vn-course__table > div { grid-template-columns: 1fr; gap: 8px; }
}

/* --- Full service listing (0.29.0) ---------------------------------------
   The Services page shows every group at once — no tabs, nothing hidden
   behind a click. The homepage keeps the tabbed view, where the menu is a
   summary rather than the destination. */
.vn-price-full { border-top: 1px solid var(--vv-line); }

.vn-price-group {
  display: grid;
  grid-template-columns: minmax(0, 15rem) minmax(0, 1fr);
  gap: 48px;
  align-items: start;
  padding: 34px 0 30px;
  border-bottom: 1px solid var(--vv-line);
}
/* Sticky moved to the aside, which now wraps the head and the photographs. */
.vn-price-group__aside { position: sticky; top: calc(var(--vv-header-h) + 20px); }
.vn-price-group__head h3 {
  font-family: var(--vv-display);
  font-size: calc(34px * var(--vv-scale));
  font-weight: var(--vv-weight-head);
  line-height: 1.15;
  letter-spacing: -.025em;
  color: var(--vv-ink);
  margin: 0 0 10px;
  text-transform: none;
}
.vn-price-group__head p {
  margin: 0;
  font-size: 13.5px;
  line-height: 1.65;
  color: var(--vv-mute);
}

.vn-price-group table { width: 100%; border-collapse: collapse; }
/* The column headers repeat per group in the markup for screen readers, but
   only the first needs to be seen. */
.vn-price-group:not(:first-child) thead { display: none; }

@media (max-width: 860px) {
  .vn-price-group { grid-template-columns: 1fr; gap: 18px; padding: 26px 0 24px; }
  .vn-price-group__aside { position: static; }
  .vn-price-group:not(:first-child) thead { display: table-header-group; }
}

/* The table treatment was all scoped to .vn-price-panel, so the full listing
   inherited almost none of it. Mirrored here against the values measured on
   the homepage table, so the two renderings match cell for cell. */
.vn-price-group table { table-layout: fixed; }
.vn-price-group th,
.vn-price-group td {
  text-align: left;
  padding: 15px 0;
  border-bottom: 1px solid var(--vv-line);
}
.vn-price-group thead th {
  text-transform: uppercase;
  font: 500 10px var(--vv-body);
  color: var(--vv-mute);
  padding: 0 0 15px;
}
.vn-price-group tbody th {
  font-family: var(--vv-display);
  font-size: 22px;
  font-weight: 400;
  letter-spacing: normal;
  text-transform: none;
  color: var(--vv-ink);
}
.vn-price-group tbody th a { color: inherit; font: inherit; }
.vn-price-group th:first-child  { width: 56%; }
.vn-price-group th:nth-child(2) { width: 22%; text-align: right; }
.vn-price-group th:last-child   { width: 22%; text-align: right; }
.vn-price-group td:nth-child(2) {
  text-align: right;
  font-size: 12.48px;
  text-transform: uppercase;
  letter-spacing: .155em;
  color: var(--vv-mute);
}
.vn-price-group td:last-child { text-align: right; font-size: 15px; color: var(--vv-ink); }
.vn-price-group tbody tr:last-child th,
.vn-price-group tbody tr:last-child td { border-bottom: 0; }
.vn-price-group tbody tr { transition: background var(--vv-fast) var(--vv-ease); }
.vn-price-group tbody tr:hover { background: color-mix(in srgb, var(--vv-butter) 22%, transparent); }

@media (max-width: 860px) {
  .vn-price-group th:first-child  { width: 50%; }
  .vn-price-group th:nth-child(2) { width: 24%; }
  .vn-price-group th:last-child   { width: 26%; }
  .vn-price-group tbody th { font-size: 18px; }
  .vn-price-group td:nth-child(2) { font-size: 11px; }
}

/* --- Services page refinements (0.30.0) ----------------------------------- */

/* White ground for the menu itself; "Before you choose" keeps its dark band. */
.vn-page .vn-pricing { background: var(--vv-surface); }

/* Service names off the display face. At table sizes Playfair reads as a run
   of small headlines competing with the group titles beside them; the body
   face lets the names sit as a list and keeps the prices dominant.
   Applied to BOTH renderings so the homepage and Services stay identical. */
.vn-price-group tbody th,
.vn-price-panel tbody th,
.vn-price-group tbody th a,
.vn-price-panel tbody th a {
  font-family: var(--vv-body);
  font-size: 16.5px;
  font-weight: 500;
  letter-spacing: -.005em;
}

/* The deposit and pricing notes are the two lines that prevent a surprise at
   the till — they were 14px and 11px. */
.vn-price-deposit { font-size: 15px; line-height: 1.6; }
.vn-price-note { font-size: 14px; line-height: 1.65; color: var(--vv-ink-soft); }
.vn-price-notes { margin-top: var(--vv-sp-6); gap: var(--vv-sp-4) var(--vv-sp-8); }

@media (max-width: 860px) {
  .vn-price-group tbody th,
  .vn-price-panel tbody th,
  .vn-price-group tbody th a,
  .vn-price-panel tbody th a { font-size: 15px; }
  .vn-price-deposit { font-size: 14px; }
  .vn-price-note { font-size: 13px; }
}

/* --- Contact page (0.31.0) ------------------------------------------------
   No enquiry form on this build, so the three real channels have to carry the
   page. Each is a large tap target with the actual number, address or handle
   visible — not a generic "contact us" link. */
.vn-ways { background: var(--vv-surface); }
.vn-ways__grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 0;
  list-style: none;
  margin: 0;
  padding: 0;
  border-top: 1px solid var(--vv-line);
  border-bottom: 1px solid var(--vv-line);
}
.vn-ways__grid > li {
  padding: 32px 34px 34px;
  border-left: 1px solid var(--vv-line);
}
.vn-ways__grid > li:first-child { border-left: 0; padding-left: 0; }
.vn-ways__grid > li:last-child { padding-right: 0; }
.vn-ways__grid a { display: block; text-decoration: none; }
.vn-ways__label {
  display: block;
  font-size: 11px;
  font-weight: 600;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--vv-tan-deep);
  margin-bottom: 14px;
}
.vn-ways__value {
  display: flex;
  align-items: baseline;
  gap: 10px;
  font-family: var(--vv-display);
  font-size: calc(32px * var(--vv-scale));
  line-height: 1.25;
  letter-spacing: -.02em;
  color: var(--vv-ink);
  word-break: break-word;
  transition: color var(--vv-fast) var(--vv-ease);
}
.vn-ways__arrow {
  font-family: var(--vv-body);
  font-size: .55em;
  flex: none;
  transition: transform var(--vv-normal) var(--vv-ease);
}
.vn-ways__grid a:hover .vn-ways__value,
.vn-ways__grid a:focus-visible .vn-ways__value { color: var(--vv-plum-deep); }
.vn-ways__grid a:hover .vn-ways__arrow { transform: translate(3px, -3px); }
.vn-ways__grid > li > p {
  margin: 14px 0 0;
  font-size: 14px;
  line-height: 1.65;
  color: var(--vv-mute);
  max-width: 30ch;
}

/* --- Getting here ---------------------------------------------------------
   The address is Suite 5 inside a larger building, and her own guidelines
   promise parking and suite directions with every confirmation. Those exact
   directions have not been supplied, so this says where they come from
   instead of inventing them. */
.vn-find { background: var(--vv-paper); }
.vn-find__grid {
  display: grid;
  grid-template-columns: minmax(0, 1.25fr) minmax(0, 1fr);
  gap: 72px;
  align-items: start;
}
.vn-find__body {
  font-size: 16px;
  line-height: 1.75;
  color: var(--vv-ink-soft);
  max-width: 52ch;
  margin: 0 0 26px;
}
.vn-find__address {
  font-family: var(--vv-display);
  font-style: normal;
  font-size: calc(30px * var(--vv-scale));
  line-height: 1.35;
  letter-spacing: -.02em;
  color: var(--vv-ink);
  margin: 0 0 28px;
  max-width: 20ch;
}
.vn-find__hours dl { margin: 0; border-top: 1px solid var(--vv-line); }
.vn-find__hours dl > div {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 20px;
  padding: 15px 0;
  border-bottom: 1px solid var(--vv-line);
}
.vn-find__hours dt { margin: 0; font-size: 14px; color: var(--vv-ink); }
.vn-find__hours dd {
  margin: 0;
  font-size: 14px;
  color: var(--vv-mute);
  text-align: right;
  white-space: nowrap;
}

@media (max-width: 900px) {
  .vn-find__grid { grid-template-columns: 1fr; gap: 40px; }
  .vn-ways__grid { grid-template-columns: 1fr; }
  .vn-ways__grid > li {
    border-left: 0;
    border-top: 1px solid var(--vv-line);
    padding: 24px 0 26px;
  }
  .vn-ways__grid > li:first-child { border-top: 0; padding-top: 4px; }
}

/* --- Gallery page (0.32.0) ------------------------------------------------
   Every tile crops to 9%-72% of the source height. That band is clear of the
   Instagram carousel badge (0-7%) and of the watermarks (below 72%) on all
   nine files — the aspect ratio is what sets the window, so it holds whatever
   width a tile happens to be. Do not change the ratio without re-checking the
   crops. */
.vn-grid-sec { background: var(--vv-surface); }

/* The booking panel is a form, not an editorial section: white keeps the
   service rows, calendar and input fields reading as controls rather than as
   cards floating on a tinted ground. */
.vn-booking-sec { background: #fff; padding-block: 72px 96px; }
@media (max-width: 760px) { .vn-booking-sec { padding-block: 44px 64px; } }

.vn-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 26px;
  list-style: none;
  margin: 0;
  padding: 0;
}
/* Every cell the same, aligned on both axes. The middle column used to drop
   42px; it read as uneven rather than composed. */
.vn-grid > li { display: flex; }

.vn-grid__tile {
  position: relative;
  display: block;
  width: 100%;
  margin: 0;
  padding: 0;
  overflow: hidden;
  border: 0;
  border-radius: 4px;
  background: var(--vv-paper-2);
  /* 1.62 is not a style choice — it is the clean band of the source files.
     The Instagram carousel badge sits in the top 0-7% and the Colormasterci
     watermark below 72%, so only 9%-72% of the 690px height is free of
     furniture. 710 wide over that 435px band is 1.63. Squaring these cells
     put the badge and the watermark back on screen. */
  aspect-ratio: 1.62;
  cursor: zoom-in;
  -webkit-appearance: none;
  appearance: none;
}
.vn-grid__tile:focus-visible {
  outline: 2px solid var(--vv-olive);
  outline-offset: 3px;
}
.vn-grid__tile img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  max-width: none;
  object-fit: cover;
  object-position: center 24%;
  transition: transform var(--vv-slow) var(--vv-ease);
}
.vn-grid__tile:hover img { transform: scale(1.03); }

.vn-grid__foot {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 20px 40px;
  margin-top: 52px;
  padding-top: 30px;
  border-top: 1px solid var(--vv-line);
}
.vn-grid__foot p {
  margin: 0;
  font-size: 15px;
  color: var(--vv-ink-soft);
}

@media (prefers-reduced-motion: reduce) {
  .vn-grid__tile img, .vn-grid__tile:hover img { transition: none; transform: none; }
}
@media (max-width: 900px) {
  .vn-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 18px; }
}
@media (max-width: 560px) {
  .vn-grid { grid-template-columns: 1fr; gap: 14px; }
  .vn-grid__foot { margin-top: 34px; }
}

/* -------------------------------------------------------------------------
   Gallery viewer
   A native <dialog>, so Esc, the focus trap, the inert background and focus
   restore are the browser's job. The image is drawn uncropped and capped at
   its own pixel size, so it is never upscaled into mush.
   ------------------------------------------------------------------------- */
.vn-lightbox {
  width: 100%;
  max-width: 100%;
  height: 100%;
  max-height: 100%;
  margin: 0;
  padding: 0;
  border: 0;
  background: transparent;
  overflow: hidden;
}
.vn-lightbox::backdrop {
  background: rgba(24, 25, 20, 0.92);
}
.vn-lightbox[open] { display: grid; place-items: center; }

.vn-lightbox__stage {
  position: relative;
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  align-items: center;
  gap: clamp(6px, 2vw, 24px);
  width: 100%;
  height: 100%;
  padding: clamp(12px, 3vw, 28px);
  box-sizing: border-box;
}

.vn-lightbox__figure {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 14px;
  min-width: 0;
  margin: 0;
}
.vn-lightbox__figure img {
  display: block;
  /* Never wider or taller than the file itself — "original quality" means the
     source pixels, not an upscale of them. */
  max-width: min(100%, 710px);
  max-height: calc(100vh - 150px);
  width: auto;
  height: auto;
  object-fit: contain;
  border-radius: 4px;
  background: var(--vv-paper-2);
}

.vn-lightbox__cap {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: center;
  gap: 6px 14px;
  max-width: 62ch;
  text-align: center;
  color: rgba(247, 244, 234, 0.72);
}
.vn-lightbox__count {
  font-size: 12px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: rgba(247, 244, 234, 0.5);
}
.vn-lightbox__alt { font-size: 14px; line-height: 1.5; }

.vn-lightbox__btn {
  display: grid;
  place-items: center;
  width: 46px;
  height: 46px;
  padding: 0;
  border: 1px solid rgba(247, 244, 234, 0.26);
  border-radius: 999px;
  background: rgba(24, 25, 20, 0.5);
  color: var(--vv-paper);
  cursor: pointer;
  transition: background var(--vv-fast) var(--vv-ease), border-color var(--vv-fast) var(--vv-ease);
}
.vn-lightbox__btn svg { width: 20px; height: 20px; }
.vn-lightbox__btn:hover,
.vn-lightbox__btn:focus-visible {
  background: rgba(247, 244, 234, 0.14);
  border-color: rgba(247, 244, 234, 0.55);
}
.vn-lightbox__btn:focus-visible {
  outline: 2px solid var(--vv-paper);
  outline-offset: 2px;
}
.vn-lightbox__close {
  position: absolute;
  top: clamp(12px, 3vw, 28px);
  right: clamp(12px, 3vw, 28px);
  z-index: 2;
}

/* Screen-reader announcement only. */
.vn-lightbox__live {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

@media (max-width: 700px) {
  .vn-lightbox__stage {
    grid-template-columns: minmax(0, 1fr);
    grid-template-rows: minmax(0, 1fr) auto;
    justify-items: center;
  }
  .vn-lightbox__figure img { max-height: calc(100vh - 210px); }
  .vn-lightbox__nav { grid-row: 2; }
  .vn-lightbox__nav--prev { justify-self: end; margin-right: 56px; }
  .vn-lightbox__nav--next { grid-row: 2; justify-self: start; margin-left: 56px; }
}

@media (prefers-reduced-motion: reduce) {
  .vn-lightbox__btn { transition: none; }
}

/* =========================================================================

/* =========================================================================
   SERVICE CARDS — card opens the menu, Book is its own button

   The card used to be one <a> straight to booking, so there was no way to look
   before committing. It is now a container: an overlay link covers the whole
   card and opens the matching group on the Services page, with the Book button
   sitting above that overlay on its own.
   ====================================================================== */

.vn-service { position: relative; display: flex; flex-direction: column; }
.vn-service__link {
  position: absolute;
  inset: 0;
  z-index: 1;
  border-radius: inherit;
}
.vn-service__link:focus-visible {
  outline: 2px solid var(--vv-moss-deep);
  outline-offset: -3px;
}
.vn-service__body { display: flex; flex-direction: column; flex: 1; }

/* Above the overlay, so these are their own targets rather than part of it. */
.vn-service__actions {
  position: relative;
  z-index: 2;
  display: flex;
  align-items: center;
  gap: 16px;
  flex-wrap: wrap;
  margin-top: auto;
  padding-top: 18px;
}
/* The arrow on .vn-button / .vn-link is a ::before/::after pinned to the right
   edge, and the base rule reserves 3.05rem of right padding for it. Setting a
   symmetric padding here put the label under the arrow. Same shape as the
   theme's existing .btn--sm: keep the asymmetry, move the arrow in with it. */
.vn-button--sm,
.vn-link--sm {
  padding: .68rem 2.3rem .68rem 1.2rem;
  font-size: 11px;
}
.vn-button--sm::before, .vn-button--sm::after,
.vn-link--sm::before,   .vn-link--sm::after { right: .95rem; font-size: 1em; }

@media (max-width: 620px) {
  .vn-service__actions { padding-top: 14px; }
}

   0.35.0 — LIVELINESS PASS
   ====================================================================== */

/* --- 1 · Ribbon marquee ---------------------------------------------------
   The strip's only job is rhythm and it was standing still. Two identical
   groups translated -50% loop seamlessly; duplicating the content in markup
   (rather than cloning in JS) means it moves on first paint with no layout
   shift and keeps working if the script never runs. */
.vn-ribbon { padding-inline: 0; overflow: hidden; }
.vn-marquee { display: flex; overflow: hidden; -webkit-mask-image: linear-gradient(90deg, transparent, #000 6%, #000 94%, transparent); mask-image: linear-gradient(90deg, transparent, #000 6%, #000 94%, transparent); }
.vn-marquee__track {
  display: flex; align-items: center; flex: none;
  gap: 22px;
  padding-right: 22px;
  min-width: 200%;
  animation: vn-marquee 46s linear infinite;
  will-change: transform;
}
.vn-marquee:hover .vn-marquee__track { animation-play-state: paused; }
.vn-marquee__item,
.vn-marquee__dot {
  white-space: nowrap;
  font-size: 11px;
  letter-spacing: .16em;
  word-spacing: .2em;
  text-transform: uppercase;
  color: var(--vv-on-dark);
}
.vn-marquee__dot { color: var(--vv-butter); opacity: .85; }
@keyframes vn-marquee {
  from { transform: translate3d(0, 0, 0); }
  to   { transform: translate3d(-50%, 0, 0); }
}

/* --- 3 · Hero backdrop drift ---------------------------------------------
   The photograph drifts behind type that stays put. The H1 is never animated
   or revealed — it must paint immediately for LCP. */
.vn-hero__backdrop img { will-change: transform; }
.vn-hero[data-drift] .vn-hero__backdrop img {
  transform: translate3d(0, calc(var(--vn-drift, 0) * 1px), 0) scale(calc(1 + (var(--vn-drift, 0) / 900)));
}

/* --- 4 · Service card: second set on hover -------------------------------- */
.vn-service__photo { position: relative; }
.vn-service__photo-alt {
  position: absolute; inset: 0;
  width: 100%; height: 100%; max-width: none;
  object-fit: cover;
  object-position: center 24%;
  opacity: 0;
  transition: opacity var(--vv-slow) var(--vv-ease);
  z-index: 1;
}
.vn-service:hover .vn-service__photo-alt,
.vn-service:focus-visible .vn-service__photo-alt { opacity: 1; }
/* The price pill already carries z-index:3 where it is positioned, which is
   above .vn-service__photo-alt at 1 — so it needs nothing here. An earlier
   attempt added `position: relative` and dropped the pill out of its absolute
   placement and on top of the card title. */

/* --- 2 · Pacing ------------------------------------------------------------
   Six sections were sharing identical 75px/75px padding — services, pricing,
   gallery, story, education and the FAQ. That uniform tempo is what made the
   page read as even no matter what moved inside it. Padding now reflects what
   each section is FOR: reading and looking get air, lists and punctuation
   bands get taken in. */
.vn-services  { padding-block: 96px 88px; }  /* first real section — most air */
.vn-pillars   { padding-block: 58px 62px; }  /* punctuation band — compact */
.vn-pricing   { padding-block: 68px 72px; }  /* a table you scan */
.vn-gallery   { padding-block: 94px 86px; }  /* the work — give it room */
.vn-story     { padding-block: 90px 84px; }  /* reading */
.vn-education { padding-block: 62px 66px; }  /* short, warm, compact */
.vn-faq       { padding-block: 66px 74px; }  /* was the tallest block at 14.5% */

@media (max-width: 900px) {
  .vn-services  { padding-block: 58px 54px; }
  .vn-pillars   { padding-block: 44px 46px; }
  .vn-pricing   { padding-block: 48px 52px; }
  .vn-gallery   { padding-block: 56px 52px; }
  .vn-story     { padding-block: 54px 50px; }
  .vn-education { padding-block: 46px 48px; }
  .vn-faq       { padding-block: 48px 54px; }
}

@media (prefers-reduced-motion: reduce) {
  .vn-marquee__track { animation: none; transform: none; min-width: 0; justify-content: center; }
  .vn-marquee { mask-image: none; -webkit-mask-image: none; }
  .vn-marquee__item:not(:first-of-type),
  .vn-marquee__dot { display: none; }
  .vn-hero[data-drift] .vn-hero__backdrop img { transform: none; }
  .vn-service__photo-alt { transition: none; }
}

/* --- CiCi's portrait in the story frame (0.37.0) -------------------------
   The story visual is a 1.56 landscape that bleeds off the left edge — tuned
   for the near-square Instagram grabs. Her portrait is roughly 0.8 vertical,
   so that frame would slice the top and bottom off her. `.has-portrait` gives
   the frame a portrait-friendly ratio while keeping the left-edge bleed that
   makes this the page's one asymmetric moment.

   object-position sits slightly above centre: her face is in the upper third
   and the frame should never cut her chin or forehead. */
@media (min-width: 901px) {
  .vn-story__visual.has-portrait > .vn-photo { aspect-ratio: 0.92; }
  .vn-story__visual.has-portrait > .vn-photo img { object-position: center 28%; }
  /* A tall image needs less column than a wide one, or it dominates the row. */
  .vn-story__grid:has(.has-portrait) { grid-template-columns: minmax(0, .86fr) minmax(0, 1fr); }
}

@media (max-width: 900px) {
  .vn-story__visual.has-portrait > .vn-photo { aspect-ratio: 1.05; }
  .vn-story__visual.has-portrait > .vn-photo img { object-position: center 26%; }
}


/* =========================================================================
   PER-SERVICE ADD-ONS (0.49.0)

   Add-Ons used to be a tab beside Full Sets and Manicures. The client asked for
   them to appear only once someone has chosen a service, so each service row
   now carries a disclosure and the add-ons sit under it.

   The panel rows render OPEN and JavaScript collapses them on load — with
   scripting off the prices are all still readable, rather than sealed behind a
   button that does nothing. Toggled with a data attribute, not [hidden]: a
   `<tr>` carries display rules from several places here and [hidden] loses to
   any of them.
   ====================================================================== */

.vn-addons-toggle {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  margin: 7px 0 0;
  padding: 3px 11px 3px 8px;
  border: 1px solid var(--vv-line);
  border-radius: var(--vv-r-full);
  background: transparent;
  font-family: var(--vv-body);
  font-size: 10.5px;
  font-weight: 600;
  letter-spacing: .09em;
  text-transform: uppercase;
  color: var(--vv-mute);
  cursor: pointer;
  transition: border-color var(--vv-fast) var(--vv-ease), color var(--vv-fast) var(--vv-ease), background var(--vv-fast) var(--vv-ease);
}
.vn-addons-toggle:hover { border-color: var(--vv-moss-deep); color: var(--vv-ink); }
.vn-addons-toggle:focus-visible { outline: 2px solid var(--vv-moss-deep); outline-offset: 2px; }
.vn-addons-toggle[aria-expanded="true"] {
  background: var(--vv-paper);
  border-color: var(--vv-moss-deep);
  color: var(--vv-ink);
}

/* A plus that becomes a minus, drawn rather than typed so it stays centred. */
.vn-addons-toggle__sign {
  position: relative;
  width: 9px;
  height: 9px;
  flex: none;
}
.vn-addons-toggle__sign::before,
.vn-addons-toggle__sign::after {
  content: "";
  position: absolute;
  inset: 50% 0 auto 0;
  height: 1.5px;
  background: currentColor;
  transform: translateY(-50%);
  transition: transform var(--vv-fast) var(--vv-ease), opacity var(--vv-fast) var(--vv-ease);
}
.vn-addons-toggle__sign::after { transform: translateY(-50%) rotate(90deg); }
.vn-addons-toggle[aria-expanded="true"] .vn-addons-toggle__sign::after { transform: translateY(-50%) rotate(0deg); opacity: 0; }

.vn-addons-row[data-open="false"] { display: none; }
.vn-addons-row > td { padding: 0 0 18px; border-bottom: 1px solid var(--vv-line); }

.vn-addons {
  padding: 16px 18px 15px;
  border-radius: var(--vv-r-md);
  background: var(--vv-paper);
}
.vn-addons__title {
  margin: 0 0 10px;
  font-family: var(--vv-body);
  font-size: 10.5px;
  font-weight: 700;
  letter-spacing: .13em;
  text-transform: uppercase;
  color: var(--vv-mute);
}
.vn-addons__list { list-style: none; margin: 0; padding: 0; display: grid; gap: 2px; }
.vn-addons__item {
  display: flex;
  align-items: baseline;
  gap: 12px;
  padding: 6px 0;
}
.vn-addons__item + .vn-addons__item { border-top: 1px solid var(--vv-line); }
/* The leader dots make a long price column readable without a second table. */
.vn-addons__name { font-size: 14.5px; color: var(--vv-ink); }
.vn-addons__name::after {
  content: "";
  display: inline-block;
  width: 0;
  flex: 1;
}
.vn-addons__item { justify-content: space-between; }
.vn-addons__price { font-family: var(--vv-body); font-size: 14px; font-weight: 600; color: var(--vv-moss-deep); white-space: nowrap; }
.vn-addons__note { margin: 11px 0 0; font-size: 12.5px; color: var(--vv-mute); }

@media (max-width: 620px) {
  .vn-addons { padding: 13px 14px 12px; }
  .vn-addons__name { font-size: 13.5px; }
}

@media (prefers-reduced-motion: reduce) {
  .vn-addons-toggle,
  .vn-addons-toggle__sign::before,
  .vn-addons-toggle__sign::after { transition: none; }
}

/* The price table right-aligns its cells; the add-on panel is prose and a list,
   so it sets its own alignment rather than inheriting the column's. */
.vn-addons { text-align: left; }

/* =========================================================================
   HERO SLIDESHOW

   Three photographs that cross-fade with a slow drift of their own. The Ken
   Burns transform sits on the slide wrapper, NOT the image: the scroll-drift
   already owns `transform` on `.vn-hero__backdrop img`, and two rules writing
   the same property would fight.

   Only slide one is visible without JavaScript, which is the hero exactly as
   it was before.
   ====================================================================== */

.vn-hero__slide {
  position: absolute;
  inset: 0;
  opacity: 0;
  overflow: hidden;
  transition: opacity 1.6s var(--vv-ease);
}
.vn-hero__slide.is-active { opacity: 1; }

/* Without JS nothing adds .is-active beyond the first, and only one slide is
   ever painted. */
.vn-hero__backdrop:not([data-ready]) .vn-hero__slide:not(.is-active) { opacity: 0; }

/* The slow push gives the fade somewhere to travel. 18s against a 7s cycle so
   the movement never resets visibly on the slide that is on screen. */
.vn-hero__slide img { transform-origin: center 45%; }
.vn-hero__backdrop[data-ready] .vn-hero__slide.is-active {
  animation: vn-hero-drift 18s linear forwards;
}
@keyframes vn-hero-drift {
  from { transform: scale(1); }
  to   { transform: scale(1.085); }
}

@media (prefers-reduced-motion: reduce) {
  /* No cross-fade and no travel: the first photograph, held. */
  .vn-hero__slide { transition: none; }
  .vn-hero__backdrop[data-ready] .vn-hero__slide.is-active { animation: none; }
}

/* =========================================================================
   HERO LOCATION BLOCK — local scrim

   The tagline and address sit bottom-right, which is the brightest part of the
   photograph and well past where the left-to-right shade has faded out.
   Measured against the composited background: 2.40:1 — below AA, and reported
   as "almost not readable".

   A soft radial behind just this block, in the same ink as the main shade, so
   it reads as part of the existing shading rather than a panel. Sized well
   beyond the text so there is no visible edge.
   ====================================================================== */

/* ⚠ No `position` here. This element is already `position: absolute` (bottom
   right of the hero) — declaring `relative` dropped it back into the flex flow
   and it landed in the middle of the hero, across the headline. Only z-index,
   which works on an already-positioned element. */
.vn-hero__location { z-index: 0; }
.vn-hero__location::before {
  content: "";
  position: absolute;
  inset: -58px -66px -60px -112px;
  z-index: -1;
  pointer-events: none;
  /* An ellipse inscribed in the box: radii 50%/50% centred at 50%/50%, so the
     last stop lands exactly on every edge and the corners sit outside it
     entirely. Nothing to see but a soft glow.

     `farthest-side` was wrong — it reaches 0 at the FARTHEST edge, so it is
     still partly opaque where it meets the nearer ones, and that drew as a
     faint rectangle. */
  background: radial-gradient(50% 50% at 50% 50%,
    rgba(25, 22, 24, .88) 0%,
    rgba(25, 22, 24, .80) 46%,
    rgba(25, 22, 24, .38) 74%,
    rgba(25, 22, 24, 0) 100%);
}

@media (max-width: 900px) {
  /* The block is hidden below 900px, so the scrim goes with it. */
  .vn-hero__location::before { content: none; }
}

/* =========================================================================
   "VIEW THE FULL SERVICE MENU"

   Centred under the three cards, and solid rather than outlined — it is the
   one action in the section, and an outline next to three solid card buttons
   read as the weakest thing on screen. Hover inverts to the outline, so the
   two states swap roles.
   ====================================================================== */

.vn-services__foot { justify-content: center; }

.vn-services .vn-services__foot .vn-link {
  background: var(--vv-olive);
  border-color: var(--vv-olive);
  color: var(--vv-on-dark);
  box-shadow: var(--vv-sh-sm);
}
.vn-services .vn-services__foot .vn-link:hover,
.vn-services .vn-services__foot .vn-link:focus-visible {
  background: transparent;
  border-color: var(--vv-olive);
  color: var(--vv-ink);
  box-shadow: none;
}

/* =========================================================================
   PRICING SECTION — white ground, neutral row hover
   ====================================================================== */

/* Was --vv-paper-2, a warm greige. White lets the panel read as a card against
   it without needing a border. */
.vn-pricing { background: #fff; }

/* The row hover was 22% butter, which lit each line yellow on the way past.
   A neutral tint of the ink instead — the row still answers the pointer
   without colouring it. Written as rgba so it needs no color-mix fallback. */
.vn-price-panel tbody tr:hover,
.vn-price-group tbody tr:hover {
  background: rgba(44, 38, 42, .04);
}
