/* VIP Liaison v1 — Design System
   Shared tokens, type scale, spacing, and base component styles.
   No page-specific rules live in this file. */

:root {
  /* Color tokens */
  --canvas: #0a0908;
  --canvas-deep: #050403;
  --surface: #14110d;
  --text-warm: #efe6d8;
  --text-muted: rgba(239, 230, 216, .62);
  --text-faint: rgba(239, 230, 216, .38);
  --bronze: #b28a54;
  --bronze-soft: rgba(178, 138, 84, .35);
  --hairline: rgba(239, 230, 216, .10);
  /* The hero's night sky, sampled from the top edge of vip-hero-v1: the
     dark title block on phones continues it so the two join seamlessly. */
  --sky: #040912;
  /* All services numerals: champagne (light: espresso, below). */
  --numeral: #c7b69f;

  /* Spacing (8px base) */
  --space-1: 8px;
  --space-2: 16px;
  --space-3: 24px;
  --space-4: 32px;
  --space-6: 48px;
  --space-9: 72px;
  --space-12: 96px;

  /* Layout */
  --container-max: 640px;
  --container-pad: 24px;
  --card-pad: 24px;

  /* Radius — flat, everywhere */
  --radius: 2px;

  /* Controls */
  --control-min-height: 48px;
  --action-min-width: 160px;
  --focus-outline-width: 2px;

  /* Motion */
  --motion-rope: 400ms;
  --motion-hover: 150ms;
  --motion-sheet: 200ms;

  --font-heading: 'Spectral', Georgia, 'Times New Roman', serif;
  --font-body: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
}

/* Fonts — self-hosted woff2, same origin only, zero external requests at
   runtime. Sourced from each family's official open-font-license
   repository (see the LICENSE-*.txt files alongside them): Spectral from
   github.com/productiontype/Spectral (fonts/webfonts/), Inter from
   github.com/rsms/inter (docs/font-files/). Both SIL OFL 1.1.
   Spectral 300 is now provided (spectral-light.woff2, same source),
   so .vl-rope and .vl-title render at their originally-designed light
   weight again. No Inter text anywhere uses font-weight: 300 — every
   font-weight: 300 declaration in this file is on font-family:
   var(--font-heading) (Spectral), none on var(--font-body) (Inter) —
   so Inter 300 was not sourced. */
@font-face {
  font-family: 'Spectral';
  src: url('fonts/spectral-light.woff2') format('woff2');
  font-weight: 300;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: 'Spectral';
  src: url('fonts/spectral-regular.woff2') format('woff2');
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: 'Spectral';
  src: url('fonts/spectral-medium.woff2') format('woff2');
  font-weight: 500;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: 'Inter';
  src: url('fonts/inter-regular.woff2') format('woff2');
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: 'Inter';
  src: url('fonts/inter-medium.woff2') format('woff2');
  font-weight: 500;
  font-style: normal;
  font-display: swap;
}

/* Reset */
*, *::before, *::after {
  box-sizing: border-box;
}

html, body {
  margin: 0;
  padding: 0;
}

/* Only the five self-hosted faces ever render: Spectral 300/400/500 and
   Inter 400/500. font-synthesis: none stops the browser faking a bold
   or an italic from them — <strong> resolves to the 500 face instead
   (see the strong rule below). */
html {
  font-synthesis: none;
  -webkit-text-size-adjust: 100%;
  text-size-adjust: 100%;
}

body {
  background: var(--canvas);
  color: var(--text-warm);
  font-family: var(--font-body);
  font-size: 17px;
  line-height: 1.5;
  font-weight: 400;
  font-kerning: normal;
  text-rendering: optimizeLegibility;
}

strong, b {
  font-weight: 500;
}

a, button, input, textarea, select {
  font: inherit;
  color: inherit;
}

a {
  text-decoration: none;
}

::selection {
  background: var(--bronze-soft);
  color: var(--text-warm);
}

/* Type scale — clamp()-based, mobile-first, resolving at the single
   480px breakpoint */
/* Rope: one line of Spectral Light wherever it fits. The previous
   15vw-8px curve reached 50px at 390px wide and broke "The VIP Liaison"
   onto two lines on every phone; 10.5vw resolves to 41px there (one
   line, measured) and still reaches the 64px cap from 610px up. A hair
   of negative tracking keeps the light face from looking loose at
   display sizes. */
.vl-rope {
  margin: 0;
  font-family: var(--font-heading);
  font-weight: 300;
  font-size: clamp(38px, 10.5vw, 64px);
  line-height: 1.08;
  letter-spacing: -0.01em;
  color: var(--text-warm);
  transition: opacity var(--motion-rope) ease, transform var(--motion-rope) ease;
}

.vl-title {
  margin: 0;
  font-family: var(--font-heading);
  font-weight: 300;
  font-size: clamp(34px, calc(6.25vw + 14px), 44px);
  line-height: 1.15;
  letter-spacing: -0.005em;
  text-wrap: balance;
  color: var(--text-warm);
}

.vl-section-head {
  margin: 0;
  font-family: var(--font-heading);
  font-weight: 400;
  font-size: clamp(24px, calc(2.5vw + 16px), 28px);
  line-height: 1.2;
  text-wrap: balance;
  color: var(--text-warm);
}

.vl-body {
  margin: 0;
  font-family: var(--font-body);
  font-weight: 400;
  font-size: 17px;
  line-height: 1.5;
  text-wrap: pretty;
  color: var(--text-warm);
}

.vl-label {
  margin: 0;
  font-family: var(--font-body);
  font-weight: 500;
  font-size: 12px;
  line-height: 1.4;
  text-transform: uppercase;
  letter-spacing: 0.10em;
  color: var(--bronze);
}

.vl-venue {
  margin: 0;
  font-family: var(--font-body);
  font-weight: 400;
  font-size: 15px;
  line-height: 1.45;
  text-wrap: pretty;
  color: var(--text-muted);
}

/* Lists (What this covers, Privacy Facts): a quieter marker in the
   faint text tone, indent pulled in to the type's own em so the list
   sits on the same left edge as the paragraphs around it. */
.vl-container ul,
.vl-privacy ul {
  margin-block-end: 0;
  padding-inline-start: 1.15em;
}

.vl-container li::marker,
.vl-privacy li::marker {
  color: var(--text-faint);
}

/* Layout */
.vl-container {
  max-width: var(--container-max);
  margin-inline: auto;
  padding-inline: var(--container-pad);
}

.vl-section {
  padding-block: var(--space-9);
}

@media (min-width: 480px) {
  .vl-section {
    padding-block: var(--space-12);
  }
}

/* Hairline */
.vl-hairline {
  border: none;
  border-top: 1px solid var(--hairline);
  margin: 0;
}

/* ---------------------------------------------------------------------
   Vertical rhythm (screenshot-review pass) — every stacked block gets
   space above it via its own margin-top, using only the existing 8px
   spacing scale (no new values). A block's FIRST occurrence in a
   section never carries a stray top margin, since margin-top only ever
   applies to a block that follows a sibling (owl selector, `* + *`).
   General rule first, more specific overrides after (all higher
   specificity, so cascade order here doesn't matter to the result). */
