/* =====================================================================
   Runway Bites | Charcuterie Carts
   Fashion-editorial static build. Vanilla CSS, mobile first.
   ===================================================================== */

/* ---------- reset ---------- */
*,*::before,*::after{box-sizing:border-box}
html,body{padding:0;margin:0}
img,svg{display:block;max-width:100%}
button,input,textarea,select{font:inherit;color:inherit}
a{color:inherit}
ul,ol{margin:0;padding:0;list-style:none}
h1,h2,h3,h4,p,figure{margin:0}

/* ---------- tokens ---------- */
:root{
  /* v12 neon system (2026-08-07). The prospect's brief: photography is
     already nightlife, the DESIGN read elegant, so the mismatch is the whole
     problem. void/surface/surface-2/hot/cyan/violet/lime/dim are the exact
     values the brief specified. ink/ink-2/ink-3 and muted/raspberry-lift now
     ALIAS those new values, so every existing var(--ink*) and var(--muted)
     and var(--raspberry-lift) usage across this file repaints on its own
     instead of needing to be hunted selector by selector. raspberry itself
     is untouched: the brief keeps it for large saturated fills only (the
     primary CTA fill, the Rooms field). */
  --void:#06050B;
  --surface:#0F0B18;
  --surface-2:#171029;
  --hot:#FF2D95;
  --cyan:#00E9F2;
  --violet:#9D4EDD;
  --lime:#CCFF33;
  --dim:#B9AFC6;

  --ink:var(--void);
  --ink-2:var(--surface);
  --ink-3:var(--surface-2);
  --ivory:#F6F1EC;
  --muted:var(--dim);
  --raspberry:#C81E5A;
  --raspberry-lift:var(--hot);
  --walnut:#7A4B32;
  --line:rgba(246,241,236,.14);
  --line-soft:rgba(246,241,236,.08);

  --display:'Syne',Arial,sans-serif;
  --sans:'Jost',Arial,sans-serif;
  --script:'Sacramento',cursive;

  --seam-x:clamp(56px,8vw,140px);
  --seam-gutter-x:clamp(56px,8vw,140px);
  --seam-lit:0%;

  --section-pad:clamp(64px,9vw,120px);
  --head-gap:clamp(28px,5vw,56px);
  --mbar-clear:84px;

  --ease:cubic-bezier(.32,.72,0,1);
  --gutter:clamp(20px,5vw,64px);
  --maxw:1360px;

  --radius:2px;
}

/* ---------- neon system utilities ----------
   The three glow recipes from the brief, kept verbatim and reused as classes
   rather than copied inline wherever a heading, rule or frame needs one.
   Cyan and violet variants follow the same recipe shape with their own
   channel values, for the spots the brief asks for more than one neon
   (the menu category headings, "bright colors used together"). */
.neon-heading{
  color:#fff;
  text-shadow:0 0 6px rgba(255,45,149,.9),0 0 22px rgba(255,45,149,.55);
}
.neon-heading--cyan{
  color:#fff;
  text-shadow:0 0 6px rgba(0,233,242,.9),0 0 22px rgba(0,233,242,.55);
}
.neon-heading--violet{
  color:#fff;
  text-shadow:0 0 6px rgba(157,78,221,.9),0 0 22px rgba(157,78,221,.55);
}
.neon-rule{
  height:2px;
  border:0;
  background:var(--hot);
  box-shadow:0 0 8px var(--hot),0 0 24px rgba(255,45,149,.6);
}
.neon-frame{
  border:1.5px solid var(--hot);
  box-shadow:0 0 0 1px rgba(255,45,149,.22),0 0 18px rgba(255,45,149,.32);
}
.neon-frame--cyan{
  border-color:var(--cyan);
  box-shadow:0 0 0 1px rgba(0,233,242,.22),0 0 18px rgba(0,233,242,.32);
}
.neon-frame--violet{
  border-color:var(--violet);
  box-shadow:0 0 0 1px rgba(157,78,221,.22),0 0 18px rgba(157,78,221,.32);
}

/* eyebrow colour + a small kicker rule beneath it. Cyan and violet stay off
   eyebrow TEXT by default: measured against --void, violet text is 4.42:1,
   under the 4.5:1 AA floor for small text (eyebrows run .72rem). Hot and
   cyan both clear 4.5:1 comfortably, so those two are the only text-color
   rotation; violet is reserved for the decorative bar (a graphical element,
   not text, so the text-contrast floor does not apply) and for the neon
   frames below. This is how violet gets real presence in the upper page
   without a contrast regression. */
.eyebrow.accent-cyan{color:var(--cyan)}
.eyebrow-bar::after{
  content:'';
  display:block;
  width:28px;height:2px;
  margin-top:8px;
}
.eyebrow-bar.bar-hot::after{background:var(--hot);box-shadow:0 0 8px var(--hot),0 0 20px rgba(255,45,149,.5)}
.eyebrow-bar.bar-cyan::after{background:var(--cyan);box-shadow:0 0 8px var(--cyan),0 0 20px rgba(0,233,242,.5)}
.eyebrow-bar.bar-violet::after{background:var(--violet);box-shadow:0 0 8px var(--violet),0 0 20px rgba(157,78,221,.5)}

/* The seam stays in the left gutter at every width. A centered spine with
   sections alternating either side of it was tried and reversed: this page
   does not have the content to fill two half-columns, so the alternation
   produced 400px voids opposite every block, split the hero wordmark, and
   cut the band and feed images in half. It read as a broken two-column grid,
   not as a catwalk. The runway idea is carried by the rail, the lit scroll
   track and the numerals instead. */
@media (max-width:900px){
  :root{ --seam-x:16px; --seam-gutter-x:16px; }
}

/* ---------- base ---------- */
html{scroll-behavior:smooth}
@media (prefers-reduced-motion:reduce){
  html{scroll-behavior:auto}
}
body{
  background-color:var(--ink);
  /* a very subtle static film-grain tile. It rides the body's own background
     so it reads as "full page" while sitting entirely behind section content,
     and it is naturally hidden wherever the ivory programme section paints
     its own opaque paper-grain background over it. No animation, so there is
     nothing prefers-reduced-motion needs to switch off. */
  background-image:url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0naHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmcnIHdpZHRoPScxODAnIGhlaWdodD0nMTgwJz48ZmlsdGVyIGlkPSduJz48ZmVUdXJidWxlbmNlIHR5cGU9J2ZyYWN0YWxOb2lzZScgYmFzZUZyZXF1ZW5jeT0nMC44NScgbnVtT2N0YXZlcz0nMicgc3RpdGNoVGlsZXM9J3N0aXRjaCcvPjxmZUNvbG9yTWF0cml4IHR5cGU9J21hdHJpeCcgdmFsdWVzPScwIDAgMCAwIDEgIDAgMCAwIDAgMSAgMCAwIDAgMCAxICAwIDAgMCAwLjA1IDAnLz48L2ZpbHRlcj48cmVjdCB3aWR0aD0nMTAwJScgaGVpZ2h0PScxMDAlJyBmaWx0ZXI9J3VybCgjbiknLz48L3N2Zz4=");
  color:var(--ivory);
  font-family:var(--sans);
  font-size:16px;
  line-height:1.6;
  position:relative;
  /* `hidden` on the body makes overflow-y compute to `auto`, which turns the
     body into a scroll container and is the classic reason position:sticky
     silently stops working. `clip` does the same visual job without creating
     one. The `hidden` line stays first as the fallback for older engines. */
  overflow-x:hidden;
  overflow-x:clip;
  -webkit-font-smoothing:antialiased;
}
::selection{background:var(--raspberry);color:var(--ivory)}

a{text-decoration:none}
:focus-visible{
  outline:2px solid var(--raspberry-lift);
  outline-offset:3px;
  border-radius:1px;
}

.visually-hidden{
  position:absolute!important;width:1px;height:1px;padding:0;margin:-1px;
  overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0;
}

.skip-link{
  position:fixed;top:-100px;left:12px;z-index:200;
  background:var(--raspberry);color:var(--ivory);
  padding:12px 18px;font-size:.85rem;letter-spacing:.05em;
  transition:top .25s var(--ease);
}
.skip-link:focus{top:12px}

.wrap{
  max-width:var(--maxw);
  margin-inline:auto;
  padding-inline:var(--gutter);
  position:relative;
}

section{position:relative;isolation:isolate;scroll-margin-top:84px}

/* ---------- typography ---------- */
h1,h2,h3{font-family:var(--display);font-weight:700;letter-spacing:.01em;text-wrap:balance}
.eyebrow{
  font-family:var(--sans);
  font-size:.72rem;
  letter-spacing:.28em;
  text-transform:uppercase;
  color:var(--muted);
}
.eyebrow.accent{color:var(--raspberry-lift)}

.h2{
  font-size:clamp(2rem,4vw,3.2rem);
  text-transform:uppercase;
  letter-spacing:.01em;
  line-height:1.08;
}
.h3{
  font-size:clamp(1.35rem,2.2vw,1.8rem);
  text-transform:uppercase;
  line-height:1.15;
}
p{max-width:60ch;color:var(--ivory)}
.lede{
  font-size:clamp(1.05rem,1.6vw,1.25rem);
  color:var(--muted);
  max-width:52ch;
}
.small{font-size:.85rem;color:var(--muted)}

/* ---------- buttons ---------- */
.btn{
  display:inline-flex;
  align-items:center;
  justify-content:center;
  gap:10px;
  font-family:var(--sans);
  font-size:.82rem;
  letter-spacing:.14em;
  text-transform:uppercase;
  padding:16px 30px;
  border-radius:999px;
  border:1px solid transparent;
  cursor:pointer;
  white-space:nowrap;
  transition:transform .45s var(--ease),background-color .3s var(--ease),
             border-color .3s var(--ease),color .3s var(--ease);
}
.btn:active{transform:scale(.97)}

.btn-primary{
  background:var(--raspberry);
  color:var(--ivory);
  border-color:var(--raspberry);
}
.btn-primary:hover{background:var(--raspberry-lift);border-color:var(--raspberry-lift)}

.btn-ghost{
  /* a translucent ground rather than pure transparency: the outline alone
     disappeared over the busy hero photograph */
  background:rgba(8,6,10,.34);
  backdrop-filter:blur(6px);
  -webkit-backdrop-filter:blur(6px);
  color:var(--ivory);
  border-color:rgba(246,241,236,.42);
}
.btn-ghost:hover{border-color:var(--ivory);background:rgba(8,6,10,.52)}

.btn-ig{
  background:var(--ink-2);
  color:var(--ivory);
  border-color:var(--line);
}
.btn-ig:hover{border-color:var(--raspberry-lift);color:var(--raspberry-lift)}

