/* ==========================================================================
   THE PARLOUR — homepage
   Implementation of "The Parlour Homepage.dc.html" from Claude Design
   (project 8c462d24, artboards 1a desktop / 1b mobile).

   The canvas doc is a mockup: absolute pixel values at 1440, inline styles,
   and a `style-hover` attribute that only the design runtime understands.
   This file is the production translation — tokens, real :hover rules, and
   a type scale that carries the 1440 design down to 390 using the mobile
   artboard's own values as the low end of each clamp.

   Structural ideas taken from the design, in order down the page:
     · a masthead strip above the header, address / hours / telephone
     · hero wordmark at two sizes on one baseline grid, 118 over 212
     · a page-length spine with the sisters mirrored either side of it
     · the cream band rising INTO the dark section above it
     · services as a numbered contents page, not a menu
     · Film & editorial, headline pushed left across the photograph
     · Legend of Geraldine set at 300px as a near-black watermark
   ========================================================================== */

/* --- 1. Tokens ----------------------------------------------------------- */
:root{
  --void:#100C0A;          /* deeper than ground; used behind full-bleed art */
  --ground:#1A1512;        /* espresso. never #000 — it flattens photography */
  --ground-2:#221B17;
  --chapter:#332821;       /* the sisters — lifted well off the services list
                              so the About chapter clearly starts here. 1.26
                              above the base, the step already proven visible */
  --close:#292019;         /* the whole closing block — Visit and the colophon
                              share one ground, lifted off the hat bar above.
                              Lighter than the page, because on a near-black
                              ground there is no room to separate downward */
  --cream:#F2EBE0;
  --sand:#E7DCCB;         /* second light tone, for a light section
                            that lands against the cream band */
  --cream-ink:#241C17;

  --bone:#F2EBE0;
  --bone-2:#A2968A;
  --bone-3:#6E6259;        /* editorial furniture: folios, captions, labels */

  --oxblood:#A8595A;       /* the accent. lifted well above true oxblood,
                              which disappears into espresso */
  --olive:#8C8A5F;         /* second accent, reserved for the hat bar */

  --hair:rgba(242,235,224,.14);
  --hair-soft:rgba(242,235,224,.10);
  --hair-2:rgba(242,235,224,.16);
  --hair-strong:rgba(242,235,224,.45);
  --cream-hair:rgba(36,28,23,.18);
  --cream-hair-2:rgba(36,28,23,.45);

  --display:'Bodoni Moda','Didot','Hoefler Text',Georgia,serif;
  --ui:'Inter',system-ui,-apple-system,'Segoe UI',sans-serif;
  --mono:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;

  --pad:clamp(18px,7.2vw,104px);
  --max:1440px;

  --t:340ms cubic-bezier(.22,1,.36,1);
}

*,*::before,*::after{ box-sizing:border-box }
html{ -webkit-text-size-adjust:100%; background:var(--ground) }

body{
  margin:0;
  background:var(--ground);
  color:var(--bone);
  font-family:var(--ui);
  font-weight:300;
  font-size:16px;
  line-height:1.7;
  -webkit-font-smoothing:antialiased;
  -moz-osx-font-smoothing:grayscale;
}

img{ display:block; max-width:100% }
a{ color:var(--bone); text-decoration:none }
:focus-visible{ outline:2px solid var(--oxblood); outline-offset:3px }

.skip{ position:absolute; left:-9999px }
.skip:focus{
  left:0; top:0; z-index:200; background:var(--bone); color:var(--ground);
  padding:12px 20px; font-size:11px; letter-spacing:.2em; text-transform:uppercase;
}

.shell{ max-width:var(--max); margin-inline:auto; overflow-x:clip }

/* --- 2. Type primitives -------------------------------------------------- */
h1,h2,h3{
  font-family:var(--display);
  font-weight:400;
  font-optical-sizing:none;
  font-variation-settings:'opsz' 96;
  margin:0;
  letter-spacing:-.025em;
  text-wrap:balance;
}
p{ margin:0 }

/* Uppercase micro-label. The design leans on this constantly; it is what
   sets the Bodoni off. Never below 9px, never under .2em tracking. */
.lbl{
  font:500 clamp(9px,.72vw,10px)/1 var(--ui);
  letter-spacing:.34em; text-transform:uppercase;
  color:var(--bone-2); margin:0;
}
.lbl--accent{ color:var(--oxblood) }
.lbl--olive{ color:var(--olive) }

/* Monospace is the design's "editorial furniture" voice — folios, captions,
   data rows. Distinct from the label voice above; keep them apart. */
.mono{
  font:400 clamp(9px,.74vw,10px)/1.7 var(--mono);
  letter-spacing:.16em; text-transform:uppercase; color:var(--bone-3);
}

.body{ font-weight:300; color:var(--bone-2); font-size:clamp(15px,1.15vw,17px); line-height:1.75 }
.body--lg{ font-size:clamp(15px,1.3vw,19px) }
.body--ink{ color:var(--cream-ink) }

/* --- 3. Actions ---------------------------------------------------------- */
.pill{
  display:inline-flex; align-items:center; justify-content:center;
  min-height:46px; padding:14px 28px;
  border:1px solid var(--hair-strong); border-radius:999px;
  font:500 10px/1 var(--ui); letter-spacing:.24em; text-transform:uppercase;
  color:var(--bone);
  transition:color var(--t), border-color var(--t);
}
/* .pill started life on <a> only. On a <button> the UA supplies a light
   buttonface background, which rendered a filled cream pill with cream text
   sitting invisibly on it. */