.vl-container > * + *,
.vl-card > * + * {
  margin-top: var(--space-3);
}

/* Kicker label tight against its heading, in either order (rope/
   concierge: h1 then label; family pages: label then h1). */
.vl-container > h1 + .vl-label,
.vl-container > .vl-label + h1 {
  margin-top: var(--space-1);
}

/* A new section (What this covers / FAQ) gets more clearance above it
   than a plain paragraph-to-paragraph gap, and a hairline rule so the
   page reads as a sequence of short sections rather than one column of
   paragraphs. */
.vl-container > .vl-section-head,
.vl-privacy > .vl-section-head {
  margin-top: var(--space-6);
  padding-top: var(--space-4);
  border-top: 1px solid var(--hairline);
}

/* Stacked cards keep an 8px gap: the handoff and fallback panels that
   request.js shows after a send, on /concierge/ and every family page
   (restored, checker MEDIUM-2). */
.vl-card + .vl-card {
  margin-top: var(--space-1);
}

/* All services: the menu book (founder ruling R-2026-10-19-J). The eight
   families are numbered rows 01-08; the whole row is the family's link (at
   least 48px tall) with the site's 2px bronze focus ring. Numeral: Spectral
   Light in champagne (dark) or espresso (light); name: Spectral capitals;
   promise: Inter, muted; a small arrow. Bronze is a line only: the rules
   between rows. Phone: one column. 900px and up: a two-page spread, 01-04 |
   05-08, with a hairline down the centre gutter; this list alone is wider
   than the 640px reading column (the intro stays at its readable width). */
.vl-container > .vl-menu {
  margin-top: var(--space-6);
}

.vl-menu__list {
  margin: 0;
  padding: 0;
  list-style: none;
}

.vl-menu__item {
  border-top: 1px solid var(--bronze-soft);
}

.vl-menu__item:last-child {
  border-bottom: 1px solid var(--bronze-soft);
}

.vl-menu__row {
  display: grid;
  grid-template-columns: 52px minmax(0, 1fr) 20px;
  column-gap: var(--space-2);
  align-items: start;
  min-height: var(--control-min-height);
  padding-block: 20px;
  color: var(--text-warm);
}

.vl-menu__num {
  font-family: var(--font-heading);
  font-weight: 300;
  font-size: 40px;
  line-height: 1;
  font-variant-numeric: lining-nums;
  color: var(--numeral);
}

.vl-menu__text {
  display: flex;
  flex-direction: column;
  gap: 6px;
  padding-top: 4px;
}

.vl-menu__name {
  font-family: var(--font-heading);
  font-weight: 400;
  font-size: 17px;
  line-height: 1.3;
  letter-spacing: 0.08em;
  color: var(--text-warm);
}

.vl-menu__promise {
  font-family: var(--font-body);
  font-size: 15px;
  line-height: 1.45;
  color: var(--text-muted);
}

.vl-menu__arrow {
  align-self: center;
  font-family: var(--font-body);
  font-size: 17px;
  line-height: 1;
  text-align: right;
  color: var(--bronze);
}

.vl-menu__row:hover .vl-menu__arrow {
  color: var(--text-warm);
}

.vl-menu__row:focus-visible {
  outline: var(--focus-outline-width) solid var(--bronze);
  outline-offset: 2px;
}

@media (min-width: 900px) {
  .vl-container > .vl-menu {
    --menu-width: min(960px, 100vw - 2 * var(--container-pad));
    width: var(--menu-width);
    margin-inline: calc((100% - var(--menu-width)) / 2);
  }

  .vl-menu__list {
    position: relative;
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    grid-template-rows: repeat(4, auto);
    grid-auto-flow: column;
    column-gap: var(--space-12);
  }

  .vl-menu__list::before {
    content: "";
    position: absolute;
    top: 0;
    bottom: 0;
    left: 50%;
    border-left: 1px solid var(--bronze-soft);
  }

  .vl-menu__item:nth-child(4) {
    border-bottom: 1px solid var(--bronze-soft);
  }

  .vl-menu__row {
    grid-template-columns: 64px minmax(0, 1fr) 20px;
    padding-block: 24px;
  }

  .vl-menu__num {
    font-size: 48px;
  }
}

/* FAQ: the question steps up into Spectral so it reads as a sub-head
   of the FAQ section rather than as faux-bold body text; its answer
   stays Inter. Items get the standard gap between them. */
.vl-faq-item + .vl-faq-item {
  margin-top: var(--space-4);
}

.vl-faq-item > * + * {
  margin-top: var(--space-1);
}

.vl-faq-item > .vl-body:first-child {
  font-family: var(--font-heading);
  font-weight: 400;
  font-size: 20px;
  line-height: 1.3;
  text-wrap: balance;
}

.vl-faq-item > .vl-body:first-child strong {
  font-weight: 400;
}

/* List items (What this covers) — tight, since they're one list, not
   separate blocks. */
.vl-container > ul > li + li {
  margin-top: var(--space-1);
}

/* Footer is compact utility text — tighter rhythm than the main
   content. */
footer.vl-section > * + * {
  margin-top: var(--space-1);
}

footer.vl-section > .vl-hairline {
  margin-top: var(--space-3);
}

footer.vl-section > .vl-hairline + * {
  margin-top: var(--space-3);
}

/* The venue-mention notice is a sentence, not a kicker: set it as
   sentence-case muted text at the venue size so it can actually be
   read, instead of five lines of 12px tracked capitals. The words are
   unchanged; only the presentation is. */
footer.vl-section > .vl-hairline + .vl-label {
  font-weight: 400;
  font-size: 15px;
  line-height: 1.45;
  text-transform: none;
  letter-spacing: 0;
  text-wrap: pretty;
  color: var(--text-muted);
}

footer.vl-section .vl-venue a {
  color: var(--text-muted);
  text-decoration: underline;
  text-decoration-color: var(--bronze-soft);
  text-underline-offset: 0.18em;
}

/* Tap area. The "ALL SERVICES" link at the top of a page and the footer links
   ("The VIP Liaison", "Privacy Facts", "Terms") are one short line of text, far
   below the 48px control height. The link itself becomes a 48px-tall box with
   the text centred in it. For "ALL SERVICES" a negative block margin gives back
   exactly the extra height, so the line it sits on keeps its own height and
   nothing on the page moves. Text, size, colour and position are unchanged. */
main > .vl-label > a,
footer.vl-section .vl-venue a {
  display: inline-flex;
  align-items: center;
  min-height: var(--control-min-height);
}

main > .vl-label > a {
  margin-block: calc((1.4em - var(--control-min-height)) / 2);
}

/* Footer links keep no negative margin: each footer link line is its own
   48px tall, so consecutive links ("Privacy Facts", "Terms") get separate tap
   boxes that never overlap. With the old negative margin the two 48px boxes
   overlapped by about 18px and a tap there went to "Terms" (independent
   ChatGPT Work audit, 2026-10-17). The footer is a little taller; text, size,
   colour and order are unchanged. */