.btn-sm{padding:11px 20px;font-size:.72rem}

/* ---------- header ---------- */
/* The header sits clear over the hero photograph and only takes on a surface
   once the page has scrolled, so nothing competes with the opening frame. */
/* above the drawer (150) and the mobile action bar (160): the hamburger turns
   into the close X, so if the drawer paints over the header there is no visible
   way out of the menu on a phone. */
.site-header{
  position:fixed;top:0;left:0;right:0;z-index:200;
  background:transparent;
  border-bottom:1px solid transparent;
  transition:background .4s var(--ease),border-color .4s var(--ease),
             backdrop-filter .4s var(--ease);
}
html.scrolled .site-header{
  background:rgba(8,6,10,.86);
  backdrop-filter:blur(16px);
  -webkit-backdrop-filter:blur(16px);
  border-bottom-color:var(--line-soft);
}
.site-header .wrap{
  display:flex;
  align-items:center;
  justify-content:space-between;
  height:72px;
  padding-block:12px;
}
/* the mark is set in type rather than a raster logo. The old 150px avatar
   was a black square with visible edges sitting on a black bar. */
.brand-lockup{
  display:flex;
  align-items:baseline;
  gap:9px;
  line-height:1;
}
.brand-script{
  font-family:var(--script);
  font-size:1.72rem;
  color:var(--ivory);
  transform:translateY(2px);
}
.brand-word{
  font-family:var(--sans);
  font-size:.68rem;
  font-weight:500;
  letter-spacing:.42em;
  text-transform:uppercase;
  color:var(--raspberry-lift);
}
@media (max-width:480px){
  .brand-script{font-size:1.5rem}
  .brand-word{letter-spacing:.3em}
}

.nav-links{display:none;gap:clamp(18px,2.4vw,34px);align-items:center}
.nav-links a{
  font-size:.78rem;
  letter-spacing:.12em;
  text-transform:uppercase;
  color:var(--ivory);
  position:relative;
  padding-block:4px;
}
.nav-links a::after{
  content:'';position:absolute;left:0;right:100%;bottom:0;height:1px;
  background:var(--raspberry-lift);
  transition:right .35s var(--ease);
}
.nav-links a:hover::after,.nav-links a:focus-visible::after{right:0}

.header-actions{display:flex;align-items:center;gap:12px}
.header-actions .btn-primary{display:none}

.hamburger{
  display:grid;place-items:center;
  width:44px;height:44px;
  background:var(--ink-2);
  border:1px solid var(--line);
  border-radius:50%;
  cursor:pointer;
}
.hamburger svg{width:20px;height:20px;stroke:var(--ivory);fill:none;stroke-width:1.6;transition:transform .3s var(--ease)}
.hamburger .icon-close{display:none}
.hamburger[aria-expanded="true"] .icon-open{display:none}
.hamburger[aria-expanded="true"] .icon-close{display:block}

@media (min-width:900px){
  .nav-links{display:flex}
  .header-actions .btn-primary{display:inline-flex}
  .hamburger{display:none}
}

/* mobile drawer */
.drawer{
  position:fixed;inset:0;z-index:150;
  background:rgba(8,6,10,.97);
  backdrop-filter:blur(18px);
  -webkit-backdrop-filter:blur(18px);
  display:flex;flex-direction:column;
  padding:100px var(--gutter) 40px;
  transform:translateY(-8px);
  opacity:0;
  pointer-events:none;
  transition:opacity .4s var(--ease),transform .4s var(--ease);
}
.drawer.open{opacity:1;transform:translateY(0);pointer-events:auto}
.drawer nav{display:flex;flex-direction:column;gap:6px}
.drawer nav a{
  font-family:var(--display);
  font-weight:700;
  font-size:clamp(1.6rem,7vw,2.2rem);
  text-transform:uppercase;
  padding:12px 0;
  border-bottom:1px solid var(--line-soft);
  opacity:0;
  transform:translateY(16px);
  transition:opacity .5s var(--ease),transform .5s var(--ease);
}
.drawer.open nav a{opacity:1;transform:translateY(0)}
.drawer.open nav a:nth-child(1){transition-delay:.06s}
.drawer.open nav a:nth-child(2){transition-delay:.11s}
.drawer.open nav a:nth-child(3){transition-delay:.16s}
.drawer.open nav a:nth-child(4){transition-delay:.21s}
.drawer.open nav a:nth-child(5){transition-delay:.26s}
.drawer .btn{
  margin-top:28px;
  align-self:flex-start;
  opacity:1;
  transform:none;
}
@media (prefers-reduced-motion:reduce){
  .drawer,.drawer nav a{transition:none}
}
@media (min-width:900px){ .drawer{display:none} }

/* ---------- hero ---------- */
/* Split, not text-over-photo. The prospect's own note: text sitting on top
   of a photograph "is a distraction". The photograph now has its own cell
   (.hero-media, in a neon frame) instead of sitting behind the wordmark, and
   .split's base rule stacks the photograph first on a phone, text cell
   second, text-left at 960 and up per the brief. */
.hero{
  min-height:100dvh;
  display:flex;
  align-items:center;
  padding-block:calc(72px + 40px) 60px;
}
@media (max-width:759px){
  .hero{padding-block:calc(72px + 20px) 40px}
}
.hero-split{width:100%}
.hero-text{max-width:640px;container-type:inline-size}

/* the venue line: styled as a ticket or marquee credit rather than a plain
   eyebrow, since it is doing the job of announcing where the show plays */
.venue-line{
  display:inline-block;
  font-family:var(--sans);
  font-size:.72rem;
  letter-spacing:.3em;
  text-transform:uppercase;
  color:var(--muted);
  padding-block:12px;
  border-top:1px solid var(--line);
  border-bottom:1px solid var(--line);
  margin-bottom:34px;
}
@media (max-width:759px){
  /* the three cities have to hold one line here. At the desktop tracking they
     wrapped and left BEACH orphaned on a line of its own between the two
     rules, which read as a break rather than a credit. */
  .venue-line{
    padding-block:7px;
    margin-bottom:16px;
    font-size:.62rem;
    letter-spacing:.14em;
  }
}

/* RUNWAY now sizes against its own text cell rather than the viewport, since
   it no longer has to bleed full width to carry the hero on its own. Syne
   800 is a wide, heavy grotesk built for exactly this kind of oversized
   display moment, and it is the one place on the page carrying the full
   neon-heading glow: the biggest word gets the effect, not every heading. */
.hero-runway{
  width:fit-content;
  display:flex;
  flex-direction:column;
  align-items:flex-start;
  margin-bottom:clamp(6px,1.6vw,16px);
}
/* RUNWAY must stay on one line at every width, 320 to 1920. It was sized off
   vw units, which track the VIEWPORT, not the actual text column: at 960px
   and up the column is roughly half the viewport (the split), so a vw-based
   size that fit a single-column phone layout was too large for the desktop
   half-column and wrapped "RUNWAY" into "RUN" / "WAY". Measured in-browser,
   Syne 800 renders "RUNWAY" at 7.628x its font-size. .hero-text establishes
   a query container above, so cqw here tracks that cell's REAL width at
   every breakpoint, split or not. 12cqw keeps the word at ~91.5% of the
   container, an 8.5% margin, and white-space:nowrap forces a font-size
   mistake to show up as visible overflow instead of a silent, brand-breaking
   line split. */
.hero-word{
  display:inline-block;
  font-family:var(--display);
  font-weight:800;
  font-size:clamp(1.9rem,12cqw,6.2rem);
  line-height:.96;
  letter-spacing:-.01em;
  white-space:nowrap;
  color:#fff;
  text-shadow:0 0 6px rgba(255,45,149,.9),0 0 22px rgba(255,45,149,.55);
}

/* Bites tucks under the tail of RUNWAY, the way the client's own logo and
   post artwork read. width:fit-content on the wordmark above means the
   flex column shrinks to the word's own rendered width, so align-self:
   flex-end here lands Bites at the true right edge of RUNWAY rather than a
   viewport-relative guess. */
.hero-bites{
  display:block;
  align-self:flex-end;
  font-family:var(--script);
  font-size:clamp(2rem,5.4vw,3.4rem);
  color:var(--raspberry-lift);
  line-height:1;
  margin-top:clamp(-1.5rem,-2.6vw,-.8rem);
  margin-right:clamp(2px,1.4vw,14px);
  text-align:right;
  transform:rotate(-3deg);
  transform-origin:right center;
}
@media (max-width:759px){
  .hero-bites{
    font-size:2.1rem;
    margin-top:-.85rem;
  }
}

.hero-sub{
  font-family:var(--display);
  font-weight:700;
  font-size:clamp(1.15rem,2vw,1.5rem);
  line-height:1.2;
  color:#fff;
  margin-bottom:10px;
}
.hero-tag{
  font-size:1rem;
  color:var(--muted);
  margin-bottom:36px;
}
@media (max-width:759px){
  .hero-sub{margin-bottom:6px}
  .hero-tag{margin-bottom:20px}
}
.hero-ctas{display:flex;flex-wrap:wrap;gap:16px}
@media (max-width:759px){
  .hero-ctas{gap:10px}
}

/* ---------- shared page furniture ---------- */
.section-head{margin-bottom:var(--head-gap);max-width:640px}

/* ---------- the split: LAW 2 ----------
   Every content section that pairs a photo with copy is a two-column split
   at 960px and up, image in one cell and text in the other, alternating
   which side the image sits on down the page (hero, the three services,
   the rooms). Below 960 they stack, image first, always, regardless of
   which side the image sits on at desktop: the base rule below sets that
   stacking order and the text-left modifier only touches the desktop rule
   inside the media query, so a "text-left" section never reorders on a
   phone. Source order in the markup is text-then-media (the accessible
   reading order); `order` does the visual work at every width. */
.split{
  display:grid;
  grid-template-columns:minmax(0,1fr);
  gap:clamp(28px,6vw,56px);
  align-items:center;
}
.split-media{order:0}
.split-text{order:1}
@media (min-width:960px){
  .split{
    grid-template-columns:minmax(0,1fr) minmax(0,1fr);
    gap:clamp(48px,6vw,96px);
  }
  .split--text-left .split-text{order:1}
  .split--text-left .split-media{order:2}
}
.split-media{
  position:relative;
  overflow:hidden;
  background:var(--ink-2);
  /* one frame ratio for every split-media cell on the page (hero, the three
     services, rooms), so the neon frame reads as one system going down the
     page rather than a different crop shape per section */
  aspect-ratio:4/5;
}
.split-media img,.split-media picture{
  display:block;
  width:100%;
  height:100%;
}
.split-media img{object-fit:cover}

