  :root {
    --paper: #ffffff;
    --paper-2: #f6f5f2;
    --dark: #000000;
    --grey: #000000;
    --ink: #1c1c1a;
    --ink-2: #4c4c48;
    /* This was #8b8a84, which measured 3.3:1 on the paper and carried 56 of
       the page's text elements: every eyebrow, every caption, every field
       label. Grey that pale reads as a design choice on a big bright monitor
       and as broken text on a phone outdoors. Taken down until it cleared
       4.5:1 with room to spare, and no further, so it is still plainly a
       quieter tone than the body ink rather than a second black. */
    --mute: #6b6a64;
    --rule: #e3e0d9;
    --on-dark: #f4f2ed;
    --on-dark-2: #d2cfc6;
    /* The quietest tone that is still meant to be read, for the footer's
       secondary lines. Anything below this and it is decoration. */
    --on-dark-3: #a9a69c;

    --gold: #b39b5f;
    --gold-soft: #cbb887;
    /* The brand gold sits at 2.5:1 on the light paper. That is fine for a
       quote mark nobody has to read and wrong for a star rating, which
       carries the information. Same hue taken down until it measured past
       4.5:1 against the paper. */
    --gold-deep: #806626;

    --grain: .015;
    --shadow: 0 3px 10px rgb(28 28 26 / .10), 0 14px 32px rgb(28 28 26 / .13), 0 34px 70px rgb(28 28 26 / .18);
    --shadow-sm: 0 2px 6px rgb(28 28 26 / .09), 0 10px 26px rgb(28 28 26 / .13);

    --serif: "Cormorant Garamond", ui-serif, Georgia, serif;
    --sans: "Jost", ui-sans-serif, system-ui, -apple-system, sans-serif;
    --script: "Parisienne", cursive;

    --band: clamp(4.5rem, 10vw, 8.5rem);
    --max: 76rem;
    --gutter: clamp(1.25rem, 5vw, 3.5rem);
    --ease: cubic-bezier(.4, 0, .2, 1);
  }

  * { box-sizing: border-box; }
  /* Light only. A salon page is read in daylight and printed on a card, and a
     second theme is one more thing to keep correct for no gain. */
  html { scroll-behavior: smooth; -webkit-text-size-adjust: 100%; color-scheme: light; }
  body {
    margin: 0; background: var(--paper); color: var(--ink);
    /* Weight 400 and a slightly larger base. The 300 that came before read as
       faint on a white ground, which is the one place a thin sans has nothing
       to sit against. */
    font-family: var(--sans); font-size: 16px; font-weight: 500; line-height: 1.78;
    -webkit-font-smoothing: antialiased; overflow-x: hidden;
    animation: pageIn .45s var(--ease) both;
    transition: background-color .5s var(--ease), color .5s var(--ease);
  }
  @keyframes pageIn { from { opacity: 0; } to { opacity: 1; } }
  body::after {
    content: ""; position: fixed; inset: 0; z-index: 40; pointer-events: none; opacity: var(--grain);
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
  }

  /* One grade over every photograph so they read as one shoot. */
  .graded { filter: saturate(.82) contrast(1.05) brightness(1.01); }

  img { max-width: 100%; display: block; }
  a { color: inherit; }
  :focus-visible { outline: 1px solid var(--gold); outline-offset: 4px; }
  ::selection { background: var(--gold); color: #fff; }

  /* Anything an anchor can land on clears the fixed bar.

     The bar is about 8rem of window that a jumped-to heading would otherwise
     arrive underneath, which reads as the link having gone to the wrong place.
     Set once here rather than per component, because every new anchor target
     would need remembering. */
  :where(section[id], article[id], .svc-group, [id^="cat-"], [id^="pack-"]) { scroll-margin-top: 8.5rem; }

  .wrap { max-width: var(--max); margin: 0 auto; padding-inline: var(--gutter); }
  .narrow { max-width: 46rem; margin-inline: auto; }
  .sr { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }

  /* Display serif, wide tracked capitals. */
  h1, h2, h3, .disp {
    font-family: var(--serif); font-weight: 600; text-transform: uppercase;
    letter-spacing: .2em; line-height: 1.2; margin: 0; text-wrap: balance;
  }
  /* Small stacked label over a hairline, the structural device of this layout. */
  .label { text-align: center; margin-bottom: 2.75rem; }
  .label .a { font-family: var(--sans); font-size: .75rem; font-weight: 600; letter-spacing: .34em; text-transform: uppercase; color: var(--mute); display: block; }
  .label .b { font-family: var(--serif); font-size: clamp(1.6rem, 3.4vw, 2.5rem); font-weight: 700; letter-spacing: .26em; text-transform: uppercase; display: block; margin-top: .55rem; }
  .label .r { display: block; width: 4.5rem; height: 1px; background: var(--gold); margin: 1.25rem auto 0; }
  .label.left { text-align: left; }
  .label.left .r { margin-inline: 0; }

  p { margin: 0 0 1.1rem; }
  .body-copy { color: var(--ink-2); font-size: 1.0625rem; font-weight: 450; }

  /* ---------- progress ---------- */
  .progress { position: fixed; top: 0; left: 0; height: 1px; width: 100%; z-index: 80; transform-origin: 0 50%; transform: scaleX(0); background: var(--gold); will-change: transform; }

  /* ---------- buttons ---------- */
  .btn {
    display: inline-flex; align-items: center; justify-content: center; gap: .6rem;
    min-height: 44px; border-radius: 999px; border: 1px solid var(--gold); background: transparent; color: inherit;
    padding: .85rem 2.1rem; font-family: var(--sans); font-size: .6875rem; font-weight: 500;
    letter-spacing: .28em; text-transform: uppercase; text-decoration: none; cursor: pointer;
    transition: background-color .25s var(--ease), color .25s var(--ease), border-color .25s var(--ease);
  }
  .btn:hover { background: var(--gold); color: #fff; }
  .btn-solid { background: var(--dark); border-color: var(--dark); color: var(--on-dark); }
  .btn-solid:hover { background: var(--gold); border-color: var(--gold); color: #fff; }
  .btn-light { border-color: rgb(244 242 237 / .55); color: var(--on-dark); }
  .btn-light:hover { background: var(--on-dark); border-color: var(--on-dark); color: var(--dark); }
  .btn-sm { padding: .6rem 1.35rem; min-height: 40px; font-size: .5625rem; }
  .btn:disabled { opacity: .35; cursor: not-allowed; }

  /* ---------- reveal ---------- */
  .reveal { opacity: 0; transform: translateY(18px); transition: opacity .8s var(--ease), transform .8s var(--ease); transition-delay: calc(var(--d, 0) * 90ms); }
  .reveal.in { opacity: 1; transform: none; }
  @media (prefers-reduced-motion: reduce) {
    html { scroll-behavior: auto; }
    .reveal { opacity: 1; transform: none; transition: none; }
    .kb { animation: none !important; }
    body { animation: none; }
    *, *::before, *::after { animation-duration: .01ms !important; transition-duration: .01ms !important; }
  }

  /* ---------- the strip above the header ----------

     One line, one fact, and it scrolls away with the page rather than sticking
     to the top forever. A permanently pinned announcement is a permanently
     smaller screen, and after the second visit nobody reads it anyway.

     It is not a second navigation and must not become one. The moment it holds
     links it competes with the bar underneath it, which is the thing people
     are actually looking for. */
  .strip { background: var(--ink); color: var(--on-dark-2); }
  .strip .wrap { display: flex; flex-wrap: wrap; align-items: center; justify-content: center;
    gap: .35rem .85rem; min-height: 2.4rem; padding-block: .5rem; text-align: center;
    font-family: var(--sans); font-size: .625rem; font-weight: 500; letter-spacing: .2em;
    line-height: 1.5; text-transform: uppercase; }
  .strip b { color: var(--gold-soft); font-weight: 600; }
  .strip .sep { width: 3px; height: 3px; border-radius: 50%; background: currentColor; opacity: .5; flex: none; }
  /* The dots go before the line wraps, not after.

     Three facts do not fit on one line on a phone, and a separator dot that
     ends up first on the second line reads as a bullet nobody asked for. The
     spacing keeps them apart on its own once they stack. Same reason the
     banner facts have no dividers. */
  @media (max-width: 52rem) {
    .strip .sep { display: none; }
    .strip .wrap { gap: .15rem 1.4rem; font-size: .5625rem; letter-spacing: .16em; }
  }

  /* ---------- header ---------- */
  /* The header is its own band above the banner rather than an overlay on it.
     Logo and navigation read against paper, not against whatever the
     photograph happens to be doing behind them. */
  /* ---------- the bar sits on the banner, not above it ----------

     The strip and the header are fixed to the top of the window and the
     photograph starts underneath them, so the first thing on screen is the
     picture with the navigation laid over it rather than a white slab and then
     the picture.

     Fixed rather than sticky: sticky needs the element to be in the flow,
     which is exactly what pushes the banner down. */
  .topbar { position: fixed; inset: 0 0 auto; z-index: 60; }

  /* The scrim that makes it work.

     Light navigation over a photograph is only readable where the photograph
     happens to be dark, and this one is bright on the right hand side, which is
     where the phone number and the Book button are. A gradient under the bar
     guarantees the ground instead of hoping for it, and it fades out by the
     bottom so the picture is not simply capped with a black band. */
  /* Extended below the bar, and strong the whole way through it.

     The first version faded to a quarter by 88% of the bar's own height, which
     put the weakest part of the scrim exactly across the bottom of the
     navigation links. The glyphs sat higher and were fine, so it looked
     correct; sampling the pixels behind the full link box found the salon
     floor coming through at rgb(138,134,126) and a ratio of 2.3. Relying on
     where the letters happen to fall inside their padding is not a design, it
     is a coincidence.

     It now covers the bar solidly and does its fading in 2.5rem of overhang
     underneath, where there is no text. */
  .topbar::after { content: ""; position: absolute; inset: 0 0 -2.5rem; z-index: -1; pointer-events: none;
    background: linear-gradient(180deg,
      rgb(12 12 10 / .94) 0%,
      rgb(12 12 10 / .88) 50%,
      rgb(12 12 10 / .78) 74%,
      rgb(12 12 10 / .32) 90%,
      transparent 100%);
    opacity: 1; transition: opacity .4s var(--ease); }
  .topbar.scrolled::after { opacity: 0; }

  header.site { position: relative; z-index: 1; background: transparent; border-bottom: 1px solid transparent;
    transition: box-shadow .4s var(--ease), background-color .4s var(--ease), border-color .4s var(--ease);
    animation: head-in .7s var(--ease) both; }

  /* Over the photograph the bar is light on dark. Once the page has moved it
     becomes the solid paper bar it always was, and everything in it goes back
     to reading against white. */
  header.site:not(.stuck) .brand,
  header.site:not(.stuck) .brand .n { color: var(--on-dark); }
  header.site:not(.stuck) .logo { border-color: rgb(255 255 255 / .45); color: var(--on-dark); }
  header.site:not(.stuck) nav.main > a,
  header.site:not(.stuck) nav.main .nav-item > a { color: var(--on-dark-2); }
  header.site:not(.stuck) nav.main > a:hover,
  header.site:not(.stuck) nav.main .nav-item > a:hover,
  header.site:not(.stuck) nav.main a.here,
  header.site:not(.stuck) nav.main a[aria-current="page"] { color: var(--gold-soft); }
  header.site:not(.stuck) nav.main a::after { background: var(--gold-soft); }
  header.site:not(.stuck) .head-live { color: var(--on-dark-2); border-right-color: rgb(255 255 255 / .22); }
  header.site:not(.stuck) .head-live .dot.open { background: var(--gold-soft); box-shadow: 0 0 0 3px rgb(203 184 135 / .25); }
  header.site:not(.stuck) .head-actions .btn { border-color: rgb(244 242 237 / .6); color: var(--on-dark); }
  header.site:not(.stuck) .head-actions .btn:hover { background: var(--on-dark); border-color: var(--on-dark); color: var(--dark); }
  /* Condensed once the page has moved. The bar loses height and gains a lift,
     so the header stops being a slab and starts being a layer above the page. */
  header.site.stuck { box-shadow: 0 1px 24px rgb(20 20 18 / .10); border-bottom-color: var(--rule);
    background: color-mix(in srgb, var(--paper) 88%, transparent);
    backdrop-filter: blur(14px); -webkit-backdrop-filter: blur(14px); }
  header.site .bar { display: flex; align-items: center; justify-content: space-between; gap: 1rem; height: 5.25rem;
    transition: height .4s var(--ease); }
  header.site.stuck .bar { height: 4.25rem; }
  header.site.stuck .logo { transform: scale(.88); }
  header.site.stuck .brand .s { opacity: 0; transform: translateY(-3px); }

  @keyframes head-in { from { opacity: 0; transform: translateY(-100%); } to { opacity: 1; transform: none; } }
  /* The brand and each nav item arrive just behind the bar itself, which reads
     as the header assembling rather than as one block dropping in. */
  @keyframes head-item { from { opacity: 0; transform: translateY(-7px); } to { opacity: 1; transform: none; } }
  header.site .brand,
  header.site nav.main a,
  header.site .head-actions { animation: head-item .55s var(--ease) both; animation-delay: calc(.18s + var(--hd, 0) * .045s); }
  .brand { display: flex; align-items: center; gap: .85rem; text-decoration: none; line-height: 1; color: var(--ink); }
  .brand .txt { display: flex; flex-direction: column; align-items: flex-start; }
  /* A ruled monogram, drawn from the salon initials so it works for any name. */
  .logo { width: 52px; height: 52px; flex: none; display: grid; place-items: center; border: 1px solid currentColor; border-radius: 50%; font-family: var(--serif); font-size: 1.05rem; font-weight: 700; letter-spacing: .04em; transition: background-color .3s var(--ease), color .3s var(--ease), border-color .3s var(--ease); }
  .brand:hover .logo { background: var(--gold); border-color: var(--gold); color: #fff; }
  
  /* Never wraps. The navigation grew when it moved to the serif and pushed the
     wordmark onto two lines, which turns the one fixed thing in the header into
     something that changes height with the width of the window. */
  .brand .n { font-family: var(--serif); font-size: 1.05rem; font-weight: 700; letter-spacing: .3em;
    text-transform: uppercase; white-space: nowrap; }
  .brand .s { font-family: var(--sans); font-size: .5rem; letter-spacing: .44em; text-transform: uppercase; margin-top: .35rem; opacity: .75;
    transition: opacity .35s var(--ease), transform .35s var(--ease); }
  .logo { transition: background-color .3s var(--ease), color .3s var(--ease), border-color .3s var(--ease), transform .4s var(--ease); }

  nav.main { display: flex; gap: 0; }

  /* On a phone the bar becomes two rows and the links scroll sideways.

     They used to be `display: none` below 68rem, which was defensible while
     every link was an anchor on the page you were already on. It is not
     defensible now that Prices and Offers are separate pages: on a phone there
     was no route to either from the header at all, only from the footer at the
     very bottom.

     A scrolling strip rather than a hamburger, deliberately. A drawer needs a
     button, a panel, a focus trap, Escape handling and a scroll lock, and all
     of it exists to hide seven short words. This shows the seven words. */
  /* 75rem, not 68rem. The links are set in the serif at 15px now, so the full
     row needs about 1200px before it clears the Book button; at 1088px it was
     pushing the page 82px wider than the window. Below this the same links
     scroll instead, so nothing is lost, only laid out differently. */
  @media (max-width: 74.99rem) {
    header.site .bar { flex-wrap: wrap; height: auto; row-gap: .25rem; padding-block: .85rem; }
    header.site.stuck .bar { height: auto; }
    /* The wordmark is tracked out to .3em at full size, which is 280px of a
       390px screen and pushed the Book button onto a row of its own, so the
       header came to three rows. Pulled in just enough that the brand and the
       one action share the top row and the links get the second. */
    .brand { min-width: 0; }
    .brand .n { font-size: .875rem; letter-spacing: .2em; }
    .brand .logo { width: 2.2rem; height: 2.2rem; }
    nav.main { order: 3; width: 100%; margin: 0 calc(var(--gutter) * -1); padding: 0 var(--gutter);
      overflow-x: auto; scrollbar-width: none; -webkit-overflow-scrolling: touch; }
    nav.main::-webkit-scrollbar { display: none; }
    nav.main a { padding: .5rem .65rem; min-height: 0; white-space: nowrap; font-size: .8125rem; letter-spacing: .1em; }
    nav.main a::after { bottom: .35rem; left: .7rem; right: .7rem; }
    /* The strip is scrollable and nothing about a flush edge says so. A fade
       on the right is the cheapest honest hint that there is more. */
    /* The fade follows the bar, which is now two different colours.

       It was a hard fade to white, written when the header was always a paper
       band. Over the photograph that painted a white block on the right of the
       scrolling links. It fades to the scrim while the bar is transparent and
       to paper once the bar is solid. */
    header.site .bar::after { content: ""; position: absolute; right: 0; bottom: .85rem; width: 2.5rem; height: 2rem;
      pointer-events: none; transition: background .4s var(--ease);
      background: linear-gradient(90deg, transparent, rgb(12 12 10 / .92)); }
    header.site.stuck .bar::after { background: linear-gradient(90deg, transparent, var(--paper)); }
    header.site .bar { position: relative; }
  }
  /* The serif, not the sans, and a size up.

     These were 11px Jost at 600 with .22em tracking, which reads as a caption
     rather than as the navigation of the page. The display serif is already
     the voice of this site — it sets the wordmark, every section heading and
     every price — so the links belong in it too. Larger, and the tracking
     comes in, because wide tracking is what makes small caps legible and
     works against them once the type has size of its own. */
  nav.main a { position: relative; padding: 1rem .68rem; min-height: 44px; display: flex; align-items: center;
    font-family: var(--serif); font-size: .9375rem; font-weight: 700; letter-spacing: .13em;
    text-transform: uppercase; color: var(--ink-2); text-decoration: none;
    transition: color .25s var(--ease); }
  nav.main a::after { content: ""; position: absolute; left: .8rem; right: .8rem; bottom: .9rem; height: 1px; background: var(--gold-deep); transform: scaleX(0); transform-origin: left; transition: transform .25s var(--ease); }
  nav.main a:hover { color: var(--gold-deep); }
  nav.main a:hover::after { transform: scaleX(1); }
  /* Set by the scroll spy. The rule stays drawn for the section you are in,
     so the navigation reports where you are rather than only what you touched. */
  nav.main a.here { color: var(--gold-deep); }
  nav.main a.here::after { transform: scaleX(1); }
  /* The spy only lights anchors on the current document. A link to another
     page needs marking too, and `aria-current` is the attribute that already
     says so to a screen reader, so the styling hangs off the same fact rather
     than off a second class that could disagree with it. */
  nav.main a[aria-current="page"] { color: var(--gold-deep); }
  nav.main a[aria-current="page"]::after { transform: scaleX(1); }

  .head-actions { display: flex; align-items: center; gap: .5rem; }

  /* ---------- the drop down panels ----------

     Opens on hover and on focus-within. The second half is not optional: a
     menu that only answers the mouse is a menu a keyboard cannot reach, and
     `:focus-within` means tabbing into the trigger opens it and tabbing out of
     the last link closes it, with no script and nothing to keep in sync.

     The trigger stays a real link to a real page. A top level item that only
     opens a panel is a dead end for anyone who taps it on a phone, where there
     is no hover at all — there the panel never opens and the link simply goes
     where it says.

     `visibility` as well as opacity, so a closed panel cannot be tabbed into
     or take a click through the page underneath it. */
  .nav-item { position: relative; display: flex; align-items: center; }
  .nav-item > a .caret { display: inline-block; width: .5rem; height: .5rem; margin-left: .45rem;
    border-right: 1.5px solid currentColor; border-bottom: 1.5px solid currentColor;
    transform: rotate(45deg) translateY(-1px); opacity: .6;
    transition: transform .3s var(--ease), opacity .3s var(--ease); }
  .nav-item:hover > a .caret,
  .nav-item:focus-within > a .caret { transform: rotate(-135deg) translateY(-1px); opacity: 1; }

  .mega { position: absolute; top: 100%; left: 50%; z-index: 70; translate: -50% 0;
    min-width: min(46rem, calc(100vw - 3rem)); padding: 2rem 2.25rem 1.75rem;
    background: var(--paper); border: 1px solid var(--rule); border-radius: 18px;
    box-shadow: 0 18px 50px rgb(20 20 18 / .13), 0 3px 10px rgb(20 20 18 / .07);
    opacity: 0; visibility: hidden; transform: translateY(-8px);
    transition: opacity .28s var(--ease), transform .28s var(--ease), visibility 0s linear .28s; }
  .nav-item:hover > .mega,
  .nav-item:focus-within > .mega { opacity: 1; visibility: visible; transform: none; transition-delay: 0s; }
  /* Bridges the gap between the link and the panel so the pointer can travel
     down without passing over dead space and closing it. */
  .nav-item > .mega::before { content: ""; position: absolute; left: 0; right: 0; top: -14px; height: 14px; }

  .mega-grid { display: grid; gap: 1.75rem 2.5rem; grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .mega-grid.three { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .mega-h { display: flex; align-items: center; gap: .7rem; margin-bottom: 1.1rem;
    font-family: var(--sans); font-size: .5625rem; font-weight: 600; letter-spacing: .28em;
    text-transform: uppercase; color: var(--gold-deep); }
  .mega-h::before { content: ""; width: 1.6rem; height: 1px; background: currentColor; flex: none; }

  .mega-list { display: flex; flex-direction: column; gap: .15rem; }
  /* Scoped under `nav.main`, and it has to be.

     `nav.main a` is a type, a class and a type: specificity 0,1,2. A plain
     `.mega-list a` is 0,1,1 and loses to it, so the panel links kept the bar's
     `display: flex`, its 44px min height and its uppercase serif. The visible
     symptom was the title and its description sitting side by side on one line
     instead of stacking, which looks like a broken grid rather than a losing
     selector. Matching the nav's own weight is the fix. */
  nav.main .mega-list a { display: block; min-height: 0; padding: .6rem .7rem; margin-inline: -.7rem;
    border-radius: 10px; text-decoration: none; font-family: var(--sans); font-size: .875rem;
    font-weight: 500; letter-spacing: 0; text-transform: none; color: var(--ink);
    transition: background-color .2s var(--ease), transform .2s var(--ease); }
  nav.main .mega-list a::after { content: none; }
  nav.main .mega-list a:hover,
  nav.main .mega-list a:focus-visible { background: var(--paper-2); transform: translateX(3px); }
  /* The panel's own button, likewise, or it inherits the bar's serif caps. */
  nav.main .mega-foot .btn { font-family: var(--sans); font-size: .5625rem; font-weight: 500;
    letter-spacing: .28em; color: var(--ink); }
  nav.main .mega-foot .btn:hover { background: var(--gold); border-color: var(--gold); color: #fff; }
  .mega-list .t { display: block; font-family: var(--sans); font-size: .875rem; font-weight: 600;
    letter-spacing: .01em; text-transform: none; color: var(--ink); line-height: 1.4; }
  .mega-list .d { display: block; margin-top: .15rem; font-family: var(--sans); font-size: .75rem;
    font-weight: 400; letter-spacing: 0; text-transform: none; color: var(--ink-2); line-height: 1.5; }
  .mega-list a:hover .t { color: var(--gold-deep); }

  /* The one strong action in the panel, along the bottom. */
  .mega-foot { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between;
    gap: .75rem 1.5rem; margin-top: 1.75rem; padding-top: 1.25rem; border-top: 1px solid var(--rule); }
  .mega-foot p { margin: 0; font-family: var(--sans); font-size: .75rem; font-weight: 400;
    letter-spacing: 0; text-transform: none; color: var(--ink-2); }

  /* No panels below the desktop breakpoint. There is no hover on a phone, the
     bar is already a scrolling strip, and every destination in every panel is
     reachable from the page the trigger goes to. */
  @media (max-width: 74.99rem) {
    .mega { display: none; }
    .nav-item > a .caret { display: none; }
  }
  @media (prefers-reduced-motion: reduce) {
    .mega { transition: opacity .01s linear, visibility 0s; transform: none; }
    .mega-list a { transition: none; }
    .mega-list a:hover { transform: none; }
  }

  /* The one piece of changing text in the bar: whether the salon is open right
     now. It is the question a visitor arrives with, it is already computed for
     the booking calendar, and it takes one line. Hidden on narrow screens
     where the bar has no room to spare. */
  .head-live { display: none; align-items: center; gap: .5rem; padding-right: .9rem; margin-right: .3rem;
    border-right: 1px solid var(--rule); font-family: var(--sans); font-size: .5625rem; font-weight: 600;
    letter-spacing: .2em; text-transform: uppercase; color: var(--ink-2); white-space: nowrap; }
  @media (min-width: 60rem) { .head-live { display: inline-flex; } }
  .head-live .dot { width: .3rem; height: .3rem; border-radius: 50%; background: var(--mute); }
  .head-live .dot.open { background: var(--gold-deep); box-shadow: 0 0 0 3px rgb(128 102 38 / .18); }

  /* ---------- hero ----------

     Full bleed, square corners. The banner is the page edge, not a card on it.

     The composition is left aligned rather than centred, and the reason is not
     taste. A centred block over a photograph has to sit where the photograph is
     busiest, so it needs a heavy scrim across the whole frame to stay readable
     and the room behind it disappears. Anchoring the type to the left lets the
     darkening be a one sided wedge: the words get their ground, and two thirds
     of the photograph stays open. Every editorial site that puts type over a
     picture does this, for that reason.

     Nothing here is a control. The buttons and the opening hours have moved to
     the bar above, which is where someone looks for them, and it leaves the
     banner to do the one job a banner is good at. */
  .hero { position: relative; min-height: 82svh; display: grid; align-items: end; overflow: hidden; }
  .hero-media { position: absolute; inset: 0; }
  .hero-media img { width: 100%; height: 100%; object-fit: cover; object-position: 50% 45%; }
  .kb { will-change: transform; animation: ken 24s linear infinite alternate; }
  @keyframes ken { from { transform: scale(1); } to { transform: scale(1.06); } }
  /* A wedge from the left plus a floor at the bottom, instead of a blanket.
     Strongest exactly where the words are and gone by two thirds across. */
  .hero-media::after { content: ""; position: absolute; inset: 0;
    background:
      linear-gradient(90deg, rgb(14 14 12 / .82) 0%, rgb(14 14 12 / .58) 32%, rgb(14 14 12 / .12) 62%, transparent 82%),
      linear-gradient(180deg, rgb(14 14 12 / .34) 0%, transparent 34%, rgb(14 14 12 / .30) 100%); }

  .hero-inner { position: relative; z-index: 2; color: var(--on-dark); width: 100%;
    padding: 0 var(--gutter) clamp(3.5rem, 9vh, 7rem); }
  .hero-copy { max-width: 30ch; }

  .hero-eyebrow { display: flex; align-items: center; gap: .85rem; font-family: var(--sans); font-size: .5625rem;
    font-weight: 600; letter-spacing: .34em; text-transform: uppercase; color: var(--gold-soft); }
  /* Drawn, not typed. A rule made of hyphens breaks differently in every font. */
  .hero-eyebrow::before { content: ""; width: 2.5rem; height: 1px; background: currentColor; opacity: .8; flex: none; }

  /* Sized so the whole block fits above the fold with room under it.

     The first version topped out at 5.4rem and it looked impressive on its
     own and wrong in place: the headline filled the frame, the supporting
     line and the three facts were shoved onto the bottom edge, and the last
     fact was cut off at 900px tall. A banner headline is not competing with
     anything, so it does not need to be the largest type the viewport can
     hold. `text-wrap: balance` keeps the ragged edge even. */
  .hero-title { margin-top: 1.4rem; font-family: var(--serif); font-weight: 500;
    font-size: clamp(2.3rem, 5.1vw, 4.1rem); line-height: 1.02; letter-spacing: -.015em; text-wrap: balance; }
  .hero-title em { font-style: italic; color: var(--gold-soft); }

  .hero-sub { margin-top: 1.6rem; max-width: 42ch; font-family: var(--sans); font-size: .9375rem;
    font-weight: 400; line-height: 1.75; color: var(--on-dark-2); }

  /* Three facts rather than three buttons. A banner is where someone decides
     whether this is their kind of salon, and an address answers that faster
     than another thing to press. */
  /* No dividers between the facts, on purpose.

     They had a hairline before each item after the first, which looks right on
     one line and wrong the moment it wraps: the rule ends up hanging at the
     start of the next line with nothing to its left. Spacing separates them
     just as clearly and cannot break. */
  .hero-facts { display: flex; flex-wrap: wrap; gap: .75rem 2.6rem; margin-top: 2rem;
    font-family: var(--sans); font-size: .5625rem; font-weight: 600; letter-spacing: .24em;
    text-transform: uppercase; color: var(--on-dark-2); }

  @media (min-width: 62rem) {
    .hero-inner { padding-inline: clamp(var(--gutter), 7vw, 7rem); }
    .hero-copy { max-width: 34ch; }
  }

  /* A quiet cue that there is more below. Fades out as soon as the page moves,
     because an arrow still bouncing after you have scrolled is nagging. */
  .hero-scroll { position: absolute; left: 50%; bottom: 1.6rem; z-index: 2; translate: -50% 0;
    display: grid; place-items: center; gap: .55rem; font-family: var(--sans); font-size: .5rem;
    font-weight: 600; letter-spacing: .3em; text-transform: uppercase; color: var(--on-dark-2);
    opacity: .75; transition: opacity .4s var(--ease); pointer-events: none; }
  .hero-scroll i { display: block; width: 1px; height: 2.6rem; background: currentColor;
    transform-origin: 50% 0; animation: hero-drop 2.6s var(--ease) infinite; }
  @keyframes hero-drop { 0%, 100% { transform: scaleY(.3); opacity: .35; } 45% { transform: scaleY(1); opacity: 1; } }
  header.site.stuck ~ main .hero-scroll { opacity: 0; }

  .status { display: inline-flex; align-items: center; gap: .5rem; margin-top: 1.75rem; font-family: var(--sans); font-size: .5625rem; letter-spacing: .24em; text-transform: uppercase; color: var(--on-dark-2); }
  .dot { width: .35rem; height: .35rem; border-radius: 50%; background: var(--on-dark-2); }
  .dot.open { background: var(--gold-soft); box-shadow: 0 0 0 3px rgb(203 184 135 / .25); }

  /* ---------- page banner, for everything that is not the home page ----------

     Shorter than the home banner on purpose. Someone on the prices page has
     already decided to look at prices, and a full height photograph between
     them and the list is a toll gate. */
  .page-hero { position: relative; min-height: 42svh; display: grid; align-items: end; overflow: hidden; }
  .page-hero .hero-media img { object-position: 50% 42%; }
  .page-hero .hero-media::after { content: ""; position: absolute; inset: 0;
    background:
      linear-gradient(90deg, rgb(14 14 12 / .84) 0%, rgb(14 14 12 / .62) 34%, rgb(14 14 12 / .18) 66%, rgb(14 14 12 / .06) 86%),
      linear-gradient(180deg, rgb(14 14 12 / .36), transparent 40%, rgb(14 14 12 / .34)); }
  .page-hero .hero-inner { padding-bottom: clamp(2.5rem, 6vh, 4rem); }
  .page-hero .hero-title { font-size: clamp(2.1rem, 5.4vw, 3.8rem); margin-top: 1.2rem; }
  .page-hero .hero-sub { margin-top: 1.1rem; font-size: .875rem; }

  /* Where you are, above the title. Two levels only, so it stays a location
     rather than becoming a second navigation. */
  .crumb { display: flex; align-items: center; gap: .6rem; margin-bottom: 1.4rem;
    font-family: var(--sans); font-size: .5625rem; font-weight: 600; letter-spacing: .26em;
    text-transform: uppercase; color: var(--on-dark-2); }
  .crumb a { color: inherit; text-decoration: none; border-bottom: 1px solid transparent; padding-bottom: .15rem;
    transition: color .25s var(--ease), border-color .25s var(--ease); }
  .crumb a:hover { color: var(--gold-soft); border-bottom-color: currentColor; }
  .crumb span[aria-current] { color: var(--gold-soft); }

  /* ---------- intro with script watermark ---------- */
  .intro { position: relative; padding: var(--band) 0; text-align: center; overflow: hidden; }
  .intro .mark { position: absolute; inset: 0; display: grid; place-items: center; pointer-events: none; }
  .intro .mark span { font-family: var(--script); font-size: clamp(5rem, 20vw, 15rem); color: var(--gold); opacity: .1; white-space: nowrap; line-height: 1; }
  .intro .inner { position: relative; z-index: 2; }
  .intro .the { font-family: var(--sans); font-size: .6875rem; font-weight: 500; letter-spacing: .4em; text-transform: uppercase; color: var(--mute); }
  /* Matches on the tag it actually carries. This read `.intro h1` and the
     wordmark became an h2 when the banner took the h1, which would have
     dropped it to the browser default size with nothing visibly wrong in
     either file. */
  .intro #intro-name { font-size: clamp(1.9rem, 5.4vw, 3.4rem); margin: 1.25rem 0 .75rem; }
  .intro .sub { font-family: var(--sans); font-size: .6875rem; font-weight: 500; letter-spacing: .5em; text-transform: uppercase; color: var(--mute); }
  .intro p { margin-top: 2.25rem; }

  /* ---------- dark band, offerings ---------- */
  .band-dark { background: var(--dark); color: var(--on-dark); padding: var(--band) 0; }
  .band-dark .label .a, .band-dark .label .b { color: var(--on-dark); }
  .band-dark .label .a { color: var(--on-dark-2); }

  /* A light band, as a class.

     The light sections used to be `.band-dark` carrying an inline
     `background:var(--paper);color:var(--ink)`. The inline style won on the
     section and had no effect on its children, so `.band-dark .label .a`
     carried on painting the section headings near-white and eight of them sat
     invisible on white. Neither rule looks wrong on its own, which is why it
     survived. Both bands are classes now and the pair cannot come apart. */
  .band-light { background: var(--paper); color: var(--ink); padding: var(--band) 0; }
  .band-light.alt { background: var(--paper-2); }
  .band-light .label .a { color: var(--mute); }
  .band-light .label .b { color: var(--ink); }

  /* `.body-copy` sets its own ink, so on a black band it overrode the band's
     light colour and printed near-black on black. The bands have to win for
     their own paragraphs. */
  .band-dark .body-copy, .band-grey .body-copy { color: var(--on-dark-2); }

  .offerings { display: grid; gap: clamp(2.5rem, 6vw, 4rem); grid-template-columns: repeat(auto-fit, minmax(14rem, 1fr)); text-align: center; }
  .offer .ic { color: var(--gold-soft); margin: 0 auto 1.5rem; display: block; }
  .offer h3 { font-family: var(--sans); font-size: 1.05rem; font-weight: 600; letter-spacing: .3em; color: var(--on-dark); }
  .offer p { color: var(--on-dark-2); font-size: 1rem; font-weight: 400; margin: 1.1rem auto 1.9rem; max-width: 28ch; }

  /* ---------- what every appointment includes ----------

     Sits in the same dark band, under the three offerings. The offerings say
     what you can have; these say what you get whichever you pick, which is the
     part that decides between this salon and a cheaper one down the road.

     Numbered, because it is a sequence rather than a list of features: what
     happens to you in order, from the consultation to walking out. A numbered
     marker on an unordered set is decoration; here it carries something.

     Rounded, and lit from the top left corner rather than given a flat border,
     so a row of four does not read as four grey boxes. */
  .assures { display: grid; gap: clamp(.9rem, 2vw, 1.25rem); grid-template-columns: 1fr;
    margin-top: clamp(3.5rem, 8vw, 5.5rem); }
  @media (min-width: 44rem) { .assures { grid-template-columns: repeat(2, 1fr); } }
  @media (min-width: 72rem) { .assures { grid-template-columns: repeat(4, 1fr); } }

  .assure { position: relative; overflow: hidden; border-radius: 18px; padding: 1.9rem 1.6rem 1.75rem;
    background: rgb(255 255 255 / .035); border: 1px solid rgb(255 255 255 / .09);
    transition: transform .45s var(--ease), background-color .45s var(--ease), border-color .45s var(--ease); }
  /* The lit corner. A masked gradient ring rather than a border colour, so it
     follows the radius instead of squaring it off. */
  .assure::after { content: ""; position: absolute; inset: 0; border-radius: inherit; padding: 1px;
    pointer-events: none; opacity: 0; transition: opacity .45s var(--ease);
    background: linear-gradient(140deg, var(--gold-soft), rgb(203 184 135 / .15) 38%, transparent 65%);
    -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
    -webkit-mask-composite: xor; mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
    mask-composite: exclude; }
  .assure:hover { transform: translateY(-4px); background: rgb(255 255 255 / .06); border-color: transparent; }
  .assure:hover::after { opacity: 1; }

  .assure-n { display: block; font-family: var(--serif); font-size: 1.9rem; font-weight: 700;
    line-height: 1; letter-spacing: .04em; color: var(--gold-soft); opacity: .55; margin-bottom: 1.1rem; }
  .assure h3 { font-family: var(--sans); font-size: .9375rem; font-weight: 600; letter-spacing: .1em;
    text-transform: none; line-height: 1.35; color: var(--on-dark); }
  .assure p { margin: .8rem 0 0; font-size: .875rem; font-weight: 400; line-height: 1.75; color: var(--on-dark-2); }

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

  /* ---------- diagonal split, work ---------- */
  .work { position: relative; padding: var(--band) 0; overflow: hidden; }
  /* The angled ground behind the photograph, the signature of this layout. */
  .work::before { content: ""; position: absolute; inset: 0 0 38% 0; background: var(--paper-2); transform: skewY(-3deg); transform-origin: top left; }
  .work-grid { position: relative; z-index: 2; display: grid; gap: clamp(2rem, 5vw, 4rem); align-items: center; }
  @media (min-width: 62rem) { .work-grid { grid-template-columns: 1fr 1fr; } }
  .work-media { position: relative; aspect-ratio: 4/5; overflow: hidden; border-radius: 18px; box-shadow: var(--shadow); }
  .work-media img { width: 100%; height: 100%; object-fit: cover; position: absolute; inset: 0; opacity: 0; transition: opacity .6s var(--ease); }
  .work-media img.on { opacity: 1; }
  .work-arrows { position: absolute; inset: auto 0 1rem; z-index: 3; display: flex; justify-content: space-between; padding-inline: 1rem; }
  .warr { width: 42px; height: 42px; border-radius: 50%; border: 1px solid rgb(255 255 255 / .5); background: rgb(0 0 0 / .3); color: #fff; cursor: pointer; display: grid; place-items: center; transition: background-color .25s var(--ease), border-color .25s var(--ease); }
  .warr:hover { background: rgb(255 255 255 / .2); border-color: #fff; }

  /* ---------- promise ---------- */
  .promise-grid { display: grid; gap: clamp(2rem, 5vw, 4rem); align-items: center; }
  @media (min-width: 62rem) { .promise-grid { grid-template-columns: 1fr 1fr; } }
  .promise-copy { text-align: center; }
  .promise-copy .big { font-family: var(--serif); font-size: clamp(1.1rem, 2.4vw, 1.5rem); letter-spacing: .22em; text-transform: uppercase; margin: 2rem 0 1.25rem; }
  .promise-media { aspect-ratio: 4/3; overflow: hidden; border-radius: 18px; box-shadow: var(--shadow); }
  .promise-media img { width: 100%; height: 100%; object-fit: cover; }

  /* ---------- grey band, what we stand for ---------- */
  .band-grey { background: var(--grey); color: var(--on-dark); padding: calc(var(--band) * .85) 0; }
  .band-grey .label .a { color: rgb(244 242 237 / .7); }
  .band-grey .label .b { color: var(--on-dark); }
  .stands { display: grid; gap: 2rem; grid-template-columns: repeat(auto-fit, minmax(11rem, 1fr)); text-align: center; }
  .stand .k { font-family: var(--serif); font-size: clamp(2.4rem, 4.4vw, 3.6rem); font-weight: 600; letter-spacing: .1em; }
  .stand .l { font-family: var(--sans); font-size: .8125rem; font-weight: 500; letter-spacing: .2em; text-transform: uppercase; color: rgb(244 242 237 / .75); margin-top: .6rem; }

  /* ---------- about the studio ----------
     Mirrored against the founder split below, so the two read as a pair
     working down the page rather than as the same block twice. */
  .about { display: grid; gap: clamp(1.25rem, 3vw, 2.25rem); max-width: var(--max); margin-inline: auto; padding-inline: var(--gutter); align-items: center; }
  @media (min-width: 62rem) { .about { grid-template-columns: 1fr 1.05fr; } }
  .about-media { min-height: 22rem; overflow: hidden; border-radius: 18px; box-shadow: var(--shadow); }
  .about-media img { width: 100%; height: 100%; object-fit: cover; }
  .about-copy p + p { margin-top: 1.15rem; }
  .about-facts { display: grid; grid-template-columns: repeat(2, 1fr); gap: 1.25rem 1.5rem; margin-top: 2.25rem;
    padding-top: 1.75rem; border-top: 1px solid var(--rule); }
  .about-facts dt { font-family: var(--sans); font-size: .5625rem; letter-spacing: .24em; text-transform: uppercase; color: var(--mute); }
  .about-facts dd { font-family: var(--serif); font-size: 1.05rem; margin-top: .35rem; }

  /* ---------- founder split ---------- */
  .founder { display: grid; gap: clamp(1.25rem, 3vw, 2rem); max-width: var(--max); margin-inline: auto; padding-inline: var(--gutter); }
  @media (min-width: 62rem) { .founder { grid-template-columns: 1fr 1fr; } }
  .founder-copy { background: var(--paper-2); border-radius: 18px; padding: var(--band) var(--gutter); display: grid; align-content: center; text-align: center; }
  .founder-copy h2 { font-size: clamp(1.5rem, 3.4vw, 2.3rem); }
  .founder-copy .quote { font-family: var(--serif); font-size: clamp(1.05rem, 2.2vw, 1.35rem); font-style: italic; letter-spacing: .06em; text-transform: none; color: var(--ink); margin: 2rem auto 1rem; max-width: 30ch; }
  .founder-copy .attrib { font-family: var(--sans); font-size: .5625rem; letter-spacing: .36em; text-transform: uppercase; color: var(--mute); margin-bottom: 2.25rem; }
  .founder-media { min-height: 24rem; overflow: hidden; border-radius: 18px; box-shadow: var(--shadow); }
  .founder-media img { width: 100%; height: 100%; object-fit: cover; }

  /* ---------- services ---------- */
  .tabs { display: flex; flex-wrap: wrap; gap: 0; justify-content: center; margin-bottom: 3rem; border-bottom: 1px solid var(--rule); }
  .tab { min-height: 44px; padding: .9rem 1.35rem; border: 0; border-bottom: 1px solid transparent; margin-bottom: -1px; background: transparent; color: var(--mute); font-family: var(--sans); font-size: .625rem; letter-spacing: .24em; text-transform: uppercase; cursor: pointer; transition: color .25s var(--ease), border-color .25s var(--ease); }
  .tab:hover { color: var(--ink); }
  .tab[aria-selected="true"] { color: var(--ink); border-bottom-color: var(--gold); }
  .svc { display: grid; grid-template-columns: 1fr auto; gap: .45rem 2rem; align-items: baseline; width: 100%; text-align: left; font: inherit; color: inherit; cursor: pointer; background: transparent; border: 0; border-bottom: 1px solid var(--rule); padding: 1.6rem .5rem; transition: background-color .25s var(--ease), padding-left .25s var(--ease); }
  .svc:hover, .svc:focus-visible { background: var(--paper-2); padding-left: 1.25rem; }
  .svc h3 { font-family: var(--sans); font-size: 1.125rem; font-weight: 600; text-transform: none; letter-spacing: .02em; }
  .svc .desc { grid-column: 1/-1; font-size: .875rem; color: var(--mute); max-width: 56ch; margin: 0; }
  .svc .price { font-family: var(--serif); font-size: 1.75rem; font-weight: 700; letter-spacing: .06em; color: var(--gold-deep); white-space: nowrap; }
  .svc .dur { font-family: var(--sans); font-size: .5625rem; letter-spacing: .22em; text-transform: uppercase; color: var(--mute); }
  .svc .go { grid-column: 1/-1; font-family: var(--sans); font-size: .5625rem; letter-spacing: .26em; text-transform: uppercase; color: var(--gold-deep); opacity: 0; transition: opacity .25s var(--ease); }
  .svc:hover .go, .svc:focus-visible .go { opacity: 1; }

  /* ---------- the full price list, on its own page ----------

     No tabs here. Every category is laid out in order with its own heading, so
     the whole price list is one scroll and one Ctrl+F, which is how people
     actually read a price list. The jump strip is a shortcut, not a filter:
     nothing is hidden behind it. */
  .svc-jump { display: flex; flex-wrap: wrap; gap: .5rem; justify-content: center; margin-bottom: clamp(2.5rem, 6vw, 4rem); }
  .svc-jump a { padding: .65rem 1.1rem; border: 1px solid var(--rule); border-radius: 999px;
    font-family: var(--sans); font-size: .5625rem; font-weight: 600; letter-spacing: .22em;
    text-transform: uppercase; color: var(--ink-2); text-decoration: none;
    transition: border-color .25s var(--ease), color .25s var(--ease), background-color .25s var(--ease); }
  .svc-jump a:hover { border-color: var(--gold-deep); color: var(--gold-deep); background: rgb(128 102 38 / .05); }

  .svc-group { margin-bottom: clamp(3rem, 7vw, 5rem); }
  .svc-group:last-child { margin-bottom: 0; }
  /* `scroll-margin-top` so a jump link does not land the heading under the
     sticky bar, which is the single most common bug in an anchor menu. */
  .svc-group { scroll-margin-top: 6.5rem; }
  .svc-group-h { display: flex; align-items: center; gap: 1.25rem; margin-bottom: 1.25rem;
    font-family: var(--sans); font-size: .625rem; font-weight: 600; letter-spacing: .32em;
    text-transform: uppercase; color: var(--gold-deep); }
  .svc-group-h::after { content: ""; flex: 1; height: 1px; background: var(--rule); }
  .svc-group-list { border-top: 1px solid var(--rule); }

  /* Tighter than the same rows on the home page, and for a reason.

     `.go` is the "Book this" cue. It is invisible until hover but it still
     occupies a full grid row, which is nothing in a tabbed list of four and
     about eight hundred pixels of empty page across twenty one services. Here
     it sits in the right hand column beside the description instead, on the
     row that already exists. Nothing is hidden and nothing shifts on hover. */
  .svc-group-list .svc { padding-block: 1.15rem; row-gap: .3rem; }
  .svc-group-list .svc .desc { grid-column: 1; }
  .svc-group-list .svc .go { grid-column: 2; grid-row: 2; align-self: end; text-align: right; }

  /* A note that belongs with a price list rather than in the small print. */
  .price-note { margin-top: clamp(2.5rem, 6vw, 4rem); padding: 1.5rem 1.75rem; border: 1px solid var(--rule);
    border-radius: 14px; background: var(--paper-2); }
  .price-note h3 { font-family: var(--sans); font-size: .625rem; font-weight: 600; letter-spacing: .26em;
    text-transform: uppercase; color: var(--ink); margin-bottom: .75rem; }
  .price-note p { font-size: .875rem; line-height: 1.8; color: var(--ink-2); max-width: 70ch; margin: 0 0 .5rem; }
  .price-note p:last-child { margin-bottom: 0; }

  /* ---------- packages ---------- */
  .packs { display: grid; gap: clamp(1rem, 2.5vw, 1.75rem); grid-template-columns: 1fr; }
  @media (min-width: 40rem) { .packs { grid-template-columns: repeat(2, 1fr); } }
  @media (min-width: 64rem) { .packs { grid-template-columns: repeat(3, 1fr); } }

  /* The colour is set here, not inherited.

     These cards sit inside a `.band-grey` section, which is black with light
     text on it. The card puts a white background back but the text kept
     inheriting the band's near white, so black-on-black-band became
     white-on-white-card. Anything with its own background needs its own ink. */
  .pack { position: relative; display: flex; flex-direction: column; overflow: hidden; border-radius: 18px;
    background: var(--paper); color: var(--ink); border: 1px solid var(--rule); box-shadow: var(--shadow-sm);
    transition: transform .35s var(--ease), box-shadow .35s var(--ease), border-color .35s var(--ease); }
  .pack:hover { transform: translateY(-5px); box-shadow: var(--shadow); border-color: var(--gold); }
  .pack-media { position: relative; aspect-ratio: 16/10; overflow: hidden; background: var(--paper-2); }
  .pack-media img { width: 100%; height: 100%; object-fit: cover; transition: transform .6s var(--ease); }
  .pack:hover .pack-media img { transform: scale(1.05); }
  .pack-tag { position: absolute; top: .85rem; left: .85rem; background: var(--gold-deep); color: #fff;
    font-family: var(--sans); font-size: .5rem; letter-spacing: .22em; text-transform: uppercase;
    padding: .45rem .7rem; border-radius: 999px; }
  .pack-save { position: absolute; top: .85rem; right: .85rem; background: rgb(20 20 18 / .82); color: #fff;
    font-family: var(--sans); font-size: .5rem; letter-spacing: .18em; text-transform: uppercase;
    padding: .45rem .7rem; border-radius: 999px; }

  .pack-body { display: flex; flex-direction: column; flex: 1; padding: 1.5rem 1.35rem 1.35rem; }
  .pack h3 { font-family: var(--serif); font-size: 1.35rem; line-height: 1.15; color: var(--ink); }
  .pack .pack-sub { font-family: var(--sans); font-size: .5625rem; letter-spacing: .22em; text-transform: uppercase;
    color: var(--ink-2); margin-top: .5rem; }
  .pack-price { display: flex; align-items: baseline; gap: .6rem; margin: 1.1rem 0 .25rem; }
  .pack-price .now { font-family: var(--serif); font-size: 1.9rem; line-height: 1; color: var(--ink); }
  /* Dark rather than grey. The line through it is what marks it as the old
     price, so the colour does not have to fade it as well. */
  .pack-price .was { font-size: .875rem; color: var(--ink-2); text-decoration: line-through; }
  .pack-mins { font-family: var(--sans); font-size: .5625rem; letter-spacing: .2em; text-transform: uppercase; color: var(--ink-2); }
  .pack-inc { list-style: none; margin: 1.25rem 0 0; padding-top: 1.25rem; border-top: 1px solid var(--rule);
    display: flex; flex-direction: column; gap: .6rem; }
  .pack-inc li { display: flex; gap: .6rem; font-size: .875rem; line-height: 1.6; color: var(--ink); }
  .pack-inc .tick { color: var(--gold); flex: none; margin-top: .15rem; }
  .pack-inc .tick svg { width: 14px; height: 14px; }
  .pack-cta { margin-top: auto; padding-top: 1.5rem; }
  .pack-cta .btn { width: 100%; }

  /* ---------- gallery ---------- */
  .gal { display: grid; grid-template-columns: repeat(2, 1fr); gap: clamp(.6rem, 1.5vw, 1.1rem); }
  @media (min-width: 48rem) { .gal { grid-template-columns: repeat(4, 1fr); } }
  .shot { position: relative; overflow: hidden; border-radius: 18px; box-shadow: var(--shadow-sm); aspect-ratio: 3/4; padding: 0; border: 0; background: var(--paper-2); cursor: zoom-in; display: block; transition: box-shadow .3s var(--ease), transform .3s var(--ease); }
  .shot:hover, .shot:focus-visible { box-shadow: var(--shadow); transform: translateY(-4px); }
  .shot:first-child { grid-column: span 2; grid-row: span 2; aspect-ratio: auto; }
  .shot img { width: 100%; height: 100%; object-fit: cover; transition: transform .5s var(--ease); }
  .shot:hover img, .shot:focus-visible img { transform: scale(1.03); }
  .shot figcaption { position: absolute; inset: auto 0 0 0; padding: 3rem 1rem 1rem; font-family: var(--sans); font-size: .5625rem; letter-spacing: .22em; text-transform: uppercase; color: #fff; text-align: left; background: linear-gradient(transparent, rgb(20 20 18 / .75)); opacity: 0; transition: opacity .3s var(--ease); }
  .shot:hover figcaption, .shot:focus-visible figcaption { opacity: 1; }

  /* ---------- lightbox ---------- */
  .lb { position: fixed; inset: 0; z-index: 90; display: none; place-items: center; padding: clamp(1rem, 4vw, 3rem); }
  .lb[open] { display: grid; }
  .lb-back { position: absolute; inset: 0; background: rgb(18 18 16 / .95); animation: fade .3s var(--ease) both; }
  @keyframes fade { from { opacity: 0; } to { opacity: 1; } }
  .lb-fig { position: relative; z-index: 2; max-width: min(62rem, 100%); margin: 0; animation: fade .35s var(--ease) both; }
  .lb-fig img { width: 100%; max-height: 76vh; object-fit: contain; border-radius: 12px; }
  .lb-cap { color: #d8d5cd; font-family: var(--sans); font-size: .5625rem; letter-spacing: .24em; text-transform: uppercase; text-align: center; margin-top: 1.25rem; }
  .lb-btn { position: absolute; z-index: 3; width: 46px; height: 46px; border-radius: 50%; border: 1px solid rgb(255 255 255 / .25); background: transparent; color: #fff; cursor: pointer; display: grid; place-items: center; transition: background-color .25s var(--ease), border-color .25s var(--ease); }
  .lb-btn:hover { background: rgb(255 255 255 / .12); border-color: #fff; }
  .lb-close { top: clamp(1rem, 3vw, 2rem); right: clamp(1rem, 3vw, 2rem); }
  .lb-prev { left: clamp(.5rem, 2vw, 1.5rem); top: 50%; margin-top: -23px; }
  .lb-next { right: clamp(.5rem, 2vw, 1.5rem); top: 50%; margin-top: -23px; }

  /* ---------- reviews ---------- */
  .rail { --rail-gap: clamp(1.5rem, 4vw, 3.5rem); display: grid; grid-auto-flow: column; grid-auto-columns: minmax(17rem, 1fr); gap: var(--rail-gap); overflow-x: auto; scroll-snap-type: x mandatory; scrollbar-width: none; }
  .rail::-webkit-scrollbar { display: none; }
  /* Three to a view on a wide screen, the rest behind the arrows.

     This was `minmax(0, 1fr)` with `overflow: visible`, which only held while
     there were exactly four reviews. At eight they all shared the one row,
     each quote got about ninety pixels, and every sentence wrapped to one word
     per line. Tying the column to a share of the container instead of to the
     item count means adding a review never resizes the others. */
  @media (min-width: 66rem) { .rail { grid-auto-columns: calc((100% - 2 * var(--rail-gap)) / 3); } }
  .quote { scroll-snap-align: start; text-align: center; padding: 0 .5rem; }
  .quote .qm { font-family: var(--serif); font-size: 3rem; line-height: .6; color: var(--gold); }
  .quote .stars { margin-top: 1.1rem; color: var(--gold-deep); font-size: .95rem; letter-spacing: .22em; }
  .quote .stars .off { color: var(--rule); }
  .rev-source { margin-top: 1.5rem; text-align: center; font-family: var(--sans); font-size: .5625rem;
    letter-spacing: .22em; text-transform: uppercase; }
  .rev-source a { color: var(--mute); text-decoration: none; border-bottom: 1px solid currentColor;
    padding-bottom: .2rem; transition: color .25s var(--ease); }
  .rev-source a:hover { color: var(--gold); }
  .quote blockquote { margin: 1.5rem 0 1.75rem; font-family: var(--serif); font-style: italic; font-weight: 500; font-size: 1.15rem; line-height: 1.7; color: var(--ink-2); }
  .quote cite { font-style: normal; font-family: var(--serif); font-size: 1.15rem; letter-spacing: .22em; text-transform: uppercase; display: block; }
  .quote .sub { font-family: var(--sans); font-size: .5625rem; letter-spacing: .26em; text-transform: uppercase; color: var(--mute); margin-top: .6rem; display: block; }
  .rev-arrows { display: flex; gap: .5rem; justify-content: center; margin-top: 2.5rem; }
  .rev-arrow { width: 44px; height: 44px; border-radius: 50%; border: 1px solid var(--rule); background: transparent; color: var(--mute); cursor: pointer; display: grid; place-items: center; transition: border-color .25s var(--ease), color .25s var(--ease); }
  .rev-arrow:hover:not(:disabled) { border-color: var(--gold); color: var(--gold); }
  .rev-arrow:disabled { opacity: .3; cursor: not-allowed; }

  /* ---------- team split ---------- */
  .team-split { display: grid; gap: clamp(1.5rem, 3vw, 2.5rem); align-items: stretch; }
  @media (min-width: 62rem) { .team-split { grid-template-columns: 1.05fr .95fr; } }
  .team-card { background: var(--dark); color: var(--on-dark); border-radius: 18px; box-shadow: var(--shadow); padding: clamp(2.5rem, 6vw, 4.5rem); display: grid; align-content: center; text-align: center; }
  .team-card .label .a { color: var(--on-dark-2); }
  .team-card .label .b { color: var(--on-dark); }
  .team-card p { color: var(--on-dark-2); font-size: 1.125rem; font-weight: 400; line-height: 1.75; margin-bottom: 2.25rem; }
  .team-media { min-height: 20rem; overflow: hidden; border-radius: 18px; box-shadow: var(--shadow); }
  .team-media img { width: 100%; height: 100%; object-fit: cover; }
  .team { display: grid; gap: clamp(1.75rem, 4vw, 2.75rem); grid-template-columns: repeat(auto-fit, minmax(13rem, 1fr)); margin-top: clamp(2.5rem, 5vw, 4rem); }
  .person { text-align: center; border-top: 1px solid var(--rule); padding-top: 1.5rem; transition: border-color .3s var(--ease); }
  .person:hover { border-top-color: var(--gold); }
  .person h3 { font-family: var(--serif); font-size: 1.1rem; letter-spacing: .2em; }
  .person .role { font-family: var(--sans); font-size: .5625rem; letter-spacing: .26em; text-transform: uppercase; color: var(--gold-deep); margin: .7rem 0 .9rem; }
  .person p { font-size: .875rem; color: var(--mute); margin: 0; }

  /* ---------- booking ---------- */
  .book-shell { border: 1px solid var(--rule); border-radius: 16px; box-shadow: var(--shadow-sm); padding: clamp(1.5rem, 4vw, 3rem); background: var(--paper); }
  .steps { display: flex; flex-wrap: wrap; gap: 1.5rem; margin-bottom: 2.5rem; }
  .step { display: inline-flex; align-items: center; gap: .6rem; font-family: var(--sans); font-size: .5625rem; letter-spacing: .24em; text-transform: uppercase; color: var(--mute); transition: color .25s var(--ease); }
  .step .num { width: 1.5rem; height: 1.5rem; border-radius: 50%; border: 1px solid var(--rule); display: grid; place-items: center; font-size: .5625rem; transition: border-color .25s var(--ease), background-color .25s var(--ease), color .25s var(--ease); }
  .step.active, .step.done { color: var(--ink); }
  .step.active .num, .step.done .num { border-color: var(--gold); background: var(--gold); color: #fff; }
  .opts { display: grid; gap: .7rem; grid-template-columns: repeat(auto-fit, minmax(13rem, 1fr)); }
  .opt { text-align: left; min-height: 44px; background: transparent; border: 1px solid var(--rule); padding: 1.05rem 1.2rem; color: var(--ink); font: inherit; cursor: pointer; transition: border-color .25s var(--ease), background-color .25s var(--ease); }
  .opt:hover { border-color: var(--gold); background: var(--paper-2); }
  .opt[aria-pressed="true"] { border-color: var(--gold); background: var(--paper-2); }
  .opt .t { display: block; font-size: .9375rem; }
  .opt .s { display: block; font-size: .8125rem; color: var(--mute); margin-top: .2rem; }
  .slots { display: grid; grid-template-columns: repeat(auto-fill, minmax(5.5rem, 1fr)); gap: .5rem; }
  .slot { min-height: 44px; padding: .7rem .5rem; border: 1px solid var(--rule); background: transparent; color: var(--ink); font-family: var(--sans); font-size: .75rem; letter-spacing: .06em; cursor: pointer; transition: border-color .25s var(--ease), background-color .25s var(--ease), color .25s var(--ease); }
  .slot:hover:not(:disabled) { border-color: var(--gold); }
  .slot[aria-pressed="true"] { background: var(--gold); border-color: var(--gold); color: #fff; }
  .slot:disabled { opacity: .3; cursor: not-allowed; text-decoration: line-through; }
  .field { display: block; margin-bottom: 1.35rem; }
  .field span { display: block; font-family: var(--sans); font-size: .5625rem; letter-spacing: .24em; text-transform: uppercase; color: var(--mute); margin-bottom: .5rem; }
  .field input, .field textarea { width: 100%; min-height: 44px; background: transparent; border: 0; border-bottom: 1px solid var(--rule); padding: .7rem 0; color: var(--ink); font: inherit; font-size: 1rem; transition: border-color .25s var(--ease); }
  .field input:focus, .field textarea:focus { border-bottom-color: var(--gold); outline: none; }
  .field input::placeholder, .field textarea::placeholder { color: var(--mute); }
  .summary { border-top: 1px solid var(--rule); padding-top: 1.6rem; margin-top: 2rem; font-size: .9375rem; }
  .summary dl { display: grid; gap: .7rem; margin: 0; }
  .summary .row { display: flex; justify-content: space-between; gap: 1rem; }
  .summary dt { color: var(--mute); font-family: var(--sans); font-size: .5625rem; letter-spacing: .24em; text-transform: uppercase; }
  .summary dd { margin: 0; text-align: right; }
  .summary .total { border-top: 1px solid var(--rule); padding-top: .85rem; margin-top: .3rem; }
  .summary .total dd { font-family: var(--serif); font-size: 1.6rem; color: var(--gold); }
  .nav-row { display: flex; flex-wrap: wrap; gap: .75rem; margin-top: 2.25rem; align-items: center; }
  .err { color: #b4543c; font-size: .8125rem; margin-top: 1rem; }
  .done-mark { width: 3.25rem; height: 3.25rem; border-radius: 50%; border: 1px solid var(--gold); color: var(--gold); display: grid; place-items: center; margin: 0 auto; animation: fade .5s var(--ease) both; }
  .done-mark svg { width: 1.4rem; height: 1.4rem; }

  /* ---------- FAQ ---------- */
  .faq-grid { display: grid; gap: clamp(2.5rem, 5vw, 4rem); }
  @media (min-width: 62rem) { .faq-grid { grid-template-columns: .8fr 1.2fr; } }
  details.q { border-bottom: 1px solid var(--rule); }
  details.q summary { list-style: none; cursor: pointer; display: flex; align-items: center; justify-content: space-between; gap: 1.5rem; padding: 1.35rem 0; min-height: 44px; font-family: var(--sans); font-size: .8125rem; font-weight: 500; letter-spacing: .14em; text-transform: uppercase; color: var(--ink-2); transition: color .25s var(--ease); }
  details.q summary::-webkit-details-marker { display: none; }
  details.q summary:hover, details.q[open] summary { color: var(--gold); }
  details.q .chev { flex: none; transition: transform .3s var(--ease); }
  details.q[open] .chev { transform: rotate(180deg); }
  details.q p { margin: 0 0 1.4rem; color: var(--mute); font-size: .9375rem; max-width: 60ch; }

  /* ---------- visit ---------- */
  .visit { display: grid; gap: clamp(2.5rem, 6vw, 4.5rem); }
  @media (min-width: 56rem) { .visit { grid-template-columns: 1fr 1fr; } }
  .hours { width: 100%; border-collapse: collapse; }
  .hours td { padding: .95rem 0; border-bottom: 1px solid var(--rule); font-family: var(--sans); font-size: .75rem; font-weight: 500; letter-spacing: .16em; text-transform: uppercase; }
  .hours td:last-child { text-align: right; color: var(--ink-2); }
  .hours tr.today td { color: var(--gold-deep); font-weight: 700; }
  .contact-row { display: flex; gap: 1rem; padding: 1rem 0; border-bottom: 1px solid var(--rule); font-size: .9375rem; }
  .contact-row:last-of-type { border-bottom: 0; }
  .contact-row .ic { color: var(--gold); flex: none; width: 1.25rem; text-align: center; }
  .contact-row a { text-decoration: none; transition: color .25s var(--ease); }
  .contact-row a:hover { color: var(--gold); }

  /* ---------- closing ---------- */
  .closing { position: relative; padding: var(--band) var(--gutter); text-align: center; overflow: hidden; }
  .closing > img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
  .closing { border-radius: 0; }
  .closing::after { content: ""; position: absolute; inset: 0; background: rgb(246 245 242 / .84); }
  .closing-inner { position: relative; z-index: 2; }
  .closing-inner .script { font-family: var(--script); font-size: clamp(2.5rem, 8vw, 5rem); color: var(--gold); opacity: .28; line-height: 1; margin-bottom: -1.5rem; }
  .closing-inner h2 { font-size: clamp(1.3rem, 3.2vw, 2rem); }

  /* ---------- footer ---------- */
  /* ---------- footer ---------- */
  footer.site { background: var(--dark); color: var(--on-dark-2); padding: 3.5rem 0 6rem; }
  @media (min-width: 48rem) { footer.site { padding: 4.5rem 0 2.5rem; } }

  .foot-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 2.5rem 1.5rem; text-align: left; }
  @media (min-width: 48rem) { .foot-grid { grid-template-columns: 1.4fr 1fr 1fr 1.1fr; gap: 3rem 2rem; } }

  .foot-brand { grid-column: 1 / -1; }
  @media (min-width: 48rem) { .foot-brand { grid-column: auto; } }
  .foot-mark { display: flex; align-items: center; gap: .7rem; }
  .foot-mark .monogram { width: 42px; height: 42px; border-radius: 999px; border: 1px solid var(--gold); color: var(--gold);
    display: grid; place-items: center; font-family: var(--serif); font-size: .95rem; letter-spacing: .04em; flex: none; }
  .foot-wordmark { font-family: var(--serif); font-size: 1.25rem; line-height: 1.1; color: #fff; }
  .foot-about { margin-top: 1rem; max-width: 34ch; font-size: .8125rem; line-height: 1.75; color: var(--on-dark-2); }

  .foot-h { font-family: var(--sans); font-size: .5625rem; letter-spacing: .24em; text-transform: uppercase;
    color: var(--gold-soft); margin-bottom: 1rem; }
  .foot-list { list-style: none; display: flex; flex-direction: column; gap: .1rem; }
  .foot-list a, .foot-list span { display: inline-block; padding: .45rem 0; font-size: .8125rem; line-height: 1.5;
    color: var(--on-dark-2); text-decoration: none; transition: color .25s var(--ease); }
  .foot-list a:hover { opacity: 1; color: var(--gold-soft); }
  .foot-list .day { display: flex; justify-content: space-between; gap: 1rem; max-width: 15rem; color: var(--on-dark-2);
    padding: .3rem 0; font-size: .8125rem; }
  .foot-list .day.shut { color: var(--on-dark-3); }

  .foot-social { display: flex; gap: .6rem; margin-top: 1.25rem; }
  .foot-social a { width: 44px; height: 44px; border-radius: 999px; border: 1px solid rgb(255 255 255 / .18);
    display: grid; place-items: center; color: inherit; opacity: .8; transition: all .25s var(--ease); }
  .foot-social a:hover { opacity: 1; border-color: var(--gold); color: var(--gold); transform: translateY(-2px); }
  .foot-social svg { width: 17px; height: 17px; fill: currentColor; }

  .foot-base { margin-top: 3rem; padding-top: 1.5rem; border-top: 1px solid rgb(255 255 255 / .12);
    display: flex; flex-direction: column; gap: .5rem; font-size: .75rem; color: var(--on-dark-3); }
  @media (min-width: 48rem) { .foot-base { flex-direction: row; align-items: center; justify-content: space-between; } }
  .foot-legal { display: flex; flex-wrap: wrap; gap: 0 1.4rem; }
  .foot-legal button { background: none; border: 0; padding: .5rem 0; font: inherit; color: var(--on-dark-2); cursor: pointer;
    transition: color .25s var(--ease); }
  .foot-legal button:hover { color: var(--gold-soft); }
  .foot-note { margin: 1.25rem 0 0; max-width: 60ch; font-size: .6875rem; color: var(--on-dark-3); }

  /* ---------- policy dialog ---------- */
  .doc { position: fixed; inset: 0; z-index: 120; display: none; }
  .doc[open] { display: block; }
  .doc-back { position: absolute; inset: 0; background: rgb(0 0 0 / .6); backdrop-filter: blur(3px); }
  .doc-panel { position: absolute; inset: auto 0 0; max-height: 88vh; background: var(--paper); color: var(--ink);
    border-radius: 20px 20px 0 0; display: flex; flex-direction: column; box-shadow: 0 -20px 60px rgb(0 0 0 / .4); }
  @media (min-width: 48rem) {
    .doc-panel { inset: 50% auto auto 50%; transform: translate(-50%, -50%); width: min(46rem, calc(100vw - 3rem));
      max-height: 82vh; border-radius: 18px; }
  }
  .doc-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 1rem;
    padding: 1.5rem 1.5rem 1rem; border-bottom: 1px solid var(--rule); }
  .doc-head h2 { font-family: var(--serif); font-size: 1.4rem; line-height: 1.2; }
  .doc-head .sub { font-size: .75rem; color: var(--ink-2); margin-top: .3rem; }
  .doc-x { width: 40px; height: 40px; border-radius: 999px; border: 1px solid var(--rule); background: none;
    display: grid; place-items: center; cursor: pointer; flex: none; font-size: 1rem; line-height: 1; color: inherit; }
  .doc-x:hover { border-color: var(--gold); color: var(--gold); }
  .doc-body { overflow-y: auto; padding: 1.25rem 1.5rem 2rem; }
  .doc-body h3 { font-family: var(--sans); font-size: .6875rem; letter-spacing: .18em; text-transform: uppercase;
    margin: 1.75rem 0 .6rem; color: var(--gold-deep); }
  .doc-body h3:first-child { margin-top: 0; }
  .doc-body p { font-size: .875rem; line-height: 1.8; margin-bottom: .75rem; }
  .doc-body ul { margin: 0 0 .75rem 1.1rem; }
  .doc-body li { font-size: .875rem; line-height: 1.8; margin-bottom: .3rem; }

  .mobile-book { position: fixed; left: 0; right: 0; bottom: 0; z-index: 70; display: flex; gap: .6rem; padding: .7rem var(--gutter) calc(.7rem + env(safe-area-inset-bottom)); background: color-mix(in srgb, var(--paper) 94%, transparent); backdrop-filter: blur(12px); -webkit-backdrop-filter: blur(12px); border-top: 1px solid var(--rule); }
  .mobile-book .btn { flex: 1; }
  @media (min-width: 48rem) { .mobile-book { display: none; } }

  @media (hover: none) {
    .shot figcaption { opacity: 1; }
    .svc .go { opacity: 1; }
  }