footer.vl-section .vl-venue a {
  margin-block: 0;
}

/* Card */
.vl-card {
  background: var(--surface);
  border: 1px solid var(--hairline);
  border-radius: var(--radius);
  padding: var(--card-pad);
}

/* Empty-state block — identical everywhere: surface-colored, fixed
   ratio, one hairline at the bottom, nothing inside */
.vl-empty {
  background: var(--surface);
  aspect-ratio: 4 / 3;
  border-bottom: 1px solid var(--hairline);
}

/* Hero — Home D Rectangle (founder ruling R-2026-10-19-J).
   vip-hero-v1 is never cropped: it always renders at its full 1456:819
   shape, full width, nose and tail of the jet in frame.
   Dark (the default; also with JavaScript off): the title, tagline and Enter
   sit in an extended night-sky block (--sky) directly above the photo, so
   there is no empty band above the title and the block runs into the photo's
   own sky; the photo's foot dissolves into the page. Landscape desktop
   (901px and up, landscape): the same lockup sits on the photo's own sky,
   over a soft sky-coloured scrim confined to the top of the photo.
   Light: a flat cream title block under the bar, then the photo in a frame
   of bronze hairlines (see the light appearance block below).
   Both: a text-free quilted band under the photo, then a seat of space. */
.vl-hero {
  position: relative;
  display: flex;
  flex-direction: column;
  padding-bottom: var(--space-6);
}

.vl-hero > .vl-hero__content {
  max-width: none;
  /* Full width in the column flex box: .vl-container's auto side margins
     would otherwise shrink the sky block to its content (checker HIGH-1). */
  margin-inline: 0;
  align-self: stretch;
  padding-top: 64px;
  padding-bottom: 44px;
  background: var(--sky);
  text-align: center;
}

.vl-hero__content > .vl-hero__tagline {
  margin-top: var(--space-2);
}

.vl-hero__media {
  position: relative;
  display: block;
}

.vl-hero__img {
  display: block;
  width: 100%;
  height: auto;
}

/* The photo's foot dissolves into the page (dark only). */
.vl-hero__media::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 46%;
  background: linear-gradient(to bottom, rgba(10, 9, 8, 0) 0%, var(--canvas) 100%);
  pointer-events: none;
}

.vl-hero__scrim {
  display: none;
}

@media (min-width: 901px) {
  .vl-hero {
    padding-bottom: 64px;
  }

  .vl-hero__media::after {
    height: 30%;
  }
}

@media (min-width: 901px) and (orientation: landscape) {
  html:not([data-theme="light"]) .vl-hero > .vl-hero__content {
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    z-index: 2;
    background: transparent;
    padding-top: clamp(16px, calc(14.5vw - 120px), 84px);
    padding-bottom: 0;
  }

  /* The scrim covers the photo only (its own 1456:819 box at the top of the
     hero), strongest behind the lockup and gone by mid-photo. Contrast over
     the photo is measured, not assumed. */
  html:not([data-theme="light"]) .vl-hero__scrim {
    display: block;
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    z-index: 1;
    aspect-ratio: 1456 / 819;
    background: linear-gradient(to bottom, rgba(4, 9, 18, .86) 0%, rgba(4, 9, 18, .72) 26%, rgba(4, 9, 18, .30) 42%, rgba(4, 9, 18, 0) 54%);
    pointer-events: none;
  }
}

/* Quilted band (R-2026-10-19-J): a text-free decorative strip of the house
   quilt, never behind text. Fixed height (no layout shift); one bronze
   hairline above and below; the flat colour shows if the image never loads.
   The tile repeats seamlessly; a row of cushions is centred in the band. */
.vl-quilt {
  height: 40px;
  border-block: 1px solid var(--bronze-soft);
  background-color: #3b2a1e;
  background-image: url('img/quilt-dark.webp');
  background-image: -webkit-image-set(url('img/quilt-dark.webp') 1x, url('img/quilt-dark-2x.webp') 2x);
  background-image: image-set(url('img/quilt-dark.webp') 1x, url('img/quilt-dark-2x.webp') 2x);
  background-size: 56px auto;
  background-position: 50% 50%;
  background-repeat: repeat;
}

@media (min-width: 901px) {
  .vl-quilt {
    height: 56px;
    background-size: 64px auto;
  }
}

/* All services: the cover band sits right under the top bar (its top
   hairline lies over the bar's own rule) and the closing band above the
   footer spans the reading column, edge to edge on a phone. */
.vl-topbar + .vl-quilt {
  margin-top: -1px;
}

.vl-container > .vl-quilt {
  margin-top: var(--space-9);
  margin-inline: calc(-1 * var(--container-pad));
}

.vl-container > .vl-quilt + footer.vl-section {
  margin-top: 0;
  padding-top: var(--space-6);
}

/* Tagline sits one step below the title in the hierarchy: body size,
   muted tone, held to a short measure so it never runs wider than the
   title above it. */
.vl-hero__tagline {
  margin: 0;
  margin-inline: auto;
  max-width: 30em;
  font-family: var(--font-body);
  font-weight: 400;
  font-size: 17px;
  line-height: 1.5;
  text-wrap: balance;
  color: var(--text-muted);
}

/* Controls */
.vl-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: var(--control-min-height);
  padding-inline: var(--space-3);
  border-radius: var(--radius);
  /* Secondary buttons take the same faint edge as the form fields
     (measured 3.0:1 against canvas and surface) instead of the 10%
     hairline, which measured 1.2:1 — the button read as floating text. */
  border: 1px solid var(--text-faint);
  background: transparent;
  color: var(--text-warm);
  font-family: var(--font-body);
  font-size: 17px;
  font-weight: 400;
  cursor: pointer;
  transition: border-color var(--motion-hover) ease, color var(--motion-hover) ease;
}

.vl-btn:hover {
  border-color: var(--bronze-soft);
}

.vl-btn:focus-visible {
  outline: var(--focus-outline-width) solid var(--bronze);
  outline-offset: 2px;
  border-color: var(--bronze-soft);
}

/* Bronze marks the single active control — never a fill, never a
   large surface */
.vl-btn--active {
  border-color: var(--bronze);
  color: var(--bronze);
}

.vl-btn--disabled,
.vl-btn:disabled {
  color: var(--text-faint);
  border-color: var(--hairline);
  cursor: not-allowed;
}

.vl-actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  align-items: center;
}

.vl-action-note {
  font-family: var(--font-body);
  font-size: 12px;
  color: var(--text-muted);
}

[data-vl-copy] {
  min-width: var(--action-min-width);
}

/* Form fields */
.vl-field {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
}

.vl-field > label {
  font-family: var(--font-body);
  font-weight: 500;
  font-size: 12px;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--bronze);
}

.vl-field input,
.vl-field textarea {
  min-height: var(--control-min-height);
  padding: var(--space-1) var(--space-2);
  background: var(--surface);
  border: 1px solid var(--text-faint);
  border-radius: var(--radius);
  color: var(--text-warm);
  font-family: var(--font-body);
  font-size: 17px;
  line-height: 1.5;
}

.vl-field textarea {
  min-height: calc(var(--control-min-height) * 3);
  resize: vertical;
}