/* An ivory paper-stock register, reused wherever the page needs to break
   from the dark canvas: the composer sheet in section C. Local tokens
   (walnut standing in for muted, ink-tinted hairlines instead of
   ivory-tinted ones) keep every existing rule that reads var(--muted) or
   var(--line) correct without having to rewrite it. */
.section-ivory{
  background-color:var(--ivory);
  color:var(--ink);
  --muted:var(--walnut);
  --line:rgba(8,6,10,.16);
  --line-soft:rgba(8,6,10,.09);
  background-image:url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0naHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmcnIHdpZHRoPScxODAnIGhlaWdodD0nMTgwJz48ZmlsdGVyIGlkPSdwJz48ZmVUdXJidWxlbmNlIHR5cGU9J2ZyYWN0YWxOb2lzZScgYmFzZUZyZXF1ZW5jeT0nMC43NScgbnVtT2N0YXZlcz0nMicgc3RpdGNoVGlsZXM9J3N0aXRjaCcvPjxmZUNvbG9yTWF0cml4IHR5cGU9J21hdHJpeCcgdmFsdWVzPScwIDAgMCAwIDAgIDAgMCAwIDAgMCAgMCAwIDAgMCAwICAwIDAgMCAwLjA0NSAwJy8+PC9maWx0ZXI+PHJlY3Qgd2lkdGg9JzEwMCUnIGhlaWdodD0nMTAwJScgZmlsdGVyPSd1cmwoI3ApJy8+PC9zdmc+");
  padding-block:var(--section-pad);
}
.section-ivory p{color:var(--ink)}
.section-ivory .eyebrow.accent{color:var(--raspberry)}

/* ---------- A: services, three alternating split rows ----------
   The old build presented these three as a drag carousel. The redesign
   brief's second law is explicit: every content section that pairs a photo
   with copy is a two-column split, image and text alternating sides going
   down the page, so the carousel (and its drag / wheel / arrow-key /
   progress-rail machinery in script.js, left in place but now unreferenced
   since no element in this section carries its old ids) is retired for
   three stacked .split rows. Row order in the markup already carries the
   image | text, text | image, image | text alternation. */
.services-split{padding-block:var(--section-pad)}
.svc-rows{
  display:flex;
  flex-direction:column;
  gap:clamp(48px,5vw,72px);
  margin-top:clamp(8px,1.6vw,20px);
}
/* .split centres its two cells, which is right for the hero and for #rooms
   where the columns are close in height. Here the photo is a 4/5 frame at
   716px against 471px of copy, so centring left 122px of dead space ABOVE and
   BELOW the text and the block floated. Top-aligned, the row opens on a shared
   line and the leftover height reads as the photograph simply being tall.
   Measured at 1440 before the change: 122/122. The .split-media aspect-ratio
   is untouched, so the one-frame-ratio system across hero, services and rooms
   still holds. */
@media (min-width:960px){
  .svc-row{align-items:start}
}
.svc-media img{filter:brightness(.9) saturate(1.05)}
@media (hover:hover) and (pointer:fine){
  .svc-media img{transition:transform .8s var(--ease)}
  .svc-media:hover img{transform:scale(1.045)}
}
.svc-body{
  display:flex;flex-direction:column;
  align-items:flex-start;
  gap:12px;
}
.svc-serves{
  font-size:.7rem;letter-spacing:.26em;text-transform:uppercase;
  color:var(--hot);
}
/* dropped from clamp(2rem,3.6vw,2.8rem) for the same reason as .room h3: at
   1440 it rendered 45px against a 51px .h2, and in Syne's wide letterforms
   a mixed-case 45px reads larger than an uppercase 51px, so the service name
   was beating the section title it sits under. */
.board-name{
  font-family:var(--display);
  font-weight:800;
  font-size:clamp(1.6rem,2.9vw,2.25rem);
  line-height:1.02;
  color:#fff;
}
.svc-desc{font-size:.95rem;color:var(--dim);max-width:48ch;line-height:1.6}
.svc-list{
  display:flex;flex-direction:column;gap:8px;
  padding-top:6px;
  width:100%;
}
.svc-list li{
  font-size:.9rem;
  color:rgba(255,255,255,.88);
  padding-left:20px;
  position:relative;
}
/* 2px, not 1px. Every one of these dashes is declared the same colour, but a
   1px hairline positioned with an em offset lands on a fractional device pixel
   on most rows: Chrome splits it across two rows at half alpha and it renders
   grey, so a list read as randomly alternating pink and grey bullets. Measured,
   not guessed: three sibling dashes in one card computed to identical
   rgb(255,45,149) while landing at y .07, .60 and .12. */
.svc-list li::before{
  content:'';position:absolute;left:0;top:.62em;
  width:9px;height:2px;background:var(--hot);
  box-shadow:0 0 4px var(--hot);
}
.svc-best{
  font-size:.85rem;
  color:var(--muted);
  border-top:1px solid var(--line-soft);
  padding-top:14px;
  margin-top:4px;
  max-width:44ch;
}
.svc-body .btn{margin-top:8px}

/* ---------- B: the rooms, on a full raspberry field ----------
   The vibrancy: after two dark-register stops, a saturated field with
   ivory type, edge to edge. Ivory on raspberry measures 4.92:1, fine for a
   full paragraph, so every line of running copy here stays ivory. Ink on
   raspberry is 3.46:1, large text only, so it is not used here at all.
   Raspberry-lift is too close to raspberry to read as text at all, so it
   never appears here either. The How It Rolls strip that used to close this
   field was removed on 2026-08-07 at Andy's request; the section now ends
   on the last room. */
.rooms{
  background-color:var(--raspberry);
  color:var(--ivory);
  padding-block:var(--section-pad);
}
.rooms .eyebrow{color:var(--ivory)}
.rooms .h2{color:var(--ivory)}

.rooms-list{border-top:1px solid rgba(246,241,236,.32)}
/* The heading sits ABOVE the paragraph, full width of the .room cell, at
   every width. This used to go side by side at 760px and up (heading in a
   .82fr column, paragraph in 1fr), which worked when .rooms-list ran the
   full page width. It no longer does: .rooms-list now lives inside the
   text half of a page-level split (Section 05), so that side-by-side
   layout was squeezing a .82fr heading column down to ~232px while the
   heading itself, in Syne 800 at up to 4.2rem (67.2px), rendered upward of
   500px wide for "Weddings" and more for "Private Events". The heading
   overflowed its column to the right and sat on top of the paragraph text
   next to it. Stacking gives the heading the .room cell's full width, so
   it wraps within itself (never overflows its own box) instead of
   overlapping a neighbour. */
/* minmax(0,1fr), not a bare 1fr: a bare fr track's implicit minimum is
   auto (its content's min-content size), and "Weddings" / "Corporate" are
   single unbreakable words. At narrow widths that min-content size forced
   the track, and everything inside it, wider than the .room cell, which
   showed up as 2.7-5.9px of real horizontal overflow at 320. Same failure
   family as the .field-row grid blowout already fixed elsewhere in this
   file. overflow-wrap on the heading is the second half of the fix: it
   lets a single word that still does not fit break mid-word instead of
   spilling past its box. */
.room{
  display:grid;
  grid-template-columns:minmax(0,1fr);
  gap:6px;
  padding-block:clamp(22px,3.6vw,38px);
  border-bottom:1px solid rgba(246,241,236,.32);
  container-type:inline-size;
}
/* clamp(2.3rem,6vw,4.2rem) scaled against the VIEWPORT, not the column it
   actually has to fit inside. Below 960 that is close enough to the same
   thing, which is why it looked fixed at first. At 960 and up .rooms runs
   the page-level split, so the text column is roughly half the viewport,
   the column halves and 6vw does not, and "Corporate" overflowed its cell
   by up to 81px. .room now establishes its own query container above, so
   cqw here tracks the .room cell's real width at every breakpoint,
   including the exact moment the split engages. overflow-wrap stays on as
   a last-resort guard; the clamp should not need it. */
/* 2026-08-08: was clamp(2rem,11cqw,4.2rem), which rendered 63px at 1440 and
   39px at 390 against an .h2 of 51px and 32px. A section's h3 outshouting
   every h2 on the page is a hierarchy inversion, and next to a 16px paragraph
   it read as a mistake rather than as emphasis. 8cqw keeps the container-query
   guard that stopped "Corporate" overflowing its cell and lands the heading a
   clear step BELOW the h2 at every width. */
.room h3{
  font-family:var(--display);
  font-weight:800;
  text-transform:none;
  font-size:clamp(1.75rem,8cqw,2.9rem);
  line-height:.98;
  color:var(--ivory);
  overflow-wrap:break-word;
}
.room p{max-width:44ch;font-size:.98rem;margin-top:2px}
/* the last room does not need a bottom rule. Nothing follows it inside the
   text half now, so a trailing hairline reads as a stray divider. */
.rooms-list .room:last-child{border-bottom:0}
@media (min-width:760px){
  .room p{font-size:1.02rem}
}

/* ---------- C: build yours, converted from ivory to dark and neon ----------
   The reserve section dropped .section-ivory in this pass, so it is back to
   the page's own void ground and the base dark-surface rules for .field,
   .cfg-option and .cfg-number below apply directly again. .cfg-card gets
   its neon frame from the ".cfg-card" rule itself now, not an override
   scoped through .configurator. */
.configurator{padding-block:var(--section-pad)}
/* ONE form closes the page. The composer used to sit in its own ivory section
   above a second, darker section carrying the real contact form, so a visitor
   answered three questions, pressed a button that only scrolled them down, and
   met the same three questions again next to the fields. The questions are now
   fields of this form and the card is a read-out of it.

   Source order is choices, card, details, which is the right reading order on
   a phone: choose, see the card fill in, then hand over your details. On
   desktop the card moves to a sticky second column spanning both, so it stays
   in view while the details are filled in. */
.reserve-form{
  display:grid;
  grid-template-columns:minmax(0,1fr);
  gap:clamp(30px,5vw,46px);
}
@media (min-width:960px){
  .reserve-form{
    grid-template-columns:minmax(0,1.15fr) minmax(0,.85fr);
    column-gap:64px;
    align-items:start;
  }
  .rf-choices{grid-column:1;grid-row:1}
  .rf-details{grid-column:1;grid-row:2}
  .rf-card{
    grid-column:2;
    grid-row:1 / span 2;
    position:sticky;
    top:calc(72px + 20px);
  }
}

/* the two steps are numbered because the form now has two distinct halves and
   the card sits between them on a phone */