button.pill{ background:transparent; cursor:pointer; -webkit-appearance:none; appearance:none }
.pill:hover{ color:var(--oxblood); border-color:var(--oxblood) }
.pill--sm{ min-height:0; padding:11px 22px }
.pill--olive:hover{ color:var(--olive); border-color:var(--olive) }
.pill--ink{ color:var(--cream-ink); border-color:var(--cream-hair-2) }
.pill--ink:hover{ color:var(--oxblood); border-color:var(--oxblood) }
.pill--block{ display:flex; width:100%; min-height:50px }

.ulink{
  display:inline-block; align-self:flex-start;
  font:500 10px/1 var(--ui); letter-spacing:.24em; text-transform:uppercase;
  color:var(--bone-2);
  border-bottom:1px solid rgba(162,150,138,.5); padding-bottom:5px;
  transition:color var(--t), border-color var(--t);
}
.ulink:hover{ color:var(--oxblood); border-color:var(--oxblood) }
.ulink--bright{ color:var(--bone); border-color:var(--hair-strong) }

/* --- 4. Art frames -------------------------------------------------------
   Every frame is ratio-locked so the page holds its composition before the
   real photography lands. Swap the <img> in, delete nothing else. */
.art{ position:relative; overflow:hidden; background:var(--ground-2) }
.art img{ width:100%; height:100%; object-fit:cover }
.art figcaption{
  position:absolute; left:clamp(14px,1.6vw,26px); bottom:clamp(12px,1.4vw,24px);
  font:400 9px/1.6 var(--mono); letter-spacing:.14em;
  text-transform:uppercase; color:var(--bone-3); pointer-events:none;
}
.r-34{ aspect-ratio:3/4 } .r-45{ aspect-ratio:4/5 }

/* Placeholder skin. The diagonal hatch reads as "frame reserved" rather than
   as a broken image, and it grades into the ground instead of punching a hole. */