.vl-field input:focus-visible,
.vl-field textarea:focus-visible {
  outline: var(--focus-outline-width) solid var(--bronze);
  outline-offset: 2px;
  border-color: var(--bronze-soft);
}

/* Review-before-send sheet */
.vl-sheet {
  position: fixed;
  inset: 0;
  z-index: 10;
  display: flex;
  align-items: flex-end;
  background: rgba(5, 4, 3, .72);
  opacity: 0;
  pointer-events: none;
  visibility: hidden;
  transition: opacity var(--motion-sheet) ease,
              visibility 0s linear var(--motion-sheet);
}

.vl-sheet[data-open="true"] {
  opacity: 1;
  pointer-events: auto;
  visibility: visible;
  transition: opacity var(--motion-sheet) ease,
              visibility 0s;
}

.vl-sheet__panel {
  width: 100%;
  max-width: var(--container-max);
  margin-inline: auto;
  background: var(--canvas-deep);
  border-top: 1px solid var(--hairline);
  border-radius: var(--radius) var(--radius) 0 0;
  padding: var(--card-pad);
  transform: translateY(100%);
  transition: transform var(--motion-sheet) ease;
}

.vl-sheet[data-open="true"] .vl-sheet__panel {
  transform: translateY(0);
}

.vl-sheet__text {
  white-space: pre-wrap;
  font-family: var(--font-body);
  font-size: 17px;
  line-height: 1.5;
  color: var(--text-warm);
  background: var(--surface);
  border: 1px solid var(--hairline);
  border-radius: var(--radius);
  padding: var(--space-2);
}

@media (min-width: 480px) {
  .vl-sheet {
    align-items: center;
  }

  .vl-sheet__panel {
    border-radius: var(--radius);
  }
}

/* ---------------------------------------------------------------------
   Level 2 — request form, pickers, confirmation, contact row.
   Existing tokens only; no new colours. */
[hidden] {
  display: none !important;
}

.vl-fields > * + * {
  margin-top: var(--space-3);
}

.vl-field__label {
  margin: 0;
  font-family: var(--font-body);
  font-weight: 500;
  font-size: 12px;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--bronze);
}

.vl-form-error:empty {
  display: none;
}

.vl-form-error {
  margin: 0;
  font-size: 15px;
  color: var(--text-warm);
  border-left: 2px solid var(--bronze);
  padding-left: var(--space-2);
}

/* Honeypot: present for bots, out of sight, tab order and screen readers */
.vl-hp {
  position: absolute;
  left: -10000px;
  top: auto;
  width: 1px;
  height: 1px;
  overflow: hidden;
}

.vl-request {
  position: relative;
}

/* Request-form space holder (R-2026-10-17-B). Every family page ships the
   form hidden and empty; request.js builds about 2,000px of fields and then
   shows it. Without a holder, everything below the form (contact row, FAQ,
   footer) jumped down when it appeared — the /request/ layout shift.
   The empty .vl-request-slot right after the form holds the built form's
   height (its 24px top margin included) while the form is still hidden and
   not yet marked data-vl-ready by request.js. Only when scripting is on:
   with JavaScript off the form never appears, so nothing is held and the
   contact row stays where it was. The heights sit at or just below the
   measured built form, so any difference only moves content already below
   the fold. Once data-vl-ready is set the slot is empty, zero-height and
   margin-free, so it takes no space and later hides of the form (the
   confirmation) never hold space again. init.js marks the form ready as soon
   as it runs, even if request.js is missing or failed; the 30s release below
   only covers every script failing to load. */
.vl-container > .vl-request-slot {
  margin-top: 0;
}

/* The confirmation card keeps the 8px gap it had when it followed the form
   directly (.vl-card + .vl-card). */
.vl-request + .vl-request-slot + .vl-card {
  margin-top: var(--space-1);
}

@media (scripting: enabled) {
  .vl-request[hidden]:not([data-vl-ready]) + .vl-request-slot {
    min-height: 2170px;
    animation: vl-request-slot-release 0s linear 30s forwards;
  }

  .vl-request[data-vl-family="special"][hidden]:not([data-vl-ready]) + .vl-request-slot,
  .vl-request[data-vl-family="dining"][hidden]:not([data-vl-ready]) + .vl-request-slot,
  .vl-request[data-vl-family="nightlife"][hidden]:not([data-vl-ready]) + .vl-request-slot,
  .vl-request[data-vl-family="celebrations"][hidden]:not([data-vl-ready]) + .vl-request-slot {
    min-height: 2270px;
  }
}

@media (scripting: enabled) and (max-width: 479px) {
  .vl-request[hidden]:not([data-vl-ready]) + .vl-request-slot {
    min-height: 2280px;
  }

  .vl-request[data-vl-family="special"][hidden]:not([data-vl-ready]) + .vl-request-slot,
  .vl-request[data-vl-family="dining"][hidden]:not([data-vl-ready]) + .vl-request-slot,
  .vl-request[data-vl-family="nightlife"][hidden]:not([data-vl-ready]) + .vl-request-slot,
  .vl-request[data-vl-family="celebrations"][hidden]:not([data-vl-ready]) + .vl-request-slot {
    min-height: 2375px;
  }
}

@media (scripting: enabled) and (max-width: 399px) {
  .vl-request[hidden]:not([data-vl-ready]) + .vl-request-slot {
    min-height: 2385px;
  }

  .vl-request[data-vl-family="special"][hidden]:not([data-vl-ready]) + .vl-request-slot,
  .vl-request[data-vl-family="dining"][hidden]:not([data-vl-ready]) + .vl-request-slot,
  .vl-request[data-vl-family="nightlife"][hidden]:not([data-vl-ready]) + .vl-request-slot,
  .vl-request[data-vl-family="celebrations"][hidden]:not([data-vl-ready]) + .vl-request-slot {
    min-height: 2500px;
  }
}

@keyframes vl-request-slot-release {
  to {
    min-height: 0;
  }
}

.vl-pick {
  position: relative;
}

.vl-pick__control {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-2);
  width: 100%;
  min-height: var(--control-min-height);
  padding: var(--space-1) var(--space-2);
  background: var(--surface);
  border: 1px solid var(--text-faint);
  border-radius: var(--radius);
  color: var(--text-warm);
  font-family: var(--font-body);
  font-size: 17px;
  line-height: 1.5;
  text-align: left;
  cursor: pointer;
}

.vl-pick__chevron {
  color: var(--bronze);
}

.vl-pick__control--empty .vl-pick__value {
  color: var(--text-muted);
}

.vl-pick__control:focus-visible {
  outline: var(--focus-outline-width) solid var(--bronze);
  outline-offset: 2px;
  border-color: var(--bronze-soft);
}

.vl-pick__list {
  position: absolute;
  left: 0;
  right: 0;
  top: calc(100% + 4px);
  z-index: 5;
  margin: 0;
  padding: var(--space-1) 0;
  list-style: none;
  max-height: 320px;
  overflow-y: auto;
  background: var(--canvas-deep);
  border: 1px solid var(--bronze-soft);
  border-radius: var(--radius);
}