.rf-step{
  display:flex;
  align-items:baseline;
  gap:10px;
  font-family:var(--sans);
  font-size:.76rem;
  letter-spacing:.18em;
  text-transform:uppercase;
  color:var(--muted);
  padding-bottom:12px;
  margin-bottom:26px;
  border-bottom:1px solid var(--line);
}
.rf-step-num{
  font-family:var(--display);
  font-weight:700;
  font-size:1.15rem;
  letter-spacing:0;
  color:var(--hot);
}
/* Two actions now, the relay submit and WhatsApp. Stacked full width on a
   phone, side by side once there is room, with the primary first in source
   order so it is also first in the tab order. */
.rf-actions{display:flex;flex-direction:column;gap:10px;margin-top:6px}
.rf-submit,.rf-wa{width:100%}
.rf-submit[disabled]{opacity:.6;cursor:progress}
@media (min-width:600px){
  .rf-actions{flex-direction:row;flex-wrap:wrap;align-items:center}
  .rf-submit,.rf-wa{width:auto}
}


.cfg-groups{display:flex;flex-direction:column;gap:28px}
@media (min-width:600px){
  .cfg-groups{gap:34px}
}
.cfg-group{border:0;margin:0;padding:0}
.cfg-group .cfg-label{
  font-size:.78rem;
  letter-spacing:.18em;
  text-transform:uppercase;
  color:var(--muted);
  margin-bottom:14px;
  padding:0;
}
.cfg-options{
  display:flex;flex-wrap:wrap;gap:9px;
  border:0;padding:0;margin:0;
}
.cfg-option{position:relative}
.cfg-option input{
  position:absolute;opacity:0;width:100%;height:100%;margin:0;cursor:pointer;
}
.cfg-option label{
  display:inline-flex;align-items:center;
  padding:10px 16px;
  border:1px solid var(--line);
  border-radius:999px;
  font-size:.76rem;
  letter-spacing:.08em;
  text-transform:uppercase;
  color:var(--muted);
  cursor:pointer;
  transition:border-color .3s var(--ease),color .3s var(--ease),background-color .3s var(--ease);
}
@media (min-width:600px){
  .cfg-option label{padding:12px 22px;font-size:.82rem}
}
.cfg-option input:hover + label{border-color:var(--ivory);color:var(--ivory)}
.cfg-option input:checked + label{
  background:var(--raspberry);
  border-color:var(--raspberry);
  color:var(--ivory);
}
.cfg-option input:focus-visible + label{
  outline:2px solid var(--raspberry-lift);
  outline-offset:3px;
}

/* number control (guests): same field chrome as the reserve form's own
   inputs, kept narrow since it only ever holds a short number */
.cfg-group--number .cfg-label{margin-bottom:10px}
.cfg-optional{
  text-transform:none;
  letter-spacing:0;
  color:var(--muted);
  font-size:.72rem;
}
/* the guest field belongs to the same set as the chips, so it is a ruled
   line rather than a boxed input. "Optional" is said once, in the label. */
.cfg-number{
  display:block;
  width:100%;
  max-width:170px;
  background:transparent;
  border:0;
  border-bottom:1px solid var(--line);
  color:var(--ivory);
  font-family:var(--display);
  font-weight:700;
  font-size:1.45rem;
  letter-spacing:.02em;
  padding:0 2px 8px;
  margin-top:-2px;
  border-radius:0;
  transition:border-color .3s var(--ease);
}
.cfg-number:hover{border-bottom-color:rgba(246,241,236,.34)}
.cfg-number::placeholder{color:rgba(162,148,155,.6)}
.cfg-number:focus-visible{
  outline:2px solid var(--raspberry-lift);outline-offset:4px;
  border-bottom-color:var(--raspberry-lift);
}

/* ---------- the order of service card ----------
   A glowing ticket rather than a printed order card: the reserve section
   left the ivory paper register behind with it, so the card is now a
   surface panel in a neon frame instead of paper stock. Unfilled rows still
   carry a dotted leader rather than a placeholder sentence, so there is no
   empty state left to design around, and every row is present from first
   paint so the card never changes height as it fills in. */
.cfg-card{
  position:relative;
  background-color:var(--surface);
  color:#fff;
  border:1.5px solid var(--hot);
  box-shadow:0 20px 44px -22px rgba(0,0,0,.7),0 0 0 1px rgba(255,45,149,.22),0 0 18px rgba(255,45,149,.28);
  padding:18px 16px 16px;
}
@media (min-width:600px){
  .cfg-card{padding:26px 24px 22px}
}
@media (min-width:960px){
  .cfg-card{padding:34px 32px 30px}
}

.cfg-card-head{
  display:flex;align-items:baseline;justify-content:space-between;
  margin-bottom:2px;
}
.cfg-card-brand{
  font-family:var(--sans);
  font-size:.64rem;
  letter-spacing:.2em;
  text-transform:uppercase;
  color:var(--dim);
}
.cfg-card-num{
  font-family:var(--display);
  font-weight:700;
  font-size:1rem;
  color:var(--hot);
}
.cfg-card-kicker{
  font-family:var(--display);
  font-weight:700;
  font-size:clamp(1.2rem,4.4vw,1.6rem);
  line-height:1.15;
  letter-spacing:.01em;
  color:#fff;
  margin-bottom:14px;
}
.cfg-card-rule{
  border:0;border-top:1px solid rgba(255,45,149,.32);
  margin:0 0 6px;
}

/* min-height, because an empty .cfg-card-row-value has no text node and so no
   line box at all: the row measured 36.4px empty and 41.5px filled, and with
   four rows the card walked ~20px down the page as the visitor answered. The
   value's own line box is 22.5px, so 2.65em holds the filled height in both
   states. em rather than px so the accessibility widget's larger-text mode
   scales the reservation with the type instead of clipping against it. */
.cfg-card-row{
  display:flex;
  align-items:center;
  flex-wrap:nowrap;
  gap:8px;
  min-height:2.65em;
  padding-block:7px;
  border-bottom:1px solid var(--line-soft);
}
.cfg-card-row-label{
  flex:0 0 auto;
  font-family:var(--sans);
  font-size:.62rem;
  letter-spacing:.15em;
  text-transform:uppercase;
  color:var(--dim);
  white-space:nowrap;
}
.cfg-card-row-fill{
  flex:1 1 auto;
  min-width:10px;
  align-self:stretch;
  margin-block:auto;
  height:0;
  border-bottom:1px dotted rgba(246,241,236,.28);
}
.cfg-card-row-value{
  flex:0 1 auto;
  min-width:0;
  text-align:right;
  font-family:var(--sans);
  font-size:.8rem;
  color:#fff;
  white-space:nowrap;
  opacity:0;
  transform:translateY(3px);
  transition:opacity .18s var(--ease),transform .18s var(--ease);
}
.cfg-card-row[data-filled="true"] .cfg-card-row-value{opacity:1;transform:none}
@media (min-width:600px){
  .cfg-card-row{padding-block:9px}
  .cfg-card-row-label{font-size:.68rem}
  .cfg-card-row-value{font-size:.88rem}
}

/* the style row also carries a small rectangular swatch, no circles */
/* Taken out of the flex row and floated over its right end. As a flex child
   this 42px box set the row's height, so the SERVICE row rendered 56px tall
   against 36px for EVENT, GUESTS and DATE, and the card's ruled rhythm read as
   a mistake in the empty state. The row keeps a constant padding-right the
   width of the swatch, so the leader still stops short of it and nothing jumps
   when a service is picked, which is why the space was reserved in the first
   place. */
.cfg-card-row--style{position:relative;--swatch-w:48px;padding-right:calc(var(--swatch-w) + 12px)}
.cfg-swatch{
  position:absolute;
  right:0;top:50%;
  transform:translateY(-50%);
  width:var(--swatch-w);height:32px;
  overflow:hidden;
  border:1px solid rgba(255,45,149,.4);
  box-shadow:0 1px 6px -3px rgba(0,0,0,.6);
  opacity:0;
  transition:opacity .18s var(--ease);
}
.cfg-card-row--style[data-filled="true"] .cfg-swatch{opacity:1}
/* The 600px bump to 84x56 is gone. At 56px tall the chip was taller than the
   36px row it now lives in and would have straddled the rules above and below
   it. 48x32 keeps the 3:2 crop and sits inside the row, and the width is held
   in --swatch-w so the row's padding-right can never drift away from it, which
   is exactly how the first attempt at this broke: padding sized for the 62px
   chip, chip grown to 84px by a media query, text underneath it. */
.cfg-swatch-img{
  position:absolute;inset:0;width:100%;height:100%;object-fit:cover;
  opacity:0;
}
.cfg-card-row--style[data-style="sweet"] .cfg-swatch-sweet{opacity:1}
.cfg-card-row--style[data-style="savoury"] .cfg-swatch-savoury{opacity:1}
.cfg-card-row--style[data-style="full"] .cfg-swatch-full{opacity:1}

/* fixed fact (the service area), always filled: stacks as its own line
   rather than forcing a long phrase onto one nowrap row */
.cfg-card-row--fixed{
  display:block;
  padding-block:9px;
  border-bottom:0;
}
.cfg-card-row--fixed .cfg-card-row-label{display:block;margin-bottom:3px}
.cfg-card-row--fixed .cfg-card-row-value{
  display:block;
  text-align:left;
  white-space:normal;
  opacity:1;transform:none;transition:none;
  font-size:.78rem;
  color:var(--dim);
}

.cfg-card-desc{
  color:var(--dim);
  font-size:.85rem;
  line-height:1.5;
  min-height:2.6em;
  margin-bottom:16px;
}

/* ---------- reserve ---------- */
.reserve{padding-block:var(--section-pad)}

/* min-width:0 stops the grid min-content blowout: a bare <input> carries an
   intrinsic ~20ch width, and as a grid item .field inherits min-width:auto,
   so at 320 the form pushed the page 3px wide and produced a scrollbar. */
.field{display:flex;flex-direction:column;gap:8px;margin-bottom:20px;min-width:0}
.field label{
  font-size:.76rem;
  letter-spacing:.12em;
  text-transform:uppercase;
  color:var(--muted);
}
.field input,.field textarea,.field select{
  width:100%;
  min-width:0;
  background:var(--ink-2);
  border:1px solid var(--line);
  color:var(--ivory);
  padding:14px 16px;
  font-size:.98rem;
  border-radius:1px;
}
.field select{appearance:none;cursor:pointer}
.field input::placeholder,.field textarea::placeholder{color:rgba(162,148,155,.7)}
.field input:focus-visible,.field textarea:focus-visible,.field select:focus-visible{
  outline:2px solid var(--raspberry-lift);outline-offset:2px;border-color:var(--raspberry-lift);
}
.field textarea{resize:vertical;min-height:120px}
.field-row{display:grid;grid-template-columns:minmax(0,1fr);gap:0}
@media (min-width:600px){
  .field-row{grid-template-columns:minmax(0,1fr) minmax(0,1fr);gap:20px}
  .field-row .field{margin-bottom:20px}
}