.ph{ background:repeating-linear-gradient(128deg,#2B231C 0 7px,#221B17 7px 14px) }
.ph--alt{ background:repeating-linear-gradient(232deg,#2B231C 0 7px,#221B17 7px 14px) }
.ph--cream{ background:repeating-linear-gradient(232deg,#DDD3C4 0 7px,#F2EBE0 7px 14px) }
.ph--cream figcaption{ color:#8A7F72 }

/* --- 5. Masthead + header ------------------------------------------------ */
.masthead{
  display:flex; justify-content:space-between; align-items:center; gap:16px;
  padding:0 var(--pad); min-height:34px;
  border-bottom:1px solid var(--hair-soft);
  font:400 9px/1 var(--mono); letter-spacing:.2em;
  text-transform:uppercase; color:var(--bone-3);
}
.masthead a{ color:inherit; transition:color var(--t) }
.masthead a:hover{ color:var(--bone-2) }
.masthead__hours{ text-align:center }

.head{
  display:grid; grid-template-columns:1fr auto 1fr; align-items:center; gap:20px;
  padding:0 var(--pad); min-height:76px;
  border-bottom:1px solid var(--hair);
}
.mark{
  font:500 clamp(10px,.85vw,11px)/1 var(--ui);
  letter-spacing:.42em; text-transform:uppercase; color:var(--bone);
}
.head__nav{ display:flex; gap:clamp(16px,2.4vw,34px); justify-self:center }
.head__nav a{
  font:500 10px/1 var(--ui); letter-spacing:.22em; text-transform:uppercase;
  color:var(--bone-2); transition:color var(--t);
}
.head__nav a:hover{ color:var(--oxblood) }
.head__end{ display:flex; align-items:center; gap:20px; justify-self:end }
.head__rating{ font:400 10px/1 var(--mono); letter-spacing:.14em; color:var(--bone-3); white-space:nowrap }
.head__rating b{ font-weight:400; color:var(--oxblood) }

.drawer{ display:none }

.menu-btn{
  display:none; align-items:center; min-height:44px; background:none; border:0;
  font:500 10px/1 var(--ui); letter-spacing:.2em; text-transform:uppercase;
  color:var(--bone-2); cursor:pointer;
}

/* --- 6. Hero -------------------------------------------------------------
   Two column, no gutter. The wordmark sets 118 over 212 on a .84 leading so
   the two lines lock into one mass rather than reading as two headings. */
.hero{ position:relative; display:grid; grid-template-columns:1fr 1fr; min-height:872px }
.hero__type{
  position:relative;
  padding:64px var(--pad) 76px calc(var(--pad) + 64px);
  display:flex; flex-direction:column; justify-content:space-between; gap:40px;
}
/* The drawn rule and the vertical rail are the hero's only ornament. */
.hero__rule{
  position:absolute; left:calc(var(--pad) + 38px); top:64px; bottom:76px;
  width:1px; background:var(--hair-2); transform-origin:top;
}
.rail{
  position:absolute; left:var(--pad); top:64px; bottom:76px;
  display:flex; align-items:flex-end;
}
.rail span{
  writing-mode:vertical-rl; transform:rotate(180deg);
  font:500 10px/1 var(--ui); letter-spacing:.44em;
  text-transform:uppercase; color:var(--bone-2);
}

.hero h1{ line-height:.84; letter-spacing:-.02em }
.hero h1 span{ display:block }
.hero__the{ font-size:clamp(58px,8.2vw,118px) }
.hero__name{ font-size:clamp(84px,14.7vw,212px); white-space:nowrap }
.hero__lede{ max-width:430px; margin-top:clamp(24px,3vw,44px) }
.hero__cta{ display:flex; flex-wrap:wrap; gap:16px; align-items:center; margin-top:clamp(22px,2.4vw,34px) }
/* .ulink sets align-self:flex-start for the column contexts it usually sits in,
   where it stops the underline stretching the full width. This row is
   horizontal, so flex-start means top and Services floated above the pill.
   Centring the box still leaves the label high, because the link's box carries
   5px of underline padding the pill's does not, so nudge it down by half that
   and the two labels share a baseline. */
.hero__cta .ulink{ align-self:center; margin-top:6px }
.hero__below{ display:none }
.hero__shot{ position:relative; background:var(--void) }
.hero__shot img{
  position:absolute; inset:0; width:100%; height:100%; object-fit:cover;
  transform:scale(1.14); transform-origin:50% 38%;
}

/* --- 7. The sisters — page-length spine ---------------------------------
   The structural answer to "they are twins": one rule down the centre of the
   page with a sister mirrored either side of it. The mirroring is the point,
   so it survives to the smallest breakpoint rather than collapsing to a stack. */
/* The services list runs straight into the sisters. Rather than a plain rule,
   the spine that separates the two of them starts early: a short hairline drops
   out of the section above and fades in, so the divider is the same line the
   mirrored layout is built on. */
.contents{ position:relative }
.contents::after{
  content:''; position:absolute; left:50%; bottom:0;
  width:1px; height:clamp(44px,6vw,96px);
  background:linear-gradient(to bottom, transparent, var(--hair-2));
}
/* The accent falls to 2.89:1 on the lifted ground, well under 4.5 for the
   IDENTICAL label and the numerals at their size. Scoped lift, same pattern as
   the light sections and the closing block. */
.twins .lbl--accent, .twins .numeral{ color:#C87E79 }

.twins{
  position:relative; background:var(--chapter);
  border-top:1px solid var(--hair-soft);
  padding:clamp(36px,5.6vw,104px) 0 clamp(48px,7.6vw,118px);
}
.spine{ position:absolute; left:50%; top:0; bottom:0; width:1px; background:var(--hair-2) }
/* The "Identical" eyebrow is gone at the owners' request. It was also carrying
   the space above the names, so that moves into the section's own padding. */
.twins__grid{ display:grid; grid-template-columns:1fr 1fr }
.sister{ display:flex; flex-direction:column; gap:clamp(12px,1.8vw,26px) }
.sister--l{ padding:0 clamp(9px,4vw,60px) 0 var(--pad); text-align:right; align-items:flex-end }
.sister--r{ padding:0 var(--pad) 0 clamp(9px,4vw,60px); text-align:left; align-items:flex-start }
.sister h3{
  font-variation-settings:'opsz' 96;
  font-size:clamp(30px,5.4vw,78px); line-height:.9; letter-spacing:-.015em;
}
.sister .art{ width:100% }
.sister p{ max-width:330px; font-size:clamp(12px,1vw,14px); line-height:1.75; color:var(--bone-2) }
.numeral{ font:400 clamp(10px,.8vw,11px)/1 var(--mono); letter-spacing:.2em; color:var(--oxblood) }
/* The sisters' mark was a roman "I" on each side. It read as a letter rather
   than a mark, so it becomes a plain hairline in the same accent — mirrored
   either side of the spine, and the same language as the spine and the section
   rules. Scoped to .sister: .numeral also numbers the 01-06 service rows, and
   those must stay as type. Colour is left to the .twins scope above. The
   negative margin pulls the mark in toward the names so it reads as belonging
   to them rather than floating midway down the section padding. */
.sister .numeral{
  display:block; width:clamp(20px,2.6vw,34px); height:1px;
  background:currentColor; margin-bottom:clamp(-14px,-1vw,-6px);
}

/* --- 8. Cream band -------------------------------------------------------
   Rises INTO the dark section above it: the band starts 40px early and the
   headline is pulled up another 46, so the type breaks the seam. That
   overlap is the whole gesture — without it this is just a light section. */
.cream{
  position:relative; background:var(--cream); color:var(--cream-ink);
  margin-top:clamp(-40px,-2.8vw,-18px);
  padding:0 0 clamp(44px,7vw,104px);
}
/* --seam is how far the headline reaches above the cream band's top edge.
   Both copies key off it, so the join stays exact at every width.

   --overhang exists because line-height:.92 makes the line box shorter than
   the glyphs: at 104px the box is 95px against a 158px natural box, so the
   capitals sit ~31px ABOVE the border box. clip-path clips to that box, which
   was slicing the tops off the first line — most visibly the apex of the A.
   Padding both copies by the overhang brings the ink inside the box; the
   translate and both clips shift by the same amount, so nothing moves. */
.cream{ --seam:clamp(24px,3.2vw,46px); --overhang:clamp(14px,2.2vw,32px) }
.cream__head{
  position:relative; padding:0 var(--pad);
  transform:translateY(calc(-1 * (var(--seam) + var(--overhang))));
}
.cream__head__in{ position:relative; max-width:900px }
.cream__head h2{
  font-size:clamp(46px,7.2vw,104px); line-height:.92;
  color:var(--cream-ink);
  padding-top:var(--overhang);
  clip-path:inset(calc(var(--seam) + var(--overhang)) 0 0 0);   /* on cream */
}
.cream__head .ghost{
  position:absolute; inset:0; margin:0;
  color:var(--cream);
  padding-top:var(--overhang);
  clip-path:inset(0 0 calc(100% - var(--seam) - var(--overhang)) 0);  /* on dark */
  pointer-events:none;
}
.cream__body{
  display:grid; grid-template-columns:1fr 1fr; gap:clamp(24px,5.5vw,80px);
  padding:0 var(--pad); align-items:start;
}
.cream__body > p{ max-width:520px }

/* A four-row fact table. Reads as a masthead colophon, and it is where the
   details that would otherwise clutter the prose go to live. */
.facts{ display:flex; flex-direction:column; gap:clamp(14px,1.5vw,22px); border-left:1px solid rgba(36,28,23,.22); padding-left:clamp(18px,2.4vw,34px) }
.facts div{
  display:flex; justify-content:space-between; gap:16px;
  font:500 10px/1.4 var(--ui); letter-spacing:.2em; text-transform:uppercase;
  color:var(--cream-ink); border-bottom:1px solid var(--cream-hair); padding-bottom:12px;
}
.facts div:last-child{ border-bottom:0; padding-bottom:0 }
.facts b{ font-weight:500; color:var(--oxblood) }

/* --- 9. Texture strip ---------------------------------------------------- */
.strip{ display:grid; grid-template-columns:repeat(5,1fr); background:var(--void) }
.strip .art{ aspect-ratio:4/5 }
/* Five frames generated and shot separately drift apart in warmth; a single
   shared grade is what makes them read as one run. */
.strip img{ filter:saturate(.86) contrast(1.04) }

/* --- 10. Services as a contents page ------------------------------------- */
.contents{ padding:clamp(48px,7.6vw,118px) var(--pad) clamp(44px,7vw,108px) }
.contents__top{
  display:flex; justify-content:space-between; align-items:baseline; gap:16px;
  border-bottom:1px solid var(--hair-2);
  padding-bottom:16px; margin-bottom:clamp(22px,3.4vw,52px);
}
/* Drawers rather than links out. Native <details> so they work with no JS,
   respond to the keyboard, and are announced correctly; the homepage stays
   uncluttered when they are closed and stops dead-ending on a click-out when
   they are not. The full menu still lives on /services. */
.entry{ border-bottom:1px solid var(--hair-soft) }
.entry > summary{
  display:grid; grid-template-columns:clamp(30px,4.4vw,64px) 1fr auto auto;
  align-items:baseline; gap:clamp(10px,1.6vw,24px);
  padding:14px 0; cursor:pointer; list-style:none;
  color:var(--bone); transition:color var(--t);
}
.entry > summary::-webkit-details-marker{ display:none }
.entry > summary:hover{ color:var(--oxblood) }
.entry > summary:focus-visible{ outline:2px solid var(--oxblood); outline-offset:4px }

.entry__name{
  font-family:var(--display); font-variation-settings:'opsz' 96;
  font-size:clamp(30px,5vw,70px); line-height:1.02; letter-spacing:-.02em;
}
.entry__name--it{ font-style:italic }
.entry__note{
  font:500 clamp(8px,.7vw,10px)/1.3 var(--ui); letter-spacing:.2em;
  text-transform:uppercase; color:var(--bone-3); text-align:right;
}

/* A drawn plus that loses its vertical stroke when open. Two pseudo-elements
   rather than a glyph, so it stays optically centred at every size. */
.entry__mark{
  position:relative; width:13px; height:13px; align-self:center;
  flex:none; margin-left:clamp(4px,1vw,14px);
}
.entry__mark::before,
.entry__mark::after{
  content:''; position:absolute; inset:0; margin:auto;
  background:currentColor; transition:transform var(--t), opacity var(--t);
}
.entry__mark::before{ width:100%; height:1px }
.entry__mark::after { width:1px; height:100% }
.entry[open] .entry__mark::after{ transform:scaleY(0); opacity:0 }
.entry[open] > summary{ color:var(--oxblood) }

.entry__body{
  display:flex; flex-direction:column; gap:var(--s-1, 18px);
  padding:4px 0 30px;
  padding-left:clamp(30px,4.4vw,64px);
  max-width:760px;
}
.rates{ display:flex; flex-direction:column }
.rates div{
  display:flex; justify-content:space-between; align-items:baseline; gap:20px;
  padding:11px 0; border-bottom:1px solid var(--hair-soft);
  font-size:14.5px; color:var(--bone-2);
}
.rates div:last-child{ border-bottom:0 }
.rates span:last-child{ color:var(--bone); font-variant-numeric:tabular-nums; white-space:nowrap }

/* The service drawers open with no easing, on purpose. This was written as an
   animated <details>: block-size 0 -> auto with content-visibility in the
   transition list. In Chrome 148 that silently never opened. content-visibility
   stayed hidden, so the panel measured zero however the height was declared,
   and every drawer showed a summary with nothing under it. Both documented
   replacements also fail here: 0 -> auto will not interpolate even with
   interpolate-size on :root, and grid-template-rows 0fr -> 1fr resolves the
   track to its minimum rather than max-content on ::details-content.
   A fixed max-block-size would animate, but it clips silently the moment the
   content outgrows the guess, and silent truncation has cost this project two
   review rounds already. So: no transition, correct disclosure. Revisit only
   with a real cross-browser test. */

/* --- 11. Film & editorial ------------------------------------------------
   The headline is pushed 190px left, out of its own column and across the
   photograph. The text-shadow is not decoration: it is what keeps the type
   legible where it crosses the image. */
.editorial{ background:var(--ground-2); display:grid; grid-template-columns:1fr 1fr; align-items:stretch }
.editorial .art{ min-height:600px }
/* The headline is pushed left out of its column and across this frame's right
   edge. Whatever photograph lands here later will not necessarily be dark in
   that corner — the previous one peaked at pure white, which is what washed the
   type out — so the frame carries its own bed for the type rather than relying
   on the picture. */
.editorial .art::after{
  content:''; position:absolute; inset:0; pointer-events:none;
  background:linear-gradient(to left, rgba(26,21,18,.78) 0%, rgba(26,21,18,.35) 26%, rgba(26,21,18,0) 55%);
}
.editorial__type{ justify-content:center; padding:clamp(44px,6.6vw,96px) var(--pad) clamp(44px,6.6vw,96px) clamp(20px,5.2vw,76px); display:flex; flex-direction:column; gap:clamp(18px,2.4vw,34px) }
.editorial h2{
  font-size:clamp(46px,6.4vw,92px); line-height:.9; position:relative; z-index:2;
  transform:translateX(clamp(-190px,-13vw,0px));
  text-shadow:0 0 18px rgba(26,21,18,.75), 0 0 48px rgba(26,21,18,.6);
}
.editorial p{ max-width:430px }
.rows{ display:flex; flex-direction:column; gap:12px; margin-top:6px }
.rows div{
  display:flex; justify-content:space-between; gap:16px;
  border-top:1px solid var(--hair); padding-top:12px;
}

/* --- 12. The hat bar — the risk -----------------------------------------
   "Legend of Geraldine" set at 300px in #241C17 on #1A1512: a watermark
   about one step off the ground, readable only as you pass it. Olive is
   reserved for this section and appears nowhere else on the page. */
.hatbar{ position:relative; padding:clamp(56px,8.4vw,130px) 0 clamp(52px,7.8vw,120px); overflow:hidden }
.hatbar__wm{
  position:absolute; left:0; right:0; top:clamp(18px,3.4vw,52px);
  display:flex; justify-content:center; pointer-events:none; user-select:none;
}
.hatbar__wm span{
  font-family:var(--display); font-variation-settings:'opsz' 96;
  font-style:italic; font-size:clamp(96px,20.8vw,300px);
  line-height:.8; letter-spacing:-.04em; color:#241C17; white-space:nowrap;
}
.hatbar__grid{
  position:relative; display:grid; grid-template-columns:1fr auto 1fr;
  align-items:end; gap:clamp(20px,3.9vw,56px); padding:0 var(--pad);
}
.hatbar h2{ font-size:clamp(46px,6.1vw,88px); line-height:.88 }
.hatbar__col{ display:flex; flex-direction:column; gap:clamp(12px,1.5vw,22px); padding-bottom:26px }
.hatbar .art{ width:clamp(190px,25vw,360px); border:1px solid rgba(242,235,224,.12) }
.hatbar .art figcaption{ color:var(--olive) }
.hatbar__meta{ border-left:1px solid var(--hair-2); padding-left:clamp(18px,2.4vw,34px); gap:16px }

/* --- 12b. Ash + Vine ------------------------------------------------------
   The photograph is atmosphere here, not the subject. Framed as an object it
   dominated a section whose only job is to say who makes the candles and link
   out, so it sits behind the type under a scrim instead. The scrim is opaque
   over the type and thins toward the right, which is the only way cream body
   copy stays readable over a photograph with light candles in it.

   Ground stays --close so the section still separates from the hat bar above
   on the page ground and the contact panel below on --chapter. */
.botanicals{
  position:relative; overflow:hidden;
  background:var(--ground);
  border-top:1px solid var(--hair-2);
  padding:clamp(56px,8.4vw,130px) 0 clamp(52px,7.8vw,120px);
}
.botanicals__bg{ position:absolute; inset:0; z-index:0 }
.botanicals__bg img{
  position:absolute; inset:0; width:100%; height:100%;
  object-fit:cover; object-position:74% 50%;
}
.botanicals__bg::after{
  content:''; position:absolute; inset:0;
  background:linear-gradient(90deg,
    #1A1512 0%, #1A1512 32%,
    rgba(26,21,18,.90) 48%,
    rgba(26,21,18,.66) 72%,
    rgba(26,21,18,.46) 100%);
}
.botanicals__grid{
  position:relative; z-index:1;
  display:grid; grid-template-columns:minmax(0,1fr) minmax(0,.9fr);
  gap:clamp(24px,4.4vw,72px); padding:0 var(--pad);
}
.botanicals h2{ font-size:clamp(42px,5.6vw,80px); line-height:.9 }
.botanicals__col{
  display:flex; flex-direction:column; align-items:flex-start;
  gap:clamp(12px,1.5vw,22px);
}
.botanicals__col .body{ max-width:42ch }
.botanicals__facts{
  display:flex; flex-wrap:wrap; gap:10px 26px;
  margin-top:clamp(2px,.6vw,8px);
}
/* Retuned for the page ground rather than --close. The section gave up its own
   tone because the photograph already separates it from the hat bar above, and
   the brown was colliding with the contact panel below. */
.botanicals .lbl--accent{ color:#C0736F }
.botanicals .mono{ color:#B4A99D }

/* --- 13. Bridal ---------------------------------------------------------- */
.bridal{ display:grid; grid-template-columns:1.05fr 1fr; background:var(--cream); color:var(--cream-ink) }
/* Bridal sits directly under the cream band, so it takes the second light tone
   to keep the two from reading as one field. Keyed to the adjacency, not to
   bridal generally — move either section and this resolves itself. */
.cream + .bridal{ background:var(--sand) }

/* The accent is tuned for the espresso ground and runs too light on the two
   light sections: #A8595A measures 4.18:1 on cream and 3.65:1 on sand, and the
   labels using it are 10px, which needs 4.5:1. Redefining the token rather than
   the rules means the labels, the facts figures and the link hovers all follow.
   Scoped, so the dark sections keep the accent they were designed with. */
.cream, .bridal{ --oxblood:#8C4A44 }

/* Bodoni's opsz axis drives stroke CONTRAST, and that is the whole problem
   here. Raising wght is the intuitive fix and it makes things worse: in a
   Didone the weight axis thickens the thick strokes and leaves the hairline
   where it was, so wght 600 at opsz 44 renders an A with a heavier right
   stroke and the same invisible left one.

   Measured across the axis at display size, the A's thin stroke stops reading
   as part of the letter somewhere above opsz 20. 16 holds it solidly and keeps
   real contrast. Light type on a dark ground optically thickens, so the hero
   is fine where it is; this applies to the light grounds only. */
.cream h2, .cream .ghost, .bridal h2{ font-variation-settings:'opsz' 16 }
.bridal__type{ justify-content:center; padding:clamp(44px,6.6vw,96px) clamp(20px,5.2vw,76px) clamp(44px,6.6vw,96px) var(--pad); display:flex; flex-direction:column; gap:clamp(16px,2.1vw,30px) }
.bridal h2{ font-size:clamp(46px,6.7vw,96px); line-height:.9; color:var(--cream-ink); letter-spacing:-.03em }
.bridal p{ max-width:460px }
.bridal .art{ aspect-ratio:4/5; min-height:0 }

/* --- 14. Visit / footer -------------------------------------------------- */
/* The hat bar ran straight into Visit on the same ground with nothing between
   them, so the two read as one long dark block. Same fix as the rest of the
   page: a tonal step plus a rule. 1.134 above the hat bar and 1.115 below into
   the footer, so both edges of the closing block are visible. */
.visit{
  position:relative;
  background:var(--close);
  border-top:1px solid var(--hair-2);
  padding:clamp(52px,7.6vw,110px) var(--pad) clamp(52px,6vw,88px);
}
/* Both of these were already under 4.5:1 on the old ground and the lift makes
   them worse, so they come up with it. Scoped, so the accent elsewhere is
   untouched. */
.visit .colhead, .visit .mono{ color:#948A81 }
.visit .lbl--accent{ color:#C0736F }
.visit__spine{ position:absolute; left:50%; top:0; height:clamp(52px,7.6vw,110px); width:1px; background:var(--hair-2) }
.visit__grid{ display:grid; grid-template-columns:1.2fr .8fr .8fr; gap:clamp(28px,4.4vw,64px); align-items:start }
.visit h2{ font-size:clamp(34px,4vw,58px); line-height:.94 }
.visit__col{ display:flex; flex-direction:column; gap:clamp(14px,1.8vw,26px) }
.visit__links{ display:flex; flex-direction:column; gap:8px; align-items:flex-start }
.visit__links a{
  font:400 14px/1.7 var(--ui); color:var(--bone);
  border-bottom:1px solid rgba(242,235,224,.3); transition:color var(--t), border-color var(--t);
}
.visit__links a:hover{ color:var(--oxblood); border-color:var(--oxblood) }
.colhead{
  font:500 10px/1 var(--ui); letter-spacing:.28em; text-transform:uppercase;
  color:var(--bone-3); border-bottom:1px solid var(--hair); padding-bottom:12px;
}
.hours{ display:flex; flex-direction:column; gap:14px }
.hours div{ display:flex; justify-content:space-between; gap:16px; font:400 13px/1.6 var(--ui); color:var(--bone-2) }
/* The page ends on the same espresso it has been on since the hat bar, so a
   hairline alone was not enough to say "this is the end".

   Stepping DOWN barely works: the ground is already near-black, so --void only
   separates by 1.075 and even pure black tops out at 1.16 — measured, and it
   was invisible in practice. There is far more headroom going up, so the
   closing block lifts instead. Visit and the colophon share --close, and the
   only break is the one above the hat bar. */
.colophon{
  background:var(--close);
  border-top:1px solid var(--hair-2);
  padding:clamp(26px,3vw,40px) var(--pad);
}
.colophon__in{
  max-width:var(--max); margin-inline:auto;
  display:flex; justify-content:space-between; align-items:center; gap:16px 28px;
  flex-wrap:wrap;
}
.colophon .mark{ font-size:clamp(10px,.8vw,11px); color:var(--bone-2); transition:color var(--t) }
.colophon .mark:hover{ color:var(--bone) }
/* On the shared closing ground, #948A81 clears 4.5 for 9px text and still sits
   below the wordmark in the hierarchy. */
.colophon .mono{ letter-spacing:.2em; color:#948A81 }
/* The privacy link sits among the colophon's static mono spans, so it needs a
   hover state to read as a link rather than one more label. */
.colophon__link{ transition:color var(--t) }
.colophon__link:hover{ color:var(--bone) }
/* Social sits under the hours, in the space that column was leaving empty on
   desktop, at the same weight as the contact links rather than as footer fine
   print. Its own colhead so it reads as a labelled block, not a stray pair. */
.visit__follow{ display:flex; flex-direction:column; gap:clamp(12px,1.4vw,18px); margin-top:clamp(28px,3.4vw,52px) }

/* --- 15. Entrance and reveal --------------------------------------------
   The hero plays a short staggered sequence on load. Everything below the
   fold reveals once on intersection. Both are enhancements: without JS the
   .is-in class is never added, so `no-js` below keeps content visible. */
@keyframes pRise{ from{ transform:translateY(44px); opacity:0 } to{ transform:none; opacity:1 } }
@keyframes pFade{ from{ opacity:0 } to{ opacity:1 } }
@keyframes pDraw{ from{ transform:scaleY(0) } to{ transform:scaleY(1) } }
@keyframes pWipe{ from{ clip-path:inset(0 100% 0 0) } to{ clip-path:inset(0 0 0 0) } }

.js .hero__rule{ animation:pDraw 1.1s .1s cubic-bezier(.22,1,.36,1) both }
.js .hero__eyebrow{ animation:pFade 1s .5s both }
.js .hero__the{ animation:pRise 1.2s .15s cubic-bezier(.22,1,.36,1) both }
.js .hero__name{ animation:pRise 1.3s .3s cubic-bezier(.22,1,.36,1) both }
.js .hero__lede{ animation:pFade 1.1s .8s both }
.js .hero__shot{ animation:pWipe 1.2s .2s cubic-bezier(.22,1,.36,1) both }

.js [data-reveal]{ opacity:0; transform:translateY(30px); transition:opacity .9s var(--t), transform .9s cubic-bezier(.22,1,.36,1) }
.js [data-reveal].is-in{ opacity:1; transform:none }

@media (prefers-reduced-motion:reduce){
  *,*::before,*::after{ animation:none !important; transition:none !important }
  .js [data-reveal]{ opacity:1; transform:none }
}

/* --- 16. Tablet ---------------------------------------------------------- */
/* --- 15b. Enquire --------------------------------------------------------
   Our markup, JotForm's field names. On a near-black page a hairline alone
   does not register as a break (proven twice on the closing block), so the
   form takes a tonal step up onto the sisters' ground and reads as its own
   panel. Fields are hairline-underlined rather than boxed: boxes are the one
   shape this page never uses. */
.enquire{
  background:var(--cream); color:var(--cream-ink);
  padding:clamp(48px,5.6vw,84px) var(--pad);
}
/* The section is now light, so the accent moves the other way: #A8595A is
   tuned for espresso and measures 4.18:1 on cream, under the 4.5 these 10px
   labels need. Redefining the token rather than the rules means the label, the
   required marks and the link hovers all follow, the same approach the story
   band and bridal take. */
.enquire{ --oxblood:#8C4A44 }
.enquire .lbl--accent, .enquire .req{ color:var(--oxblood) }
.enquire__in{
  display:grid; grid-template-columns:1fr 1.15fr; gap:clamp(28px,4vw,72px);
  align-items:start; max-width:1240px; margin-inline:auto;
}
.enquire__head{
  display:flex; flex-direction:column; align-items:flex-start;
  gap:clamp(12px,1.4vw,18px);
}
.enquire h2{ font-size:clamp(34px,4vw,58px); line-height:.94; color:var(--cream-ink) }
.enquire .body{ color:#5C4F45 }
.enquire .ulink{ color:#5C4F45; border-bottom-color:var(--cream-hair-2) }
.enquire .ulink:hover{ color:var(--oxblood); border-color:var(--oxblood) }
/* Copy, booking link, trigger. Everything the closed state needs, in the
   column that was empty. */
.enquire__side{
  display:flex; flex-direction:column; align-items:flex-start;
  gap:clamp(16px,1.8vw,24px);
}
.enquire__side .body{ max-width:44ch }
.enquire__side .enquire__d{ width:100%; margin-top:clamp(2px,.6vw,8px) }

/* The form is closed until asked for. A contact form sitting open under a
   heading is a lot of empty rules on a page that is otherwise all pictures and
   type, and most visitors are here to book on Vagaro instead. Native <details>,
   the same control the service drawers use, so it opens without JS. */
/* Control boundaries need 3:1, and --cream-hair-2 measures 2.34:1 on this
   ground. .5 ink over cream is 3.12:1. */
.enquire__d > summary{
  list-style:none; cursor:pointer;
  color:var(--cream-ink); border-color:rgba(36,28,23,.5);
}
.enquire__d > summary::-webkit-details-marker{ display:none }
.enquire__d > summary:focus-visible{ outline:2px solid var(--oxblood); outline-offset:4px }
.enquire__d[open] > summary{ color:var(--oxblood); border-color:var(--oxblood) }
.enquire__d:not([open]) .enquire__toggle-close{ display:none }
.enquire__d[open] .enquire__toggle-open{ display:none }

.enquire__form{ display:grid; grid-template-columns:1fr 1fr; gap:clamp(20px,2.4vw,32px);
  padding-top:clamp(26px,3vw,40px) }
.enquire__pot{ display:none }
.field{ display:flex; flex-direction:column; gap:9px; min-width:0 }
.field--wide{ grid-column:1 / -1 }
.field label{
  font:500 10px/1 var(--ui); letter-spacing:.28em; text-transform:uppercase;
  color:#6B5B50;
}
.field__note{ font:300 12.5px/1.6 var(--ui); color:#6B5B50; margin:2px 0 0 }
.field input, .field select, .field textarea{
  width:100%; background:transparent; color:var(--cream-ink);
  font:300 15px/1.6 var(--ui);
  border:0; border-bottom:1px solid rgba(36,28,23,.5); border-radius:0;
  padding:8px 0 10px;
  transition:border-color var(--t);
}
.field textarea{ resize:vertical; min-height:104px }
/* The placeholder carries the phone format, so it is content rather than
   decoration and needs AA like any other text. The dark-ground value measured
   2.76:1 here; this is 4.62:1. */
.field input::placeholder, .field textarea::placeholder{ color:#756759 }
.field input:hover, .field select:hover, .field textarea:hover{ border-bottom-color:rgba(36,28,23,.72) }
.field input:focus, .field select:focus, .field textarea:focus{
  outline:none; border-bottom-color:var(--oxblood);
}
.field input:focus-visible, .field select:focus-visible, .field textarea:focus-visible{
  outline:2px solid var(--oxblood); outline-offset:4px;
}

/* Native select, stripped to match the text inputs, with the chevron drawn
   back on as two gradients. color-scheme keeps the option popup dark so it is
   not black-on-white against the page. */
.field select{
  appearance:none; -webkit-appearance:none; color-scheme:light; cursor:pointer;
  padding-right:26px;
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='11' height='7' viewBox='0 0 11 7'%3E%3Cpath d='M1 1l4.5 4.5L10 1' fill='none' stroke='%236B5B50' stroke-width='1.2' stroke-linecap='round'/%3E%3C/svg%3E");
  background-size:11px 7px;
  background-position:right 2px center;
  background-repeat:no-repeat;
}
.field select option{ background:var(--cream); color:var(--cream-ink) }

.enquire__foot{
  grid-column:1 / -1; display:flex; flex-wrap:wrap;
  align-items:center; gap:16px 26px; margin-top:clamp(4px,1vw,12px);
}
.enquire__submit{ color:var(--cream-ink); border-color:rgba(36,28,23,.5) }
.enquire__submit[disabled]{ opacity:.45; pointer-events:none }
.enquire__status{ font:300 14px/1.6 var(--ui); color:#5C4F45; margin:0 }
.enquire__status.is-ok{ color:var(--cream-ink) }
.enquire__status.is-err{ color:var(--oxblood) }
.enquire__status a{ color:inherit; border-bottom:1px solid currentColor }
/* On success the fields go and the confirmation is all that is left. */
.enquire__form.is-sent .field,
.enquire__form.is-sent .enquire__submit{ display:none }

/* No transition here either, for the reason recorded on the service drawers. */

@media (max-width:1100px){
  .hero{ min-height:0 }
  .enquire__in{ grid-template-columns:1fr; gap:clamp(28px,4vw,44px) }
  .editorial h2{ transform:none }
  .editorial .art{ min-height:420px }
  .bridal .art{ aspect-ratio:1/1 }
}

/* --- 17. Phone ----------------------------------------------------------
   The mobile artboard keeps the spine and the mirrored sisters, so those
   stay. What changes: the hero stacks type over a full-bleed 3:4 frame, the
   nav collapses to a Menu control, and the five-up strip becomes a scroller. */
@media (max-width:820px){
  .masthead{ min-height:28px; font-size:8px; letter-spacing:.18em }
  .masthead__hours{ display:none }
  .masthead .long{ display:none }

  .head{ grid-template-columns:1fr auto; min-height:58px }
  .head__nav{ display:none }
  .head__end{ display:none }
  .menu-btn{ display:flex }
  .head.is-open + .drawer{
    display:flex; flex-direction:column; gap:4px;
    padding:14px var(--pad) 22px; border-bottom:1px solid var(--hair);
  }
  .drawer a{
    font:500 11px/1 var(--ui); letter-spacing:.22em; text-transform:uppercase;
    color:var(--bone-2); padding:14px 0; min-height:44px; display:flex; align-items:center;
  }

  /* Type block, then the photograph full bleed, then the copy and CTA. */
  .hero{ grid-template-columns:1fr }
  .hero__type{ padding:34px 18px 30px 40px; gap:0 }
  .hero__rule{ display:none }
  .rail{ left:16px; top:34px; bottom:30px }
  .rail span{ font-size:8px; letter-spacing:.4em; color:var(--bone-3) }
  .hero h1{ margin-top:22px }
  .hero__lede{ display:none }          /* moves below the photograph */
  .hero__shot{ aspect-ratio:3/4; margin-top:-8px }
  .hero__shot img{ position:static }
  .hero__below{ display:block; padding:28px 18px 40px }
  .hero__below .hero__cta{ margin-top:26px }

  /* One column: two half-width fields at phone width leave neither enough
     room for a real name. */
  .enquire__form{ grid-template-columns:1fr }

  .sister p{ display:none }            /* names and portraits carry it */
  /* Removing the Identical eyebrow left room above the names. Spend it on the
     names themselves — the one thing this block exists to show. The limit is
     "Jennifer", the longest word, against its column. Letting the h3 alone
     break out of the column padding buys it real width without moving the
     portraits, and tighter tracking buys a little more. */
  .sister h3{
    font-variation-settings:'opsz' 60;
    font-size:clamp(42px,13.2vw,56px); letter-spacing:-.032em;
  }
  .sister--l h3{ margin-left:-10px }
  .sister--r h3{ margin-right:-10px }
  .sister--l{ padding:0 7px 0 14px }
  .sister--r{ padding:0 14px 0 7px }
  .twins__grid{ gap:0 }

  /* One column, and the photograph stops being a backdrop: it becomes a band
     that LEADS the section, the same order the editorial and hat bar frames
     take at this width. Sized to its own 27:10 so the whole strip shows;
     cover-fitting it into a full-height box at 390px cropped a narrow vertical
     slice that landed on the lids and the bench rather than the candles. The
     scrim now feathers the bottom edge, down into the ground the type sits on. */
  .botanicals{ padding-top:calc(37vw + clamp(30px,7vw,44px)) }
  .botanicals__grid{ grid-template-columns:1fr }
  .botanicals__bg{ inset:0 0 auto 0; height:37vw }
  .botanicals__bg img{ object-position:50% 50% }
  .botanicals__bg::after{
    background:linear-gradient(180deg,
      rgba(26,21,18,.06) 0%, rgba(26,21,18,.48) 64%, #1A1512 100%);
  }

  .strip{
    display:flex; overflow-x:auto; scroll-snap-type:x mandatory;
    scrollbar-width:none; -webkit-overflow-scrolling:touch;
  }
  .strip::-webkit-scrollbar{ display:none }
  .strip .art{ flex:0 0 45%; scroll-snap-align:start }

  .entry > summary{
    grid-template-columns:clamp(26px,7vw,40px) 1fr auto;
    row-gap:2px; align-items:center;
  }
  .entry__note{ grid-column:2; text-align:left }
  .entry__mark{ grid-column:3; grid-row:1 / span 2 }
  .entry__body{ padding-left:clamp(26px,7vw,40px) }
  .rates div{ font-size:13.5px }

  /* Editorial overlap is a desktop gesture here. At phone width the headline
     collides with the portraits above it and reads as a mistake, so the cream
     band starts clean and the ghost copy clips away to nothing. */
  .cream{ margin-top:0; --seam:0px }
  .cream__head{ padding-top:clamp(28px,7vw,44px) }
  .cream__head h2{ clip-path:none }
  .cream__head .ghost{ display:none }

  .cream__body,
  .editorial,
  .bridal,
  .visit__grid{ grid-template-columns:1fr }
  .editorial .art{ min-height:0; aspect-ratio:4/5 }
  .bridal .art{ min-height:0; aspect-ratio:4/5 }

  /* Three columns of hat bar content will not fit; the frame leads, the
     copy follows, and the meta list closes. */
  .hatbar__grid{ grid-template-columns:1fr; align-items:start }
  .hatbar .art{ width:100%; order:-1 }
  .hatbar__meta{ border-left:0; padding-left:0; border-top:1px solid var(--hair-2); padding-top:20px }
  .hatbar__col{ padding-bottom:0 }

  .visit__spine{ display:none }
  .colophon__in{ flex-direction:column; align-items:flex-start; gap:10px }
}


