.vl-pick__option {
  display: flex;
  align-items: center;
  min-height: var(--control-min-height);
  padding: 0 var(--space-2);
  color: var(--text-warm);
  cursor: pointer;
}

.vl-pick__option[aria-selected="true"] {
  color: var(--bronze);
}

.vl-pick__option--active {
  background: var(--surface);
  outline: 1px solid var(--bronze-soft);
  outline-offset: -1px;
}

.vl-cal {
  position: absolute;
  left: 0;
  top: calc(100% + 4px);
  z-index: 5;
  width: 100%;
  max-width: calc(7 * var(--control-min-height) + 2 * var(--space-2) + var(--space-1));
  padding: var(--space-2);
  background: var(--canvas-deep);
  border: 1px solid var(--bronze);
  border-radius: var(--radius);
}

.vl-cal__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-1);
}

.vl-cal__title {
  margin: 0;
  font-family: var(--font-body);
  font-weight: 500;
  font-size: 15px;
  color: var(--text-warm);
}

/* Calendar controls meet the site's 48px control height. On phones
   (max-width 480px) the calendar opens as a full-width sheet, so days
   and month buttons are 48px wide and tall at widths of 375px and up.
   Wider than that the popup is capped at seven 48px columns plus its own
   padding and border (and an 8px allowance): height stays 48px and day
   width is fluid, never under 48px. */
.vl-cal__nav,
.vl-cal__day {
  min-width: var(--control-min-height);
  min-height: var(--control-min-height);
  background: transparent;
  border: 1px solid transparent;
  border-radius: var(--radius);
  color: var(--text-warm);
  font-family: var(--font-body);
  font-size: 15px;
  cursor: pointer;
}

.vl-cal__nav {
  font-size: 22px;
  color: var(--bronze);
  border-color: var(--text-faint);
}

.vl-cal__nav:disabled {
  color: var(--text-faint);
  cursor: not-allowed;
}

.vl-cal__grid {
  width: 100%;
  margin-top: var(--space-1);
  border-collapse: collapse;
  table-layout: fixed;
}

.vl-cal__grid th {
  padding: 4px 0;
  font-family: var(--font-body);
  font-weight: 500;
  font-size: 12px;
  letter-spacing: 0.06em;
  color: var(--text-muted);
}

.vl-cal__grid td {
  padding: 0;
  text-align: center;
}

.vl-cal__day {
  width: 100%;
  min-width: 0;
}

/* Today: a faint edge in the field-outline tone (2.99:1 on the calendar's
   deep background; the 10% hairline measured 1.19:1 and read as nothing).
   A supplementary cue only: today is also the first selectable day, and
   aria-current="date" names it for screen readers. The selected day keeps
   the bronze edge, so the two never look alike. */
.vl-cal__day[aria-current="date"] {
  border-color: var(--text-faint);
}

.vl-cal__day--selected {
  border-color: var(--bronze);
  color: var(--bronze);
}

/* Selected wins over today. [aria-current] outranks a single class, so
   without this rule a selected today kept the today edge and lost the
   bronze one (seen on the live commit d0feeac). */
.vl-cal__day[aria-current="date"].vl-cal__day--selected {
  border-color: var(--bronze);
}

.vl-cal__day--off {
  color: var(--text-faint);
  cursor: not-allowed;
}

.vl-cal__nav:focus-visible,
.vl-cal__day:focus-visible {
  outline: var(--focus-outline-width) solid var(--bronze);
  outline-offset: 1px;
}

.vl-cal__foot {
  margin-top: var(--space-2);
  justify-content: flex-end;
}

/* Phones: the calendar opens as a full-width sheet (viewport width less
   8px each side) so all seven day columns and both nav buttons reach
   48px. The picker sits inside the form card, inside the container's
   side padding, so the sheet is pulled left by both paddings and the
   card's 1px border, less the 8px gutter. */
@media (max-width: 480px) {
  .vl-cal {
    left: calc(var(--space-1) - var(--container-pad) - var(--card-pad) - 1px);
    width: calc(100vw - 2 * var(--space-1));
    max-width: none;
    padding: var(--space-1);
  }

  .vl-cal__nav {
    min-width: var(--control-min-height);
  }
}

.vl-ref {
  letter-spacing: 0.04em;
}

.vl-status-link {
  overflow-wrap: anywhere;
}

.vl-status-link a {
  color: var(--text-warm);
  text-decoration: underline;
  text-decoration-color: var(--bronze-soft);
}

[data-vl-confirm]:focus,
[data-vl-fallback-panel]:focus {
  outline: none;
}

.vl-contact > * + * {
  margin-top: var(--space-2);
}

.vl-privacy > * + * {
  margin-top: var(--space-3);
}

.vl-privacy > h1 + p {
  margin-top: var(--space-1);
}

.vl-privacy li + li {
  margin-top: var(--space-1);
}

/* Public request upgrade (R-2026-10-15-M): the optional details, the
   review screen and the handoff screen. Existing tokens only; no new
   colours, no shadow; bronze stays an edge, never a fill. */
.vl-more > * + * {
  margin-top: var(--space-3);
}

.vl-more > .vl-label {
  margin-top: var(--space-3);
}

.vl-more > .vl-label + .vl-venue {
  margin-top: var(--space-1);
}

.vl-field input[aria-invalid="true"] {
  border-color: var(--bronze);
}

.vl-review > * + * {
  margin-top: var(--space-3);
}

.vl-review > .vl-section-head + .vl-venue {
  margin-top: var(--space-1);
}

.vl-review:focus,
.vl-handoff:focus {
  outline: none;
}

.vl-review__list {
  margin-block: var(--space-3) 0;
  margin-inline: 0;
  padding: 0;
}

.vl-review__list dt {
  margin: 0;
  font-family: var(--font-body);
  font-weight: 500;
  font-size: 12px;
  line-height: 1.4;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--bronze);
}

.vl-review__list dt + dd {
  margin: 4px 0 0;
}

.vl-review__list dd {
  font-family: var(--font-body);
  font-size: 17px;
  line-height: 1.5;
  color: var(--text-warm);
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}

.vl-review__list dd + dt {
  margin-top: var(--space-2);
}

.vl-handoff > * + * {
  margin-top: var(--space-3);
}

.vl-handoff__message {
  margin: 0;
  white-space: pre-wrap;
  overflow-wrap: anywhere;
  font-family: var(--font-body);
  font-size: 17px;
  line-height: 1.5;
  color: var(--text-warm);
  background: var(--canvas-deep);
  border: 1px solid var(--hairline);
  border-radius: var(--radius);
  padding: var(--space-2);
}

/* Motion discipline — nothing animates outside the named exceptions */
@media (prefers-reduced-motion: reduce) {
  * {
    transition-duration: 0.01ms !important;
    animation-duration: 0.01ms !important;
  }

  /* The review sheet hides at once: no 200ms wait (--motion-sheet) before its
     visibility flips. */
  .vl-sheet {
    transition-delay: 0s !important;
  }
}

/* Status page trip statement (only rendered when the Worker's statement
   switch is on). Spacing only. */