/* The reserve form moved onto the ivory sheet when it merged with the
   composer. Everything reading var(--muted) or var(--line) is already remapped
   by .section-ivory; these three rules were hard coded for a dark surface and
   would otherwise be ivory text in an ivory box. */
.section-ivory .field input,
.section-ivory .field textarea,
.section-ivory .field select{
  background:rgba(255,255,255,.62);
  color:var(--ink);
}
.section-ivory .field input::placeholder,
.section-ivory .field textarea::placeholder{color:rgba(122,75,50,.5)}
.section-ivory .field input:focus-visible,
.section-ivory .field textarea:focus-visible,
.section-ivory .field select:focus-visible{
  background:#fff;
  outline-color:var(--raspberry);
  border-color:var(--raspberry);
}

.form-note{
  font-size:.82rem;
  color:var(--muted);
  margin-top:6px;
}
.form-status{
  margin-top:16px;
  font-size:.9rem;
  display:none;
}
.form-status.show{display:block}
.form-status.ok{color:var(--ivory)}
.form-status.err{color:var(--raspberry-lift)}
.section-ivory .form-status.ok{color:var(--ink)}
.section-ivory .form-status.err{color:var(--raspberry)}

/* the Instagram route is a closing line under the one form, not a second
   panel competing with it */
.reserve-side{
  display:flex;
  flex-wrap:wrap;
  align-items:center;
  gap:18px 26px;
  margin-top:clamp(34px,5vw,52px);
  padding-top:clamp(24px,3vw,32px);
  border-top:1px solid var(--line);
}
.reserve-side-text{
  flex:1 1 300px;
  min-width:0;
  color:var(--dim);
  font-size:.92rem;
  line-height:1.6;
}

.consent-note-inline{margin-top:12px}

/* ---------- footer ---------- */
.site-footer{
  padding-block:70px 100px;
  border-top:1px solid var(--line-soft);
}
.footer-top{
  display:flex;flex-direction:column;gap:26px;
  margin-bottom:40px;
}
.footer-brand{display:flex;align-items:center;gap:12px}
.footer-brand img{height:30px;width:auto}
.footer-brand span{font-family:var(--display);font-weight:700;text-transform:uppercase;letter-spacing:.03em}
.footer-links{display:flex;flex-wrap:wrap;gap:22px}
.footer-links a{font-size:.82rem;letter-spacing:.06em;color:var(--muted)}
.footer-links a:hover{color:var(--ivory)}
.footer-bottom{
  display:flex;flex-wrap:wrap;justify-content:space-between;gap:14px;
  padding-top:26px;border-top:1px solid var(--line-soft);
  font-size:.78rem;color:var(--muted);
}
.footer-a11y-controls{display:flex;gap:14px;flex-wrap:wrap}
/* the only two controls on the page that fell under a 44px thumb target */
.footer-a11y-controls button{
  background:transparent;border:1px solid var(--line);
  color:var(--muted);padding:8px 16px;min-height:44px;border-radius:999px;font-size:.72rem;
  letter-spacing:.08em;text-transform:uppercase;cursor:pointer;
}
.footer-a11y-controls button:hover{border-color:var(--ivory);color:var(--ivory)}

@media (min-width:760px){
  .footer-top{flex-direction:row;justify-content:space-between;align-items:center}
}

/* ---------- mobile action bar ---------- */
.mobile-action-bar{display:none}
@media (max-width:759px){
  .mobile-action-bar{
    display:flex;
    gap:10px;
    position:fixed;left:0;right:0;bottom:0;z-index:160;
    padding:12px var(--gutter) calc(12px + env(safe-area-inset-bottom));
    background:rgba(8,6,10,.92);
    backdrop-filter:blur(14px);
    -webkit-backdrop-filter:blur(14px);
    border-top:1px solid var(--line-soft);
    transform:translateY(0);
    transition:transform .3s var(--ease);
  }
  .mobile-action-bar.hide,
  html.consent-open .mobile-action-bar,
  /* the drawer carries its own Reserve button; two of them stacked at the
     foot of an open menu reads as a mistake */
  html.drawer-open .mobile-action-bar{transform:translateY(100%);pointer-events:none}
  .mobile-action-bar .btn{flex:1;padding:14px 16px;font-size:.74rem}
}

/* Visually hidden but present for assistive tech. Used by the panel's live
   region and by the honeypot's label. Never display:none, which would remove it
   from the accessibility tree and silence every announcement. */
.sr-only{
  position:absolute!important;width:1px;height:1px;
  padding:0;margin:-1px;overflow:hidden;
  clip:rect(0 0 0 0);clip-path:inset(50%);white-space:nowrap;border:0;
}

/* The honeypot. Off-screen rather than display:none, because some bots skip
   fields they can tell are not rendered. Paired with aria-hidden and
   tabindex="-1" in the markup so no real user can reach it. */
.hp-field{position:absolute;left:-9999px;width:1px;height:1px;overflow:hidden}

/* Windows High Contrast Mode and any other forced-colours context. The neon
   glows are all box-shadow, which forced-colours discards, so anything relying
   on a glow to show its edge needs a real border to fall back to. The a11y
   panel, consent banner and their controls used to be listed here too; that
   whole implementation now lives in the canonical Krispy Widget, which ships
   its own forced-colours handling. */
@media (forced-colors:active){
  .btn,.neon-frame{border:1px solid CanvasText}
  :focus-visible{outline:3px solid Highlight!important;outline-offset:2px!important}
}

/* ---------- reveals ---------- */
html.js .fade-up{
  opacity:0;
  transform:translateY(28px);
  transition:opacity .8s var(--ease),transform .8s var(--ease);
}
html.js .fade-up.in{
  opacity:1;
  transform:none;
}
@media (prefers-reduced-motion:reduce){
  html.js .fade-up{opacity:1;transform:none;transition:none}
  .mobile-action-bar{transition:none}
  .cfg-card-row-value{transition:none}
  .cfg-swatch{transition:none}
}

/* stagger helpers */
.fade-up.d1{transition-delay:.08s}
.fade-up.d2{transition-delay:.16s}
.fade-up.d3{transition-delay:.24s}

/* ---------- misc ---------- */
.hidden-print,.js-fallback-note{}
noscript.block-note{
  display:block;background:var(--ink-2);border:1px solid var(--line-soft);
  padding:16px 20px;font-size:.85rem;color:var(--muted);margin-bottom:26px;
}

/* =====================================================================
   v4 effects. Everything here is transform/opacity only, GPU friendly,
   and fully disabled under prefers-reduced-motion or the a11y widget's
   motionless switch. None of it changes layout.
   ===================================================================== */

/* --- the walk: RUNWAY rises letter by letter, like a model stepping out --- */
.hero-word .ltr{
  display:inline-block;
  will-change:transform,opacity;
}
html.js .hero-word .ltr{
  opacity:0;
  transform:translateY(.34em) rotate(1.5deg);
}
html.js .hero-word.walked .ltr{
  opacity:1;
  transform:none;
  transition:opacity .7s var(--ease), transform .9s var(--ease);
}
html.js .hero-word.walked .ltr:nth-child(1){transition-delay:.05s}
html.js .hero-word.walked .ltr:nth-child(2){transition-delay:.11s}
html.js .hero-word.walked .ltr:nth-child(3){transition-delay:.17s}
html.js .hero-word.walked .ltr:nth-child(4){transition-delay:.23s}
html.js .hero-word.walked .ltr:nth-child(5){transition-delay:.29s}
html.js .hero-word.walked .ltr:nth-child(6){transition-delay:.35s}
html.js .hero-bites{
  opacity:0;
  transform:translateY(14px) rotate(-3deg);
  transition:opacity .8s var(--ease) .5s, transform .8s var(--ease) .5s;
}
html.js .hero-word.walked ~ .hero-bites,
html.js .hero-runway.walked .hero-bites{
  opacity:1;
  transform:rotate(-3deg);
}

/* --- images wipe up into frame instead of just fading --- */
html.js .wipe img{
  clip-path:inset(16% 0 0 0);
  transition:clip-path 1s var(--ease);
}
html.js .wipe.in img{clip-path:inset(0 0 0 0)}

/* --- parallax drift on the two full-bleed photographic bands --- */
.parallax img{will-change:transform}

/* --- buttons get a little more presence on hover --- */
.btn-primary{box-shadow:0 0 0 0 rgba(200,30,90,0)}
.btn-primary:hover{box-shadow:0 10px 34px -12px rgba(200,30,90,.75)}

@media (prefers-reduced-motion:reduce){
  html.js .hero-word .ltr,
  html.js .hero-bites{opacity:1;transform:none;transition:none}
  html.js .hero-bites{transform:rotate(-3deg)}
  html.js .wipe img{clip-path:none;transition:none}
  .btn-primary:hover{box-shadow:none}
}
html.kw-pause-animations .hero-word .ltr,
html.kw-pause-animations .hero-bites{opacity:1!important;transition:none!important}
html.kw-pause-animations .hero-word .ltr{transform:none!important}
html.kw-pause-animations .wipe img{clip-path:none!important}
html.kw-pause-animations .hero-word{animation:none}



/* =====================================================================
   v11, the live-site absorption pass (2026-08-04)
   The client shipped runwaybites.miami with real event photography, three
   reels, a real logo file, a real menu, real prices and a WhatsApp number.
   Everything below is the layout that content needed. Ordered to match the
   page: brand mark, section heads, reels, service panels, gallery, menu,
   pricing, WhatsApp, footer.
   ===================================================================== */

/* ---------- brand mark ----------
   The typographic lockup was a stand-in for a logo we did not have. We have
   the real one now (640x230 white PNG), so the mark is the mark. Height is
   set and width left auto: setting only one dimension on an element with
   width/height ATTRIBUTES leaves the other at the attribute value and
   distorts the image, which is why the pair is always declared together. */
.brand-mark{
  display:block;
  height:38px;
  width:auto;
}
@media (max-width:480px){ .brand-mark{height:31px} }
.footer-brand img{display:block;height:46px;width:auto}

/* ---------- section heads that carry a lede beside the title ---------- */
.section-head--split{
  max-width:none;
  display:grid;
  gap:clamp(14px,2vw,40px);
  align-items:end;
}
@media (min-width:900px){
  .section-head--split{grid-template-columns:minmax(0,1fr) minmax(0,26rem)}
  .section-head--split .lede{padding-bottom:.4rem}
}