.vl-status-trip > * {
  margin: 0;
}

.vl-status-trip > * + * {
  margin-top: var(--space-1);
}

/* ---------------------------------------------------------------------
   Top bar (founder, 2026-10-17: "I want Claude to have a home button").
   One compact row on every public guest page: the wordmark and "Home" both
   go to the home page, "All services" goes to /concierge/, then the
   Light/Dark choice. Existing tokens only. Every link and button is 48px
   tall (the site's control height) and at least 44px wide, with the site's
   2px bronze focus ring. At 390px it is one row; on a phone narrower than
   the row it wraps to a second line instead of overlapping or scrolling
   sideways. */
.vl-topbar {
  border-bottom: 1px solid var(--hairline);
}

.vl-topbar__bar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: flex-end;
  max-width: var(--container-max);
  min-height: 60px;
  margin-inline: auto;
  padding: 6px var(--space-2);
}

.vl-topbar__nav {
  display: flex;
  align-items: center;
  flex: 1 1 auto;
}

@media (min-width: 480px) {
  .vl-topbar__bar {
    padding-inline: var(--container-pad);
  }
}

/* A visible 8px gap between the "Home" and "All services" tap boxes at every
   width (checker L3, 2026-10-17: they touched below 480px). The wordmark is
   kept apart from them by its own auto margin. */
.vl-topbar__link + .vl-topbar__link {
  margin-inline-start: var(--space-1);
}

.vl-topbar__mark,
.vl-topbar__link,
.vl-theme__btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: var(--control-min-height);
  min-width: 44px;
  white-space: nowrap;
}

.vl-topbar__mark {
  justify-content: flex-start;
  margin-inline-end: auto;
  font-family: var(--font-heading);
  font-weight: 400;
  font-size: 16px;
  line-height: 1.2;
  color: var(--text-warm);
}

.vl-topbar__link {
  padding-inline: 4px;
  font-family: var(--font-body);
  font-weight: 500;
  font-size: 14px;
  line-height: 1.2;
  color: var(--text-muted);
  text-decoration: underline;
  text-decoration-color: transparent;
  text-decoration-thickness: 1px;
  text-underline-offset: 0.35em;
}

/* Phones narrower than 400px (iPhone mini and SE at 375px): one size step
   down so the whole row still fits on one line. */
@media (max-width: 399px) {
  .vl-topbar__mark {
    font-size: 15px;
  }

  .vl-topbar__link,
  .vl-theme__btn {
    font-size: 13px;
  }
}

/* The page you are on: full-strength text and an underline, never colour
   alone. */
.vl-topbar__link[aria-current="page"] {
  color: var(--text-warm);
  text-decoration-color: var(--bronze);
}

.vl-topbar__mark:focus-visible,
.vl-topbar__link:focus-visible,
.vl-theme__btn:focus-visible {
  outline: var(--focus-outline-width) solid var(--bronze);
  outline-offset: 2px;
}

/* Light / Dark: a two-button group. The pressed button shows full-strength
   text and a 2px bar under it; aria-pressed carries the state for screen
   readers. Hidden (space kept, out of the tab order) until theme.js has run,
   so without JavaScript there are no buttons that do nothing. */
.vl-theme {
  display: inline-flex;
  margin-inline-start: 6px;
  border: 1px solid var(--text-faint);
  border-radius: var(--radius);
}

html:not([data-theme]) .vl-theme {
  visibility: hidden;
}

.vl-theme__btn {
  margin: 0;
  padding: 0 6px;
  background: transparent;
  border: 0;
  border-bottom: 2px solid transparent;
  border-radius: 0;
  /* 46px + the group's 1px edge above and below = the 48px control height. */
  min-height: 46px;
  color: var(--text-muted);
  font-family: var(--font-body);
  font-weight: 500;
  font-size: 14px;
  line-height: 1.2;
  cursor: pointer;
}

.vl-theme__btn[aria-pressed="true"] {
  color: var(--text-warm);
  border-bottom-color: var(--bronze);
}

/* Hover keeps a control edge of at least 3:1 in both themes (checker L5,
   2026-10-17: the soft bronze hover edge measured about 1.6:1). Dark: bronze
   #b28a54; light: espresso (the light theme's bronze role). Disabled and
   not-yet-armed buttons keep their own edge. Guest pages only: html carries
   data-theme only where theme.js runs, so the admin (which also loads
   site.css) keeps its own hover (re-check L-b). */
html[data-theme] .vl-btn:hover:not(:disabled):not(.vl-btn--disabled):not([aria-disabled="true"]) {
  border-color: var(--bronze);
}

/* The primary button already has the bronze edge, so on hover its text turns
   to the full text tone instead: a visible change that never drops below
   3:1 (re-check L-a). Dark: #efe6d8 on the page 16.09:1. */
html[data-theme] .vl-btn.vl-btn--active:hover:not(:disabled):not(.vl-btn--disabled):not([aria-disabled="true"]) {
  color: var(--text-warm);
}

/* A theme switch is instant: theme.js sets this class for the one style pass
   that applies the new colours, so no colour transition runs. */
html.vl-theme-switching *,
html.vl-theme-switching *::before,
html.vl-theme-switching *::after {
  transition: none !important;
}

/* ---------------------------------------------------------------------
   Light appearance (guest's choice, theme.js; dark stays the default).
   Settled VIP tokens and mixes of them only — no new hue:
     canvas, canvas-deep  #efe6d8 (the warm text tone as the page)
     surface              #e5daca = 25% champagne #c7b69f over #efe6d8
     text                 #14110d
     muted text           espresso #3b2a1e
     faint (field and button edges, list markers)
                          espresso #3b2a1e at 62%
     bronze role          espresso #3b2a1e: every place the dark theme uses
                          bronze as text, a focus ring or a control edge
                          (bronze #b28a54 itself is 2.55:1 on #efe6d8, too
                          light for text or a control edge)
     bronze-soft, hairline  bronze #b28a54 at 55% / 45%: rules, card edges,
                          underlines and hover edges only — never text,
                          never a fill
   Every text/background pair is computed in
   tests/unit/vip-theme-contrast.test.ts (WCAG AA). */
html[data-theme="light"] {
  --canvas: #efe6d8;
  --canvas-deep: #efe6d8;
  --surface: #e5daca;
  --text-warm: #14110d;
  --text-muted: #3b2a1e;
  --text-faint: rgba(59, 42, 30, .62);
  --bronze: #3b2a1e;
  --bronze-soft: rgba(178, 138, 84, .55);
  --hairline: rgba(178, 138, 84, .45);
  --numeral: #3b2a1e;
}

/* Light hero (R-2026-10-19-J): a flat cream title block under the bar —
   title #14110d, tagline espresso, Enter the light primary — then the photo,
   full width and uncropped, framed by bronze hairlines top and bottom, with
   no dissolve. At every width, landscape desktop included. Numerals on All
   services take espresso. */
html[data-theme="light"] .vl-hero > .vl-hero__content {
  padding-top: var(--space-6);
  padding-bottom: 36px;
  background: var(--canvas);
}

html[data-theme="light"] .vl-hero__media {
  border-block: 1px solid var(--bronze-soft);
}

html[data-theme="light"] .vl-hero__media::after {
  display: none;
}

@media (min-width: 901px) {
  html[data-theme="light"] .vl-hero > .vl-hero__content {
    padding-top: 56px;
    padding-bottom: 40px;
  }
}

html[data-theme="light"] .vl-quilt {
  background-color: #e5daca;
  background-image: url('img/quilt-light.webp');
  background-image: -webkit-image-set(url('img/quilt-light.webp') 1x, url('img/quilt-light-2x.webp') 2x);
  background-image: image-set(url('img/quilt-light.webp') 1x, url('img/quilt-light-2x.webp') 2x);
}

/* Calendar edges (WCAG 1.4.11, found by tests/unit/vip-theme-contrast.test.ts,
   2026-10-17): on the calendar's deep background the faint field-outline tone
   measured 2.99:1, just under 3:1, for the month buttons' edge and today's
   edge. Inside the calendar only, that tone is 40% instead of 38% (3.20:1);
   everywhere else it is unchanged. Light keeps its own faint tone. */
.vl-cal {
  --text-faint: rgba(239, 230, 216, .40);
}

html[data-theme="light"] .vl-cal {
  --text-faint: rgba(59, 42, 30, .62);
}

/* Light primary buttons (PENDING founder approval, checker M2, 2026-10-17).
   In the light theme the main action ("Enter", "Send request", the review's
   "Send request", "Open …" on the handoff, the first contact link of the
   fallback) had lost its lead: espresso text beside near-black secondary
   buttons. Light only, it now has a solid espresso #3b2a1e fill with #efe6d8
   text. Bronze is never a fill. Dark is unchanged; secondary buttons are
   unchanged.
     rest       #efe6d8 on #3b2a1e   11.06:1; fill against the page 11.06:1
     hover      #efe6d8 on #14110d   15.22:1 (a deeper fill)
     pressed    #c7b69f on #14110d   champagne text on the deeper fill
     focus      the site's 2px espresso ring, 2px clear of the fill
     not armed / disabled  no fill: espresso text (11.06:1) and the faint
                62% edge (3.79:1), like an outlined button */
html[data-theme="light"] .vl-btn.vl-btn--active {
  background: #3b2a1e;
  border-color: #3b2a1e;
  color: #efe6d8;
}

html[data-theme="light"] .vl-btn.vl-btn--active:hover:not(:disabled):not(.vl-btn--disabled):not([aria-disabled="true"]) {
  background: #14110d;
  border-color: #14110d;
  color: #efe6d8;
}

html[data-theme="light"] .vl-btn.vl-btn--active:active:not(:disabled):not(.vl-btn--disabled):not([aria-disabled="true"]) {
  background: #14110d;
  border-color: #14110d;
  color: #c7b69f;
}

html[data-theme="light"] .vl-btn.vl-btn--active:disabled,
html[data-theme="light"] .vl-btn.vl-btn--active.vl-btn--disabled,
html[data-theme="light"] .vl-btn.vl-btn--active[aria-disabled="true"] {
  background: transparent;
  border-color: var(--text-faint);
  color: var(--text-muted);
}

/* Light primary, not armed and sending (PENDING founder approval; depends on
   the light primary fill above; re-check M2-D, 2026-10-17). The no-fill state
   above looked like an enabled secondary button. While "Send request" is not
   yet armed (its first 400 ms) or is sending, it now takes the same dimmed
   look as a disabled secondary button such as "Edit" beside it: the faint
   62% espresso text (3.79:1 on the page, 3.62:1 on a card — the contrast the
   light disabled state had before the fill) and the bronze hairline edge. */
html[data-theme="light"] .vl-btn.vl-btn--active:disabled,
html[data-theme="light"] .vl-btn.vl-btn--active.vl-btn--disabled,
html[data-theme="light"] .vl-btn.vl-btn--active[aria-disabled="true"] {
  background: transparent;
  border-color: var(--hairline);
  color: var(--text-faint);
}

/* =====================================================================
   Clean upgrade (founder ruling R-2026-10-22-M, "as recommended"):
   soft rounded corners, pill buttons, the ☰ menu holding Home, All
   services and the light/dark switch, one line-icon family (Lucide, ISC
   licence, assets/icons/), and the All services rows as rounded cards.
   Guest pages only: html carries data-theme only where theme.js runs, so
   the admin pages (which also load this file) keep their flat 2px corners;
   without JavaScript the guest pages keep them too.
   Icons are drawn with CSS masks over self-hosted SVG files (CSP img-src
   'self'), coloured by currentColor or bronze, so no markup carries them.
   ===================================================================== */
html[data-theme] {
  --radius: 14px;
  --radius-card: 18px;
  --radius-pill: 999px;
}

html[data-theme] .vl-card {
  border-radius: var(--radius-card);
}

html[data-theme] .vl-btn {
  gap: 10px;
  border-radius: var(--radius-pill);
}

html[data-theme] .vl-sheet__panel {
  border-radius: var(--radius-card) var(--radius-card) 0 0;
}

@media (min-width: 600px) {
  html[data-theme] .vl-sheet__panel {
    border-radius: var(--radius-card);
  }
}

html[data-theme] .vl-cal__day {
  border-radius: var(--radius-pill);
}

/* --- Icons --------------------------------------------------------- */
.vl-icon-mask,
a.vl-btn[data-vl-channel]::before,
.vl-theme__btn::before,
.vl-navmenu__icon,
.vl-chip[aria-pressed="true"]::before {
  -webkit-mask: var(--vl-icon) center / contain no-repeat;
  mask: var(--vl-icon) center / contain no-repeat;
}

html[data-theme] a.vl-btn[data-vl-channel]::before {
  content: "";
  flex: none;
  width: 18px;
  height: 18px;
  background-color: currentColor;
}

a.vl-btn[data-vl-channel="whatsapp"] { --vl-icon: url('icons/message-circle.svg'); }
a.vl-btn[data-vl-channel="sms"] { --vl-icon: url('icons/message-square.svg'); }
a.vl-btn[data-vl-channel="email"] { --vl-icon: url('icons/mail.svg'); }

/* --- The ☰ menu ----------------------------------------------------- */
.vl-topbar__bar {
  position: relative;
  flex-wrap: nowrap;
}

.vl-navmenu {
  flex: none;
}

.vl-navmenu__button {
  display: flex;
  align-items: center;
  justify-content: center;
  box-sizing: border-box;
  width: var(--control-min-height);
  height: var(--control-min-height);
  /* A visible edge, so the button still shows if its icon file fails. */
  border: 1px solid var(--text-faint);
  border-radius: var(--radius-pill);
  color: var(--text-warm);
  cursor: pointer;
  list-style: none;
}

.vl-navmenu__button::-webkit-details-marker {
  display: none;
}

.vl-navmenu__button::marker {
  content: "";
}

.vl-navmenu__button:focus-visible {
  outline: var(--focus-outline-width) solid var(--bronze);
  outline-offset: 2px;
}