/* ---------- the reels ----------
   Three vertical clips, 9:16, muted, looping, and started only when they
   scroll into view. Re-encoded from the client's own 1080x1920 masters:
   theirs ship at ~9.4 Mbps, which is 43MB of autoplaying video on a phone.
   Ours are 720x1280 at CRF 27, same clips, a quarter of the bytes. */
.reels{padding-block:var(--section-pad)}
.reel-row{
  display:grid;
  gap:clamp(14px,2.4vw,26px);
  grid-template-columns:repeat(auto-fit,minmax(min(240px,100%),1fr));
}
.reel-item{display:flex;flex-direction:column;gap:12px}
.reel-frame{
  position:relative;
  aspect-ratio:9/16;
  background:var(--ink-2);
  border:1px solid var(--line-soft);
  overflow:hidden;
}
.reel-video{
  position:absolute;inset:0;
  width:100%;height:100%;
  object-fit:cover;
  display:block;
}
/* the control is a real button, not a click handler on the video, so the
   clips are operable from the keyboard and announce a label */
.reel-toggle{
  position:absolute;right:12px;bottom:12px;z-index:2;
  width:44px;height:44px;border-radius:50%;
  display:grid;place-items:center;
  background:rgba(8,6,10,.62);
  backdrop-filter:blur(8px);
  -webkit-backdrop-filter:blur(8px);
  border:1px solid rgba(246,241,236,.34);
  color:var(--ivory);
  cursor:pointer;
  transition:border-color .3s var(--ease),background-color .3s var(--ease);
}
.reel-toggle:hover{border-color:var(--ivory);background:rgba(8,6,10,.8)}
.reel-toggle svg{width:17px;height:17px;fill:currentColor;stroke:currentColor;stroke-width:1.9}
.reel-toggle .reel-icon-play{display:none;stroke:none;margin-left:2px}
.reel-toggle[aria-pressed="true"] .reel-icon-pause{display:none}
.reel-toggle[aria-pressed="true"] .reel-icon-play{display:block}
.reel-caption{font-size:.82rem;color:var(--muted);max-width:34ch}

/* ---------- the gallery ----------
   True-aspect masonry. The live site declares width="1066" height="1600" on
   every single frame including the landscapes, so its wide shots render
   squeezed into a portrait box. Here each <img> carries its own real
   dimensions and is sized width:100%/height:auto, so nothing is distorted
   and nothing is cropped. CSS columns rather than grid: with 29 photographs
   at three different ratios, a column flow packs them with no gaps and no
   per-item row-span arithmetic. */
.gallery{padding-block:var(--section-pad)}
.gal-mosaic{
  columns:2;
  column-gap:clamp(8px,1.4vw,16px);
  margin-top:clamp(10px,2vw,24px);
}
@media (min-width:700px){ .gal-mosaic{columns:3} }
@media (min-width:1100px){ .gal-mosaic{columns:4} }

.gal-item{
  break-inside:avoid;
  margin-bottom:clamp(8px,1.4vw,16px);
  position:relative;
  background:var(--ink-2);
  overflow:hidden;
  cursor:zoom-in;
}
.gal-item img{
  display:block;
  width:100%;
  height:auto;              /* the pair that keeps the real aspect ratio */
  filter:brightness(.92) saturate(1.03);
  transition:transform .7s var(--ease),filter .5s var(--ease);
}
/* a neon hairline rather than the full neon-frame recipe: 29 tiles at the
   frame's full glow radius reads as a muddy pink wall, so the border is the
   same hot pink but the glow is a fraction of the strength used on the
   hero, the service rows and the pricing tiers. */
.gal-item::after{
  content:'';
  position:absolute;inset:0;
  border:1px solid rgba(255,45,149,.5);
  box-shadow:inset 0 0 0 1px rgba(255,45,149,.12);
  pointer-events:none;
  transition:border-color .3s var(--ease),box-shadow .3s var(--ease);
}
@media (hover:hover) and (pointer:fine){
  .gal-item:hover img{transform:scale(1.05);filter:brightness(1) saturate(1.08)}
  .gal-item:hover::after{
    border-color:var(--hot);
    box-shadow:0 0 12px rgba(255,45,149,.45);
  }
}
@media (prefers-reduced-motion:reduce){
  .gal-item img{transition:none}
}
html.kw-pause-animations .gal-item img{transition:none}

.gal-more{display:none}
.gal-mosaic.expanded .gal-more{display:block}
.gal-more-wrap{display:flex;justify-content:center;margin-top:clamp(22px,3vw,38px)}

/* ---------- lightbox ---------- */
.lightbox{
  position:fixed;inset:0;z-index:300;
  display:grid;
  grid-template-columns:auto minmax(0,1fr) auto;
  align-items:center;
  gap:clamp(4px,1.4vw,20px);
  padding:clamp(52px,7vh,80px) clamp(8px,2vw,32px) clamp(48px,6vh,64px);
  background:rgba(6,4,7,.95);
  backdrop-filter:blur(10px);
  -webkit-backdrop-filter:blur(10px);
}
.lightbox[hidden]{display:none}
.lb-stage{
  min-width:0;
  height:100%;
  display:flex;flex-direction:column;
  align-items:center;justify-content:center;
  gap:14px;
}
.lb-stage img{
  max-width:100%;
  /* a percentage max-height inside a flex item never resolves, so the image
     renders full size and reads as cropped. Capped against the viewport. */
  max-height:calc(100dvh - 190px);
  width:auto;height:auto;
  object-fit:contain;
  background:var(--ink-2);
}
.lb-stage figcaption{
  font-size:.82rem;
  color:var(--muted);
  text-align:center;
  max-width:56ch;
  line-height:1.5;
}
.lb-close,.lb-nav{
  width:46px;height:46px;
  min-width:46px;
  border-radius:50%;
  display:grid;place-items:center;
  background:rgba(18,13,18,.9);
  border:1px solid var(--line);
  color:var(--ivory);
  cursor:pointer;
  transition:border-color .3s var(--ease);
}
.lb-close:hover,.lb-nav:hover{border-color:var(--raspberry-lift)}
.lb-close svg,.lb-nav svg{width:19px;height:19px;fill:none;stroke:currentColor;stroke-width:1.7}
.lb-close{position:absolute;top:14px;right:14px;z-index:2}
.lb-count{
  position:absolute;left:0;right:0;bottom:18px;
  text-align:center;
  font-size:.7rem;letter-spacing:.22em;text-transform:uppercase;
  color:var(--muted);
  max-width:none;
}
@media (max-width:600px){
  .lb-nav{position:absolute;bottom:52px;z-index:2}
  .lb-prev{left:16px}
  .lb-next{right:16px}
  .lightbox{grid-template-columns:minmax(0,1fr)}
  .lb-stage{grid-column:1}
  .lb-stage img{max-height:calc(100dvh - 210px)}
}
html.lightbox-open,html.lightbox-open body{overflow:hidden}

/* ---------- price dialog ----------
   Same backdrop treatment as the lightbox so the two modals on this page read
   as one mechanism. The panel scrolls internally rather than the page behind
   it, which is what keeps a long body on a 320 wide phone reachable while
   html stays locked. */
.price-modal{
  position:fixed;inset:0;z-index:320;
  display:grid;place-items:center;
  padding:clamp(16px,4vw,40px);
  background:rgba(6,4,7,.95);
  backdrop-filter:blur(10px);
  -webkit-backdrop-filter:blur(10px);
}
.price-modal[hidden]{display:none}
.pm-panel{
  position:relative;
  width:min(38rem,100%);
  max-height:calc(100dvh - clamp(32px,8vw,80px));
  overflow-y:auto;
  background:var(--ink-2);
  border:1.5px solid var(--hot);
  box-shadow:0 0 0 1px rgba(255,45,149,.3),0 0 40px rgba(255,45,149,.35);
  padding:clamp(26px,4vw,44px);
}
/* the ask-us card opens the same dialog, so the frame follows the card that
   opened it rather than always shouting the rate colour */
.price-modal[data-variant="ask"] .pm-panel{
  border-color:var(--cyan);
  box-shadow:0 0 0 1px rgba(0,233,242,.28),0 0 40px rgba(0,233,242,.28);
}
.price-modal[data-variant="ask"] .pm-eyebrow{color:var(--cyan);margin-bottom:6px}
/* the inclusion list is the FULL cart's contents. The scaled down version has
   not been specced by the client, so listing them here would be inventing the
   package. Hidden rather than reworded. */
.price-modal[data-variant="ask"] .pm-list{display:none}
.price-modal[data-variant="ask"] .pm-title{color:var(--cyan)}
/* the hidden list took its own top rule with it, so the actions pick it up */
.price-modal[data-variant="ask"] .pm-actions{
  border-top:1px solid var(--line);
  padding-top:20px;margin-top:20px;
}
.pm-close{
  position:absolute;top:12px;right:12px;
  width:42px;height:42px;
  border-radius:50%;
  display:grid;place-items:center;
  background:rgba(18,13,18,.9);
  border:1px solid var(--line);
  color:var(--ivory);
  cursor:pointer;
  transition:border-color .3s var(--ease);
}
.pm-close:hover{border-color:var(--hot)}
.pm-close svg{width:18px;height:18px;fill:none;stroke:currentColor;stroke-width:1.7}
.pm-eyebrow{
  font-size:.7rem;letter-spacing:.22em;text-transform:uppercase;
  color:var(--hot);
  padding-right:44px;
}
.pm-figure{
  font-family:var(--display);
  font-weight:800;
  font-size:clamp(2.6rem,7vw,4rem);
  line-height:1;
  color:#fff;
  margin:.35rem 0 .1rem;
  text-shadow:0 0 8px rgba(255,45,149,.75),0 0 28px rgba(255,45,149,.45);
}
.pm-figure[hidden]{display:none}
/* "Quoted for you" is four words in a slot sized for four characters */
.pm-figure[data-small="true"]{font-size:clamp(1.6rem,4vw,2.2rem);line-height:1.15}
.pm-title{
  font-family:var(--sans);
  font-size:.78rem;letter-spacing:.2em;text-transform:uppercase;
  font-weight:600;
  color:var(--dim);
  margin-bottom:14px;
}
.pm-body{color:var(--dim);font-size:.95rem;margin-bottom:14px}
.pm-alt{
  border-left:2px solid var(--cyan);
  padding:2px 0 2px 14px;
  color:var(--ivory);
  font-size:.88rem;
  margin-bottom:16px;
}
.pm-alt[hidden]{display:none}
.pm-list{
  border-top:1px solid var(--line);
  padding-top:16px;
  display:grid;gap:8px;
  margin-bottom:22px;
}
.pm-list li{
  font-size:.86rem;color:var(--dim);
  padding-left:18px;position:relative;
}
.pm-list li::before{
  content:'';position:absolute;left:0;top:.62em;
  width:8px;height:2px;background:var(--hot);
}
.pm-actions{display:flex;flex-wrap:wrap;gap:10px;align-items:center}
html.price-modal-open,html.price-modal-open body{overflow:hidden}
/* #reserve is focused programmatically, never tabbed to, so the ring it would
   draw around the whole section is noise */