.vl-navmenu__icon {
  --vl-icon: url('icons/menu.svg');
  display: block;
  width: 24px;
  height: 24px;
  background-color: currentColor;
}

.vl-navmenu[open] .vl-navmenu__icon {
  --vl-icon: url('icons/x.svg');
}

.vl-navmenu__panel {
  position: absolute;
  z-index: 50;
  top: calc(100% + 8px);
  right: var(--space-2);
  box-sizing: border-box;
  width: min(320px, calc(100vw - 2 * var(--space-2)));
  padding: var(--space-1) var(--space-2) var(--space-2);
  background: var(--surface);
  border: 1px solid var(--hairline);
  border-radius: var(--radius-card);
}

.vl-navmenu__panel .vl-topbar__nav {
  display: flex;
  flex-direction: column;
  align-items: stretch;
}

.vl-navmenu__panel .vl-topbar__link {
  justify-content: space-between;
  min-height: 56px;
  padding-inline: 0;
  font-family: var(--font-heading);
  font-weight: 300;
  font-size: 22px;
  color: var(--text-warm);
  border-bottom: 1px solid var(--hairline);
}

.vl-navmenu__panel .vl-topbar__link + .vl-topbar__link {
  margin-inline-start: 0;
}

.vl-navmenu__panel .vl-topbar__link::after {
  content: "";
  width: 18px;
  height: 18px;
  background-color: var(--bronze);
  -webkit-mask: url('icons/chevron-right.svg') center / contain no-repeat;
  mask: url('icons/chevron-right.svg') center / contain no-repeat;
}

/* Without JavaScript the Light/Dark group is hidden (above); so is its label. */
html:not([data-theme]) .vl-navmenu__label {
  visibility: hidden;
}

.vl-navmenu__label {
  margin: var(--space-3) 0 var(--space-1);
  font-family: var(--font-body);
  font-weight: 500;
  font-size: 12px;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--bronze);
}

.vl-navmenu__panel .vl-theme {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 4px;
  margin: 0;
  padding: 3px;
  border: 1px solid var(--text-faint);
  border-radius: var(--radius-pill);
}

.vl-navmenu__panel .vl-theme__btn {
  gap: 8px;
  min-height: var(--control-min-height);
  padding: 0 12px;
  border: 1px solid transparent;
  border-radius: var(--radius-pill);
  color: var(--text-warm);
  font-size: 15px;
}

.vl-navmenu__panel .vl-theme__btn::before {
  content: "";
  flex: none;
  width: 18px;
  height: 18px;
  background-color: currentColor;
}

.vl-theme__btn[data-vl-theme-set="light"] { --vl-icon: url('icons/sun.svg'); }
.vl-theme__btn[data-vl-theme-set="dark"] { --vl-icon: url('icons/moon.svg'); }

/* The chosen look: an espresso fill with cream text and a bronze edge in
   dark (bronze stays a line, never a fill); espresso in light. */
.vl-navmenu__panel .vl-theme__btn[aria-pressed="true"] {
  background: #3b2a1e;
  color: #efe6d8;
  border-color: var(--bronze);
}

/* --- All services: rounded cards with a family icon ----------------- */
.vl-menu__item,
.vl-menu__item:last-child,
.vl-menu__item:nth-child(4) {
  border: 0;
}

.vl-menu__item + .vl-menu__item {
  margin-top: 10px;
}

.vl-menu__row {
  grid-template-columns: 44px minmax(0, 1fr) 20px;
  align-items: center;
  padding: 14px 16px;
  background: var(--surface);
  border: 1px solid var(--hairline);
  border-radius: var(--radius-card);
}

.vl-menu__num {
  position: relative;
  width: 44px;
  height: 44px;
  font-size: 0;
  border: 1px solid var(--hairline);
  border-radius: 999px;
}

.vl-menu__num::after {
  content: "";
  position: absolute;
  inset: 11px;
  background-color: var(--bronze);
  -webkit-mask: var(--vl-icon) center / contain no-repeat;
  mask: var(--vl-icon) center / contain no-repeat;
}

.vl-menu__text {
  padding-top: 0;
}

.vl-menu__name {
  font-family: var(--font-body);
  font-weight: 600;
  font-size: 13px;
  letter-spacing: 0.14em;
}

.vl-menu__arrow {
  width: 20px;
  height: 20px;
  font-size: 0;
  background-color: var(--bronze);
  -webkit-mask: url('icons/chevron-right.svg') center / contain no-repeat;
  mask: url('icons/chevron-right.svg') center / contain no-repeat;
}

.vl-menu__row:hover .vl-menu__arrow {
  background-color: var(--text-warm);
}

[data-vl-icon="plane"] { --vl-icon: url('icons/plane.svg'); }
[data-vl-icon="utensils"] { --vl-icon: url('icons/utensils.svg'); }
[data-vl-icon="martini"] { --vl-icon: url('icons/martini.svg'); }
[data-vl-icon="trophy"] { --vl-icon: url('icons/trophy.svg'); }
[data-vl-icon="mountain-snow"] { --vl-icon: url('icons/mountain-snow.svg'); }
[data-vl-icon="party-popper"] { --vl-icon: url('icons/party-popper.svg'); }
[data-vl-icon="briefcase"] { --vl-icon: url('icons/briefcase.svg'); }
[data-vl-icon="sparkles"] { --vl-icon: url('icons/sparkles.svg'); }

@media (min-width: 900px) {
  .vl-menu__list {
    column-gap: var(--space-3);
    row-gap: 10px;
  }

  .vl-menu__list::before {
    content: none;
  }

  .vl-menu__item + .vl-menu__item {
    margin-top: 0;
  }

  .vl-menu__row {
    grid-template-columns: 44px minmax(0, 1fr) 20px;
    padding: 18px 20px;
  }

  .vl-menu__num {
    font-size: 0;
  }
}

/* --- A room's own choices (R-2026-10-22-M item 1) --------------------
   Inside a room the "Kind of help" list is replaced by that room's own
   services, taken from its "What this covers" list, as tap choices. */
.vl-chips {
  margin: 0;
  padding: 0;
  border: 0;
  min-width: 0;
}

.vl-chips > legend {
  padding: 0;
  margin-bottom: var(--space-1);
}

.vl-chips__row {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-1);
}

.vl-chip {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  min-height: var(--control-min-height);
  margin: 0;
  padding: 10px 16px;
  background: transparent;
  border: 1px solid var(--text-muted);
  border-radius: var(--radius-pill);
  color: var(--text-warm);
  font-family: var(--font-body);
  font-size: 15px;
  line-height: 1.25;
  text-align: left;
  cursor: pointer;
}

.vl-chip:focus-visible {
  outline: var(--focus-outline-width) solid var(--bronze);
  outline-offset: 2px;
}

.vl-chip[aria-pressed="true"] {
  background: #3b2a1e;
  color: #efe6d8;
  border-color: var(--bronze);
}

.vl-chip[aria-pressed="true"]::before {
  --vl-icon: url('icons/check.svg');
  content: "";
  flex: none;
  width: 16px;
  height: 16px;
  background-color: currentColor;
}