[tabindex="-1"]:focus{outline:none}

/* ---------- the menu ----------
   The biggest elegance offender: ivory paper stock, ink type. Converted to
   the void ground with surface cards, per the brief. No .section-ivory
   class on this section any more, so it already shows the body's own void
   background and grain; everything below only had to stop assuming ink
   text on a light card. Category headings cycle hot, cyan and violet three
   at a time (three colors down nine cards, never adjacent repeats) rather
   than every heading carrying the same glow, which is the "more colors"
   half of the brief and not just "more pink". */
/* align-items:start, because these cards hold wildly different item counts.
   Charcuterie Crisp has three lines and Curated Cheese has seven, and a grid
   row stretches every card to the tallest, so the short ones carried ~140px
   of empty space inside a visible border. Each card is now its own height. */
/* This section had NO section padding at all. It used to carry .section-ivory,
   which is where its padding-block came from, and v12 dropped that class when
   it converted the menu from ivory paper to the dark ground without giving the
   padding a new home. Every other section declares the token on its own class.
   Measured before the fix: 92px of clear space between the menu and each of
   its neighbours, against 212 to 240px at every other section boundary. */
.menu{padding-block:var(--section-pad)}

.menu-grid{
  display:grid;
  align-items:start;
  gap:clamp(12px,1.8vw,22px);
  grid-template-columns:repeat(auto-fit,minmax(min(240px,100%),1fr));
}
/* nine categories. auto-fit resolved to four columns at desktop, which left
   Spread stranded alone on a third row. Three columns divides nine exactly
   and gives each list more room. */
@media (min-width:1000px){
  .menu-grid{grid-template-columns:repeat(3,minmax(0,1fr))}
}
.menu-card{
  border:1px solid var(--line);
  background:var(--surface);
  padding:clamp(18px,2.2vw,26px);
  display:flex;flex-direction:column;gap:4px;
}
.menu-card :is(h2,h3){
  font-family:var(--display);
  font-size:1.22rem;
  line-height:1.15;
  text-transform:uppercase;
  letter-spacing:.02em;
  color:#fff;
  text-shadow:0 0 6px rgba(255,45,149,.9),0 0 22px rgba(255,45,149,.55);
}
.menu-card:nth-of-type(3n+2) :is(h2,h3){text-shadow:0 0 6px rgba(0,233,242,.9),0 0 22px rgba(0,233,242,.55)}
.menu-card:nth-of-type(3n) :is(h2,h3){text-shadow:0 0 6px rgba(157,78,221,.9),0 0 22px rgba(157,78,221,.55)}
.menu-note{
  font-size:.76rem;
  font-style:italic;
  color:var(--muted);
  margin-bottom:10px;
}
.menu-card ul{display:flex;flex-direction:column;gap:5px}
.menu-card li{
  font-size:.88rem;
  color:var(--ivory);
  padding-left:15px;
  position:relative;
}
.menu-card li::before{
  content:'';position:absolute;left:0;top:.6em;
  width:6px;height:2px;background:var(--hot);
}

/* ---------- vegan collection ---------- */
/* A full parallel menu with seven categories, not an aside, so it reuses the
   .menu-card system rather than the single framed panel .menu-kids uses. It
   is separated from the main grid the way .dietary is, by a rule and the same
   64px interval every other block in this section sits at.
   --lime is the one accent the v12 brief defined and never spent, so it marks
   this as its own collection without inventing a colour. */
.menu-vegan{
  margin-top:clamp(34px,5vw,64px);
  border-top:1px solid var(--line);
  padding-top:clamp(24px,3.4vw,40px);
}
.menu-vegan-head{max-width:46rem;margin-bottom:clamp(16px,2.4vw,28px)}
.menu-vegan-head .eyebrow.accent{color:var(--lime)}
.menu-vegan-head .eyebrow-bar::after{
  background:var(--lime);
  box-shadow:0 0 8px var(--lime),0 0 20px rgba(204,255,51,.5);
}
.menu-vegan-head :is(h2,h3){
  font-family:var(--display);
  font-size:clamp(1.5rem,3vw,2.2rem);
  line-height:1.12;
  text-transform:uppercase;
  margin:.4rem 0 .6rem;
  color:#fff;
}
.menu-vegan-head p{color:var(--dim);max-width:52ch}

/* Seven cards. The auto-fit track count .menu-grid resolves to would strand
   one card alone on the last row at 3 columns AND at 2, which is the exact
   defect the three-column override above was written to fix for nine. Tracks
   are pinned to 4 and 2 and the last card spans two of them, so every row
   above the single-column stack is exactly full. */
.menu-vegan-grid{
  display:grid;
  align-items:start;
  gap:clamp(12px,1.8vw,22px);
}
@media (min-width:620px){
  .menu-vegan-grid{grid-template-columns:repeat(2,minmax(0,1fr))}
  .menu-vegan-grid>.menu-card:last-child{grid-column:span 2}
  .menu-vegan-grid>.menu-card:last-child ul{
    display:grid;
    grid-template-columns:repeat(2,minmax(0,1fr));
    gap:5px 18px;
  }
}
@media (min-width:1000px){
  .menu-vegan-grid{grid-template-columns:repeat(4,minmax(0,1fr))}
}
.menu-vegan-grid .menu-card{border-color:rgba(204,255,51,.28)}
.menu-vegan-grid .menu-card li::before{background:var(--lime)}
/* the hot/cyan/violet rotation on .menu-card headings is :nth-of-type, which
   restarts inside this grid and would repaint the collection in three colours.
   Specificity is raised to 0,3,1 on purpose: a 0,2,1 tie decided by source
   order is one edit away from silently flipping back. */
.menu-vegan .menu-vegan-grid .menu-card :is(h2,h3){
  text-shadow:0 0 6px rgba(204,255,51,.9),0 0 22px rgba(204,255,51,.55);
}

.menu-kids{
  /* was clamp(18px,2.4vw,28px), which put 28px between the grid and this block
     while .menu-extras and .dietary below it both sit at 64px. Matched to them
     so the section has one interval, not three. */
  margin-top:clamp(34px,5vw,64px);
  border:1.5px solid var(--hot);
  box-shadow:0 0 0 1px rgba(255,45,149,.22),0 0 18px rgba(255,45,149,.32);
  background:rgba(255,45,149,.06);
  padding:clamp(22px,3vw,34px);
  display:grid;
  gap:clamp(16px,2.4vw,34px);
}
@media (min-width:860px){
  .menu-kids{grid-template-columns:minmax(0,22rem) minmax(0,1fr);align-items:start}
}
.menu-kids-head :is(h2,h3){
  font-family:var(--display);
  font-size:clamp(1.4rem,2.4vw,1.9rem);
  line-height:1.12;
  text-transform:uppercase;
  margin:.4rem 0 .6rem;
  color:#fff;
}
.menu-kids-head p{font-size:.9rem;color:var(--dim);max-width:38ch}
.menu-kids-list{
  display:grid;
  grid-template-columns:repeat(auto-fit,minmax(min(150px,100%),1fr));
  gap:7px 18px;
  align-content:start;
}
.menu-kids-list li{
  font-size:.88rem;color:var(--ivory);
  padding-left:15px;position:relative;
}
.menu-kids-list li::before{
  content:'';position:absolute;left:0;top:.6em;
  width:6px;height:2px;background:var(--hot);
}

.menu-extras{margin-top:clamp(34px,5vw,64px)}
.menu-extras-head{max-width:46rem;margin-bottom:clamp(16px,2.4vw,28px)}
.menu-extras-head :is(h2,h3){
  font-family:var(--display);
  font-size:clamp(1.5rem,3vw,2.2rem);
  line-height:1.12;
  text-transform:uppercase;
  margin:.4rem 0 .6rem;
  color:#fff;
}
.menu-extras-head p{color:var(--dim);max-width:52ch}
/* .extras-row and .extra are gone: the four blocks under "Beyond meat and
   cheese" were removed 2026-08-08 and nothing else used those classes.
   .menu-extras-head now has no margin-bottom to earn, so it is zeroed when
   it is the block's only child. */
.menu-extras-head:only-child{margin-bottom:0}

.dietary{
  margin-top:clamp(34px,5vw,64px);
  border-top:1px solid var(--line);
  padding-top:clamp(24px,3.4vw,40px);
  display:grid;
  gap:clamp(16px,2.6vw,40px);
  align-items:center;
}
@media (min-width:900px){
  .dietary{grid-template-columns:minmax(0,1fr) minmax(0,24rem)}
}
.dietary :is(h2,h3){
  font-family:var(--display);
  font-size:clamp(1.4rem,2.6vw,2rem);
  line-height:1.12;
  text-transform:uppercase;
  margin:.4rem 0 .6rem;
  color:#fff;
}
.dietary p{color:var(--dim);max-width:50ch}
.diet-tags{display:flex;flex-wrap:wrap;gap:9px}
.diet-tags li{
  font-size:.74rem;letter-spacing:.14em;text-transform:uppercase;
  border:1px solid var(--cyan);
  color:var(--cyan);
  border-radius:999px;
  padding:9px 16px;
}

/* ---------- pricing ---------- */
.pricing{padding-block:var(--section-pad)}
.price-row{
  display:grid;
  gap:clamp(10px,1.4vw,16px);
  grid-template-columns:repeat(auto-fit,minmax(min(200px,100%),1fr));
  margin-top:clamp(10px,2vw,20px);
}
/* Every tier is a <button> now, so the reset has to be explicit: a bare
   <button> inherits neither the page font nor left alignment, and Windows
   gives it a buttonface grey ground the moment background is left unset.
   The guest count carries the card where the dollar figure used to, which
   keeps this section on the same numeral motif as the rest of the page. */
.price-tier{
  width:100%;
  font-family:inherit;
  text-align:left;
  border:1.5px solid var(--hot);
  border-radius:0;
  box-shadow:0 0 0 1px rgba(255,45,149,.22),0 0 18px rgba(255,45,149,.16);
  background:var(--ink-2);
  color:inherit;
  padding:clamp(20px,2.4vw,28px);
  display:flex;flex-direction:column;gap:6px;
  height:100%;
  cursor:pointer;
  transition:box-shadow .35s var(--ease),transform .5s var(--ease);
}
.price-row > li{display:flex}
@media (hover:hover) and (pointer:fine){
  .price-tier:hover{box-shadow:0 0 0 1px rgba(255,45,149,.3),0 0 24px rgba(255,45,149,.4);transform:translateY(-3px)}
  .price-tier:hover .price-reveal{color:#fff}
  .price-tier:hover .price-reveal svg{transform:translateX(4px)}
}
.price-tier:focus-visible{outline:2px solid var(--cyan);outline-offset:3px}
.price-tier.is-featured{
  box-shadow:0 0 0 1px rgba(255,45,149,.4),0 0 30px rgba(255,45,149,.5);
  background:linear-gradient(180deg,rgba(255,45,149,.14),rgba(15,11,24,.94));
}
.price-count{
  font-family:var(--display);
  font-weight:700;
  font-size:clamp(1.8rem,3.2vw,2.5rem);
  line-height:1;
  color:#fff;
  letter-spacing:-.01em;
}
.price-tier.is-featured .price-count{
  text-shadow:0 0 6px rgba(255,45,149,.9),0 0 22px rgba(255,45,149,.55);
}
/* "Smaller" is a word, not a numeral, so it needs to come down a step or it
   sets the row's line height on its own at narrow widths */
.price-count--word{font-size:clamp(1.5rem,2.6vw,2rem)}
.price-unit{
  font-size:.7rem;letter-spacing:.2em;text-transform:uppercase;
  color:var(--hot);
}
.price-note{font-size:.82rem;color:var(--muted);max-width:26ch;margin-top:4px}
/* pushed to the foot of the card so the six affordances line up across the
   row however tall each note runs */
.price-reveal{
  margin-top:auto;padding-top:14px;
  display:inline-flex;align-items:center;gap:7px;
  font-size:.72rem;letter-spacing:.16em;text-transform:uppercase;
  font-weight:600;
  color:var(--hot);
  transition:color .3s var(--ease);
}
.price-reveal svg{width:16px;height:16px;transition:transform .3s var(--ease)}

/* the smaller celebration band. Cyan, not hot pink, because it is not one of
   the five published rates: it is the ask-us route, and the colour is what
   says so before the copy does. It sits below the row rather than inside it,
   full width, so five rates read as a set and this reads as the alternative. */
/* 16px here read as a rendering accident next to the 48px below the band.
   Still tighter than that 48 on purpose: the band is the alternative to the
   five rates, so it should group with them rather than float free. */
.price-ask{margin-top:clamp(16px,2.2vw,26px)}
.price-tier--ask{
  border-color:var(--cyan);
  box-shadow:0 0 0 1px rgba(0,233,242,.18),0 0 18px rgba(0,233,242,.14);
}
@media (hover:hover) and (pointer:fine){
  .price-tier--ask:hover{box-shadow:0 0 0 1px rgba(0,233,242,.28),0 0 24px rgba(0,233,242,.34)}
}
.price-tier--ask .price-unit,
.price-tier--ask .price-reveal{color:var(--cyan)}
/* wide enough to lay out sideways: label stacked left, the promise across the
   middle, the affordance right. Below this it stays the stacked card the five
   tiers are, because a three column band at 600px is three cramped columns. */
@media (min-width:760px){
  .price-tier--ask{
    display:grid;
    grid-template-columns:minmax(0,auto) minmax(0,1fr) auto;
    grid-template-rows:auto auto;
    column-gap:clamp(20px,3.4vw,48px);
    row-gap:2px;
  }
  .price-tier--ask .price-count{grid-column:1;grid-row:1;align-self:end}
  .price-tier--ask .price-unit{grid-column:1;grid-row:2;align-self:start}
  .price-tier--ask .price-note{
    grid-column:2;grid-row:1/3;align-self:center;
    margin-top:0;max-width:48ch;
  }
  .price-tier--ask .price-reveal{
    grid-column:3;grid-row:1/3;align-self:center;
    margin-top:0;padding-top:0;
  }
}

.price-included{
  margin-top:clamp(26px,3.6vw,48px);
  border-top:1px solid var(--line);
  padding-top:clamp(20px,2.8vw,34px);
}
.price-included :is(h2,h3){
  font-family:var(--sans);
  font-size:.78rem;letter-spacing:.2em;text-transform:uppercase;
  font-weight:600;
  color:var(--raspberry-lift);
  margin-bottom:16px;
}
.price-included ul{
  display:grid;
  gap:10px clamp(18px,3vw,44px);
  grid-template-columns:repeat(auto-fit,minmax(min(260px,100%),1fr));
  margin-bottom:18px;
}
.price-included li{
  font-size:.9rem;
  padding-left:18px;position:relative;
}
.price-included li::before{
  content:'';position:absolute;left:0;top:.65em;
  width:8px;height:2px;background:var(--raspberry-lift);
}

/* ---------- WhatsApp ----------
   WhatsApp is the client's real channel: it is how the number on their own
   site routes, and the reserve form composes into it rather than posting to
   a form service they would have to check. Brand green, not raspberry, so it
   reads as the channel it is.

   2026-08-08: the green was 1F-A8-55, which puts white text at 3.09:1, under
   the 4.5 floor for a 13px label, on the form's primary submit. Deepened one
   shade to the #14833F below, measured at 4.83:1. Still unmistakably WhatsApp
   green, so the reason the button is green at all survives. The old hover,
   17-8F-47, is only 4.15:1 and was not enough on its own. Hexes written with
   separators here so a future find-and-replace on the live values does not
   silently rewrite this note, which is exactly what happened when it landed. */
.btn-wa{
  background:#14833F;
  color:#FFFFFF;
  border-color:#14833F;
}
.btn-wa:hover{background:#107436;border-color:#107436}
.btn-wa svg{flex:0 0 auto}

.wa-float{
  position:fixed;
  right:16px;
  bottom:calc(16px + var(--mbar-clear));
  z-index:140;
  width:54px;height:54px;
  border-radius:50%;
  display:grid;place-items:center;
  background:#14833F;
  color:#FFFFFF;
  box-shadow:0 10px 30px rgba(0,0,0,.42);
  transition:transform .4s var(--ease),background-color .3s var(--ease);
}
.wa-float:hover{background:#107436;transform:translateY(-3px)}
@media (min-width:900px){
  .wa-float{bottom:22px;right:22px}
}
/* the a11y trigger sits bottom-left, the consent banner takes the full
   width while it is up, and the drawer covers everything: the float stands
   down for both rather than floating over them */
html.consent-open .wa-float,
html.drawer-open .wa-float{opacity:0;pointer-events:none}
.wa-float{transition:opacity .3s var(--ease),transform .4s var(--ease),background-color .3s var(--ease)}

/* ---------- reserve, the WhatsApp submit ---------- */
.rf-submit{width:100%;margin-top:6px}
.form-note{
  font-size:.8rem;
  color:var(--muted);
  margin-top:12px;
  max-width:44ch;
}
.section-ivory .form-note{color:var(--walnut)}
.form-note a{color:var(--hot);border-bottom:1px solid rgba(255,45,149,.4)}
.reserve-side-actions{display:flex;flex-wrap:wrap;gap:10px}

/* the swatch previews the services. Boxes dropped 2026-08-08, not offered yet */
.cfg-card-row--style[data-service="Grazing Table"] .cfg-swatch-table{opacity:1}

/* ---------- footer additions ---------- */
.footer-contact{
  display:flex;flex-wrap:wrap;
  gap:8px clamp(18px,3vw,36px);
  align-items:center;
  margin-bottom:18px;
}
.footer-contact a,.footer-contact span{
  font-size:.9rem;
  color:var(--ivory);
}
.footer-contact a:hover{color:var(--raspberry-lift)}
.footer-social{
  display:flex;flex-wrap:wrap;
  gap:8px clamp(14px,2.4vw,28px);
  margin-bottom:26px;
}
.footer-social a{
  font-size:.72rem;letter-spacing:.2em;text-transform:uppercase;
  color:var(--muted);
}
.footer-social a:hover{color:var(--raspberry-lift)}

/* ---------- touch targets ----------
   Measured at 390: the footer nav, the social row, the contact row and the
   header brand link were all between 18 and 31px high. Standalone navigation
   controls, so they get a real 44px target. Inline links inside running copy
   are deliberately left alone: they are exempt, and padding them out would
   break the line box they sit in. */
.footer-links a,
.footer-social a,
.footer-contact a{
  display:inline-flex;
  align-items:center;
  min-height:44px;
}
.brand-lockup{min-height:44px;align-items:center}
.footer-brand{display:inline-flex;align-items:center;min-height:44px}

/* ---------- multipage: page hero + page cta ----------
   Added 2026-08-09 when services, gallery, menu and pricing moved off the
   home page onto their own pages. The header is position:fixed at 72px, so
   every new page opens with .page-hero to clear it before the moved
   section's own content starts, the same way .hero already does. */
.page-hero{
  padding-block:calc(72px + var(--section-pad)) calc(var(--section-pad) * .5);
  background-color:var(--void);
}
@media (max-width:759px){
  .page-hero{padding-block:calc(72px + 20px) 40px}
}

/* the moved section already opens with its own padding-block:var(--section-pad);
   stacking .page-hero's bottom pad on top of that doubled the gap under the
   fixed header on every new page */
.page-hero + section{padding-top:0}

.page-cta{
  padding-block:var(--section-pad);
  text-align:center;
  background-color:var(--void);
}
.page-cta-actions{
  display:flex;
  flex-wrap:wrap;
  justify-content:center;
  gap:.75rem;
  margin-top:1.5rem;
}

/* the home page pricing band replaces the five rate cards with a short pitch,
   so its section-head is centred rather than left aligned like every other
   section-head on the site */
.pricing-teaser .section-head{
  text-align:center;
  margin-inline:auto;
}

/* CENTRING, the part that text-align does not do.
   .lede caps at 52ch and every p caps at 60ch. A block narrower than its
   parent does NOT centre just because the parent centres its TEXT: the text
   centres inside the block, and the block stays flush left. That is why the
   sub text under "Reserve your date" sat 264px left of centre on all four
   new pages while the heading above it and the buttons below it were centred,
   which reads as broken rather than as a near miss.
   Scoped to the two centred contexts on the site and applied to every child,
   so adding a constrained element to either one cannot reintroduce it. */
.page-cta > .wrap > *,
.pricing-teaser .section-head > *{
  margin-inline:auto;
}
