/* ==========================================================================
   Salvia Farm to Table — "Warm Earth & Terracotta"
   ==========================================================================

   This stylesheet is the DESIGN.md design system, hand-written. The mock-up it
   comes from was built on the Tailwind CDN; that is a prototyping tool and has
   no place on a production WordPress site (a ~400KB runtime compiler on every
   page load, and a config object no PHP template can read). Every token below
   is the same value the mock-up's tailwind.config declared, expressed as a
   custom property, so the two cannot drift.

   STYLE — Tactile Minimalism. Structured layout, organic detail. Depth comes
   from tonal layers and hairline borders, never from heavy drop shadows; the
   one shadow in the system is a diffused terracotta-tinted lift on hover.

   PALETTE
     #9b2f00  primary        headings, focus, pressed states  (terracotta)
     #c2410c  primary-ctr    filled buttons                   (fired clay)
     #855300  secondary      labels, ticks, quote marks       (amber)
     #fbfaee  surface        the page                         (soft cream)
     #1b1c15  on-surface     body ink                         (deep charcoal)
     #59413a  on-surface-var secondary voice                  (warm brown)
     #303129  inverse-surf   the dark bands
     #e1bfb5  outline-var    every hairline

   Contrast measured, not eyeballed (AA needs 4.5:1 body, 3:1 UI):
     on-surface-variant on surface .. 8.9:1  ✓   primary on surface .. 7.2:1  ✓
     secondary on surface .......... 6.2:1  ✓   white on primary-ctr  5.2:1  ✓
     white on primary .............. 7.5:1  ✓   primary ring on surface 7.2:1 ✓

   TYPE
     Literata        display + headings. Bookish, organic terminals.
     Be Vietnam Pro  body, labels, inputs. Keeps the warmth from reading dated.
   Both are enqueued in functions.php with a system fallback stack, so a blocked
   font request degrades to Georgia/system sans rather than to nothing.
   ========================================================================== */

:root {
  /* ---- colour: surfaces ---- */
  --surface:          #fbfaee;
  --surface-dim:      #dbdbcf;
  --surface-lowest:   #ffffff;
  --surface-low:      #f5f4e8;
  --surface-ctr:      #efeee3;
  --surface-high:     #e9e9dd;
  --surface-highest:  #e4e3d7;
  --inverse-surface:  #303129;
  --inverse-on:       #f2f1e5;

  /* ---- colour: ink ---- */
  --on-surface:       #1b1c15;
  --on-surface-var:   #59413a;
  --outline:          #8d7168;
  --outline-var:      #e1bfb5;

  /* ---- colour: accent ---- */
  --primary:          #9b2f00;
  --primary-ctr:      #c2410c;
  --on-primary:       #ffffff;
  --primary-fixed-dim:#ffb59d;
  --secondary:        #855300;
  --tertiary:         #4c5665;
  --error:            #ba1a1a;
  --error-ctr:        #ffdad6;
  --on-error-ctr:     #93000a;

  /* Hairlines at two strengths: the section rules are quieter than the ones
     that outline a card, or a page of stacked sections reads as a table. */
  --rule:      rgba(225, 191, 181, .55);
  --rule-soft: rgba(133, 83, 0, .10);

  /* ---- type ---- */
  --serif: "Literata", "Iowan Old Style", Georgia, "Times New Roman", serif;
  --sans:  "Be Vietnam Pro", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;

  --fs-caption:  0.75rem;    /* 12 / 16 */
  --fs-label:    0.875rem;   /* 14 / 20, uppercase, +0.05em */
  --fs-body:     1rem;       /* 16 / 24 */
  --fs-body-lg:  1.125rem;   /* 18 / 28 */
  --fs-title:    1.25rem;    /* 20 / 28 */
  --fs-head-sm:  1.5rem;     /* 24 / 32 */
  --fs-head-md:  clamp(1.75rem, 1.6rem + 0.64vw, 2rem);      /* 28 → 32 */
  --fs-display:  clamp(2.25rem, 1.94rem + 1.33vw, 3rem);     /* 36 → 48 */

  --tracking-label: 0.05em;
  --tracking-wide:  0.14em;

  /* ---- space (DESIGN.md scale, unchanged) ---- */
  --sp-xs:   4px;
  --sp-base: 8px;
  --sp-sm:   12px;
  --sp-md:   24px;
  --sp-lg:   48px;
  --sp-xl:   80px;
  --gutter-grid: 24px;

  /* Section rhythm. Reaches the spec's 80px at desktop and eases off on a
     phone, where 80px top and bottom is a third of the viewport. */
  --sp-section: clamp(3.5rem, 2.879rem + 2.65vw, 5rem);      /* 56 → 80 */

  /* ---- layout ---- */
  --content: 1280px;
  --measure: 42rem;   /* ≈68 characters — reading column */
  --narrow:  34rem;   /* centred display text, never past ~3 lines */
  --page-pad: 16px;   /* 4-col mobile; stepped up at the breakpoints below */

  /* ---- shape (DESIGN.md prose: cards/inputs 4px, media 8px) ---- */
  --radius:    0.25rem;
  --radius-lg: 0.5rem;
  --radius-xl: 0.75rem;

  /* ---- depth ---- */
  --lift:  0 12px 24px rgba(194, 65, 12, .08);
  --lift-lg: 0 16px 32px rgba(155, 47, 0, .10);
  /* Transparent outline + double ring: box-shadow vanishes in Windows
     forced-colors mode, where the recoloured outline is all that survives. */
  --ring: 0 0 0 2px var(--surface), 0 0 0 4px var(--primary);

  --ease: .16s ease;
}

@media (min-width: 48em)  { :root { --page-pad: 32px; } }   /* 768 — 8 col  */
@media (min-width: 64em)  { :root { --page-pad: 64px; } }   /* 1024 — 12 col */

/* ==========================================================================
   Base
   ========================================================================== */

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

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
  /* Anchored jumps (#gallery, #contact) must clear the sticky header. */
  scroll-padding-top: 6rem;
}

body {
  margin: 0;
  background: var(--surface);
  color: var(--on-surface);
  font-family: var(--sans);
  font-size: var(--fs-body);
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  overflow-x: hidden;
}

img, svg, video { max-width: 100%; height: auto; display: block; }

a { color: var(--primary); text-underline-offset: 0.18em; transition: color var(--ease); }
a:hover { color: var(--primary-ctr); }

:focus-visible { outline: 3px solid transparent; box-shadow: var(--ring); border-radius: 2px; }

h1, h2, h3, h4 {
  font-family: var(--serif);
  font-weight: 600;
  color: var(--on-surface);
  margin: 0;
  text-wrap: balance;
}

p { margin: 0; }
/* The testimonial band is figure > blockquote > figcaption, which is the right
   structure for a quotation with an attribution and the one place the browser's
   default margins would fight the flex gaps. */
figure, blockquote { margin: 0; }

.prose > * + * { margin-top: var(--sp-md); }
.prose { max-width: var(--measure); margin-inline: auto; }

.skip-link {
  position: absolute;
  left: -9999px;
  top: var(--sp-base);
  background: var(--primary);
  color: var(--on-primary);
  padding: var(--sp-sm) var(--sp-md);
  border-radius: var(--radius);
  z-index: 100;
}
.skip-link:focus { left: var(--sp-base); color: var(--on-primary); }

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: .01ms !important;
    transition-duration: .01ms !important;
    scroll-behavior: auto !important;
  }
  /* Zeroing the duration stops the animation, not the movement — the lifts
     and zooms must also not happen at all. */
  .btn:hover, .btn:active,
  .card:hover, .card:focus-within,
  .ethos-card:hover,
  .frame:hover .frame__img { transform: none; }
}

/* ==========================================================================
   Layout primitives
   ========================================================================== */

.shell {
  width: 100%;
  max-width: var(--content);
  margin-inline: auto;
  padding-inline: var(--page-pad);
}

/* A band is full-bleed; the shell inside holds content to the grid. */
.band { padding-block: var(--sp-section); }
.band--tight { padding-block: calc(var(--sp-section) * .7); }

/* Tonal layers, not shadows — Level 0 is the body, Level 1 these washes. */
.band--paper  { background: var(--surface-low); }
.band--white  { background: var(--surface-lowest); }
.band--ink    { background: var(--inverse-surface); color: var(--inverse-on); }
.band--ink h2, .band--ink h3 { color: var(--inverse-on); }
.band--ink p, .band--ink .lede { color: rgba(242, 241, 229, .78); }

/* Hairline between two sections that share a background, so the page reads
   as an edited column rather than one long scroll. */
.band + .band,
.band + .band--white,
.band--white + .band { border-top: 1px solid var(--rule); }
.band--ink + .band, .band + .band--ink { border-top: 0; }

/* ==========================================================================
   ALIGNMENT
   ==========================================================================
   ONE RULE: alignment is a property of the SECTION, not of the element.

   CENTRED — short, announcement-like, never past ~3 lines.
       section intros · facts · steps · philosophy · gallery head · closing CTA
   LEFT, IN A CENTRED COLUMN — anything you actually read.
       hero · ethos · about prose · service rows · FAQ · card interiors · form

   The hero is LEFT in this design, unlike the previous build: it is now a
   two-column split, and centred text in a half-width column is unreadable.
   ========================================================================== */

.h1 { font-size: var(--fs-display); line-height: 1.16; letter-spacing: -0.02em; font-weight: 700; }
.h2 { font-size: var(--fs-head-md); line-height: 1.25; }
.h3 { font-size: var(--fs-head-sm); line-height: 1.33; }
.h4 { font-size: var(--fs-title); line-height: 1.4; font-family: var(--sans); font-weight: 600; }

/* Section headings are terracotta — the one place the brand colour carries
   type, and it measures 7.2:1 on cream. */
.section-head .h2,
.band > .shell > .h2 { color: var(--primary); }

.lede {
  font-size: var(--fs-body-lg);
  line-height: 1.62;
  color: var(--on-surface-var);
  max-width: var(--measure);
  text-wrap: pretty;
}

.eyebrow,
.label {
  font-family: var(--sans);
  font-size: var(--fs-label);
  font-weight: 600;
  line-height: 1.43;
  text-transform: uppercase;
  letter-spacing: var(--tracking-label);
  color: var(--secondary);
}
.eyebrow { display: block; }

.micro { font-size: var(--fs-label); line-height: 1.55; color: var(--on-surface-var); }
.band--ink .micro { color: rgba(242, 241, 229, .7); }

/* Centred sections, declared once. */
.section-head,
.facts__grid,
.steps,
.creed,
.cta-band > .shell,
.testimonials__head { text-align: center; }

.section-head > * { margin-inline: auto; }
.section-head { margin-bottom: var(--sp-lg); }
.section-head .h2 + .lede { margin-top: var(--sp-sm); }
.section-head .h2 { max-width: 26ch; }
.section-head .lede { max-width: var(--measure); }

/* ==========================================================================
   The "aperture" grain overlay
   A fractal-noise SVG at 15%, over every large photograph. It earns its place
   twice over now the photography is the client's own: thirty phone pictures
   taken across years, kitchens and light sources are pulled into one
   sun-drenched set, and the grain hides the softness of the smaller files.
   Inline data URI — no request, no asset.
   ========================================================================== */

.grain::after {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  opacity: .15;
  background-image: url('data:image/svg+xml;utf8,%3Csvg viewBox="0 0 200 200" xmlns="http://www.w3.org/2000/svg"%3E%3Cfilter id="n"%3E%3CfeTurbulence type="fractalNoise" baseFrequency="0.65" numOctaves="3" stitchTiles="stitch"/%3E%3C/filter%3E%3Crect width="100%25" height="100%25" filter="url(%23n)"/%3E%3C/svg%3E');
}

/* ==========================================================================
   Icons
   Inline SVG rather than the mock-up's Material Symbols webfont: five glyphs
   are not worth a second font request, and an icon font that fails to load
   leaves ligature text ("restaurant_menu") in the page.
   ========================================================================== */

.icon {
  width: 1em;
  height: 1em;
  flex: none;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.75;
  stroke-linecap: round;
  stroke-linejoin: round;
}
.icon--lg { width: 2rem; height: 2rem; stroke-width: 1.5; color: var(--primary); }
.icon--tick { width: 1rem; height: 1rem; color: var(--secondary); margin-top: .28em; }
.icon--quote { width: 2.25rem; height: 2.25rem; color: var(--secondary); opacity: .5; fill: currentColor; stroke: none; }

/* ==========================================================================
   Buttons
   Solid terracotta fill, cream text. A 0.98 scale on press, not a lift —
   the design brief asks for tactile feedback, and pressing something down
   is what tactile means.
   ========================================================================== */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--sp-base);
  background: var(--primary-ctr);
  color: var(--on-primary);
  font-family: var(--sans);
  font-size: var(--fs-label);
  font-weight: 600;
  line-height: 1.43;
  letter-spacing: var(--tracking-label);
  text-transform: uppercase;
  text-decoration: none;
  padding: var(--sp-sm) var(--sp-lg);
  border: 1px solid var(--primary-ctr);
  border-radius: var(--radius);
  cursor: pointer;
  transition: background-color var(--ease), border-color var(--ease), color var(--ease), transform var(--ease);
}
.btn:hover {
  background: var(--primary);
  border-color: var(--primary);
  color: var(--on-primary);
}
.btn:active { transform: scale(.98); }

.btn--ghost {
  background: transparent;
  color: var(--primary);
  border-color: var(--primary);
}
.btn--ghost:hover { background: transparent; border-color: var(--primary-ctr); color: var(--primary-ctr); }

.band--ink .btn { background: var(--primary-ctr); border-color: var(--primary-ctr); color: var(--on-primary); }
.band--ink .btn:hover { background: var(--inverse-on); border-color: var(--inverse-on); color: var(--inverse-surface); }

/* ==========================================================================
   Header
   Sticky rather than the mock-up's `fixed` + a body top-padding: same result,
   without a magic number that has to be kept in step with the bar's height.
   ========================================================================== */

.site-header {
  position: sticky;
  top: 0;
  z-index: 40;
  border-bottom: 1px solid var(--rule-soft);
}

/*
 * The frosted bar is painted by a PSEUDO-ELEMENT, not by .site-header itself, and that
 * is load-bearing rather than decorative.
 *
 * backdrop-filter (like filter and transform) makes an element a containing block for
 * any position:fixed DESCENDANT. With the blur on .site-header, the mobile nav panel —
 * which is position:fixed with inset:4rem 0 0 — resolved those offsets against the 64px
 * header instead of against the viewport, and collapsed from a full-screen panel to a
 * 49px sliver. A ::before is not an ancestor of .nav, so the blur lands in the same
 * place visually and the panel gets the viewport back.
 *
 * z-index:-1 keeps it behind the header's own content; .site-header's z-index:40 opens
 * a stacking context, so it cannot slide behind the page.
 */
.site-header::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  background: color-mix(in srgb, var(--surface) 90%, transparent);
  -webkit-backdrop-filter: blur(16px);
  backdrop-filter: blur(16px);
}
/* color-mix is unsupported below Safari 16.2 / Firefox 113 — those get an
   opaque cream bar, which is the same bar without the translucency. */
@supports not (background: color-mix(in srgb, red 50%, transparent)) {
  .site-header::before { background: var(--surface); }
}

.site-header__inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-md);
  min-height: 5rem;
}

.brand {
  display: flex;
  align-items: center;
  gap: var(--sp-base);
  text-decoration: none;
  color: var(--primary);
  min-width: 0;
}
/* The badge artwork is a navy seal on an opaque white square. Cropping it to
   a circle — as the mock-up does — clips the corners that would otherwise
   show as a white tile on the cream bar. */
.brand__mark {
  width: 2.5rem;
  height: 2.5rem;
  flex: none;
  border-radius: 50%;
  object-fit: cover;
}
.brand__name {
  font-family: var(--serif);
  font-size: var(--fs-head-sm);
  font-weight: 600;
  line-height: 1.1;
  letter-spacing: -0.01em;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.nav__list {
  list-style: none;
  display: flex;
  align-items: center;
  gap: var(--sp-lg);
  margin: 0;
  padding: 0;
}
.nav__list a {
  color: var(--on-surface-var);
  text-decoration: none;
  /* A navigation item that wraps is a navigation item that has broken. "Request
     a Date" is styled as a button, so wrapping it split the label across three
     lines INSIDE the button and pushed the header off its 80px rhythm. */
  white-space: nowrap;
  font-size: var(--fs-label);
  font-weight: 600;
  letter-spacing: var(--tracking-label);
  text-transform: uppercase;
  transition: color var(--ease);
}
.nav__list a:hover { color: var(--secondary); }
/* .is-current is the scroll spy's (site.js); the two core classes cover the one item
   that is a real page link. They get the same treatment because to the visitor they
   mean the same thing: this is where you are. */
.nav__list a.is-current,
.nav__list .current-menu-item > a,
.nav__list .current_page_item > a {
  color: var(--primary);
  box-shadow: inset 0 -2px 0 var(--primary-ctr);
}

/* The last nav item is the booking link — it carries button weight. */
.nav__list li:last-child a {
  background: var(--primary-ctr);
  color: var(--on-primary);
  padding: var(--sp-sm) var(--sp-lg);
  border: 1px solid var(--primary-ctr);
  border-radius: var(--radius);
  box-shadow: none;
  transition: background-color var(--ease), color var(--ease), transform var(--ease);
}
.nav__list li:last-child a:hover { background: var(--primary); border-color: var(--primary); color: var(--on-primary); }
.nav__list li:last-child a:active { transform: scale(.98); }

/* The two rules above out-specify the global :focus-visible ring and would
   silently strip it from the header's most important control. */
.nav__list li:last-child a:focus-visible { box-shadow: var(--ring); }
.nav__list a.is-current:focus-visible,
.nav__list .current-menu-item > a:focus-visible,
.nav__list .current_page_item > a:focus-visible { box-shadow: inset 0 -2px 0 var(--primary-ctr), var(--ring); }

.nav-toggle {
  display: none;
  width: 2.75rem;
  height: 2.75rem;
  padding: 0;
  background: transparent;
  border: 1px solid var(--outline-var);
  border-radius: var(--radius);
  cursor: pointer;
}
.nav-toggle__bars,
.nav-toggle__bars::before,
.nav-toggle__bars::after {
  display: block;
  width: 1.15rem;
  height: 2px;
  background: var(--primary);
  margin-inline: auto;
  transition: transform .18s ease, opacity .18s ease;
}
.nav-toggle__bars { position: relative; }
.nav-toggle__bars::before,
.nav-toggle__bars::after { content: ""; position: absolute; left: 0; }
.nav-toggle__bars::before { top: -6px; }
.nav-toggle__bars::after  { top: 6px; }

/* ==========================================================================
   Hero — two-column split
   ========================================================================== */

.hero { padding-block: var(--sp-section); }
.hero__inner {
  display: grid;
  grid-template-columns: 1fr 1fr;
  align-items: center;
  gap: var(--sp-xl);
  /* Capped as well as proportional. 72vh alone is right on a laptop and absurd on a
     tall portrait monitor, where it reserves most of a metre of screen for one
     sentence and pushes the first service card off the bottom of the world. */
  min-height: min(72vh, 44rem);
}
.hero__copy { display: flex; flex-direction: column; gap: var(--sp-md); align-items: flex-start; }
.hero .h1 { max-width: 14ch; }
.hero .lede { max-width: 34rem; }
.hero__actions { display: flex; flex-wrap: wrap; gap: var(--sp-md); padding-top: var(--sp-base); }
.hero .micro { max-width: 34rem; }

.hero__media {
  position: relative;
  height: clamp(24rem, 18rem + 24vw, 43.75rem);   /* 384 → 700 */
  border-radius: var(--radius-lg);
  overflow: hidden;
  border: 1px solid var(--outline-var);
  background: var(--surface-high);
}
.hero__photo { width: 100%; height: 100%; object-fit: cover; }

/* ==========================================================================
   Facts strip
   ========================================================================== */

.facts { padding-block: var(--sp-lg); border-top: 1px solid var(--rule); }
.facts__grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: var(--sp-md) var(--sp-lg);
}
.fact__label {
  display: block;
  font-family: var(--serif);
  font-size: var(--fs-title);
  font-weight: 600;
  color: var(--primary);
  line-height: 1.3;
  margin-bottom: var(--sp-xs);
}
.fact__note { font-size: var(--fs-label); color: var(--on-surface-var); line-height: 1.5; }

/* ==========================================================================
   Ethos — 12-column editorial split, heading in the left 4
   ========================================================================== */

.ethos {
  display: grid;
  grid-template-columns: repeat(12, 1fr);
  gap: var(--gutter-grid);
}
.ethos__head { grid-column: span 4; }
.ethos__head .h2 { color: var(--primary); margin-bottom: var(--sp-md); }
.ethos__head .label { letter-spacing: var(--tracking-wide); }
.ethos__body { grid-column: span 8; }

.ethos__cards {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: var(--sp-lg);
  margin-top: var(--sp-xl);
}
.ethos-card {
  background: var(--surface-low);
  border: 1px solid var(--outline-var);
  border-radius: var(--radius);
  padding: var(--sp-md);
  transition: box-shadow var(--ease), transform var(--ease);
}
.ethos-card:hover { box-shadow: var(--lift); transform: translateY(-2px); }
.ethos-card .icon--lg { margin-bottom: var(--sp-sm); }
.ethos-card__title { font-size: var(--fs-title); font-family: var(--sans); margin-bottom: var(--sp-sm); }
.ethos-card p { color: var(--on-surface-var); }

/* ==========================================================================
   About
   Portrait beside the bio, on the same 12-column editorial grid as the ethos
   band above it — 5 and 7, so the text column stays close to the reading
   measure instead of running the full 1280.
   ========================================================================== */

.about {
  display: grid;
  grid-template-columns: repeat(12, 1fr);
  gap: var(--sp-lg);
  align-items: start;
}
.about__media {
  grid-column: span 5;
  position: relative;
  border-radius: var(--radius-lg);
  overflow: hidden;
  border: 1px solid var(--outline-var);
  background: var(--surface-high);
}
/* 3:4 fixed, because the portrait is a placeholder that will be swapped for a
   real photograph of unknown shape and the column must not change height. */
.about__photo { width: 100%; aspect-ratio: 3 / 4; object-fit: cover; }

.about__body { grid-column: span 7; }
.about__body .h2 { color: var(--primary); margin-bottom: var(--sp-base); }
.about__body .label { display: block; letter-spacing: var(--tracking-wide); margin-bottom: var(--sp-md); }
.about__body .lede { margin-bottom: var(--sp-md); }
.about__prose > p { color: var(--on-surface-var); max-width: var(--measure); }
.about__prose > p + p { margin-top: var(--sp-md); }

/* ==========================================================================
   Offerings — service cards
   Two across, not four. There are four real services and a 1280px shell
   splits four ways at 296px, which turns each card into a 700px column of
   text. Two rows of two keeps the measure readable.
   ========================================================================== */

.cards {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: var(--sp-lg);
}
.card {
  position: relative;          /* anchor for the stretched button link */
  display: flex;
  flex-direction: column;
  gap: var(--sp-md);
  background: var(--surface-ctr);
  border: 1px solid var(--outline-var);
  border-radius: var(--radius-xl);
  padding: var(--sp-lg);
  transition: box-shadow .3s ease, transform .3s ease;
}
.card:hover,
.card:focus-within { box-shadow: var(--lift-lg); transform: translateY(-4px); }

/* The hover treatment promises the whole card is clickable — make it true.
   The button is the card's only link, so stretching it is safe. */
.card .btn::after { content: ""; position: absolute; inset: 0; }

.card__media {
  position: relative;
  height: 12rem;
  border-radius: var(--radius-lg);
  overflow: hidden;
  background: var(--surface-high);
}
.card__photo { width: 100%; height: 100%; object-fit: cover; transition: transform .7s ease; }
.card:hover .card__photo { transform: scale(1.05); }

/* One gap value for the whole card interior, then two explicit overrides: the meta
   line belongs to the heading above it, and the button is pushed to the floor so
   every card's action sits on the same baseline whatever its text length. */
.card__body { display: flex; flex-direction: column; gap: var(--sp-sm); flex: 1; }
.card__name { font-size: var(--fs-head-sm); color: var(--on-surface); }
.card__meta {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: var(--sp-base);
}
.card__blurb, .card .ticks { margin-top: var(--sp-base); }
.card__price {
  font-size: var(--fs-caption);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: var(--tracking-label);
  color: var(--secondary);
}
.card__note { font-size: var(--fs-label); color: var(--on-surface-var); }
.card__blurb { color: var(--on-surface-var); flex-grow: 1; }

/* Ingredient-list bullets: the design brief asks for a solid terracotta
   square. The service ticks use the check glyph instead — they are claims,
   not ingredients — and the square is kept for the prose lists. */
.ticks { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--sp-base); }
.ticks li {
  display: flex;
  align-items: flex-start;
  gap: var(--sp-base);
  font-size: var(--fs-body);
  color: rgba(89, 65, 58, .82);
  line-height: 1.5;
}

.card .btn { margin-top: auto; align-self: flex-start; }

/* ==========================================================================
   Steps
   ========================================================================== */

.steps {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: var(--sp-lg);
}
.step__num {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 2.75rem;
  height: 2.75rem;
  border-radius: 50%;
  background: var(--primary);
  color: var(--on-primary);
  font-family: var(--serif);
  font-size: var(--fs-title);
  margin: 0 auto var(--sp-md);
}
.step__title { margin-bottom: var(--sp-base); }
.step p { font-size: var(--fs-body); color: var(--on-surface-var); margin-inline: auto; max-width: 32ch; }

/* A photograph above each step. 4:3 rather than the strips' 4:5, because three
   of these sit in a row across the full band and portrait boxes at that width
   would push the numbered heading below the fold on a laptop.

   The number then overlaps the photo's bottom edge — it is the step's marker,
   and floating it half onto the picture ties the two together instead of
   leaving a disc stranded in the gap. Needs the negative margin AND a stacking
   context, or the grain overlay paints over it. */
.step--photo { display: flex; flex-direction: column; }
.step__media {
  position: relative;
  overflow: hidden;
  border-radius: var(--radius-lg);
  background: var(--surface-high);
  margin-bottom: var(--sp-md);
}
.step__img {
  display: block;
  width: 100%;
  aspect-ratio: 4 / 3;
  object-fit: cover;
  transition: transform .7s ease;
}
.step--photo:hover .step__img { transform: scale(1.05); }
.step--photo .step__num {
  position: relative;
  z-index: 1;
  margin-top: calc(var(--sp-md) * -1 - 1.375rem);
  margin-bottom: var(--sp-md);
  box-shadow: var(--lift-lg);
}

/* ==========================================================================
   Chips — consulting role tags
   Soft cream ground, 1px terracotta border, label type. Seven near-identical
   job titles read as a tag cloud, not as seven sentences.
   ========================================================================== */

.chips {
  list-style: none;
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-base);
  margin: var(--sp-md) 0 0;
  padding: 0;
}
.chips li {
  font-size: var(--fs-label);
  font-weight: 600;
  letter-spacing: var(--tracking-label);
  color: var(--primary);
  background: var(--surface);
  border: 1px solid var(--outline-var);
  border-radius: 999px;
  padding: 0.35em 0.9em;
  line-height: 1.4;
}
.chips__label + .chips { margin-top: var(--sp-base); }
.chips--center { justify-content: center; max-width: var(--measure); margin-inline: auto; }

.section-head:has(+ .chips--center) { margin-bottom: var(--sp-md); }
.chips--center + .band__cta { margin-top: var(--sp-lg); }

.band__cta { margin-top: var(--sp-lg); text-align: center; }
.cta-band .band__cta { margin-top: 0; }

/* ==========================================================================
   Gallery
   ========================================================================== */

.gallery__head { margin-bottom: var(--sp-lg); }
.gallery__head .h2 { color: var(--primary); margin-bottom: var(--sp-base); }
.gallery__head .label { letter-spacing: var(--tracking-wide); }

/* auto-fill, not repeat(4): how many photographs the client has is his business, not
   the grid's. A fixed four columns quietly made "keep the total a multiple of four" a
   rule somebody had to remember on every addition, and forgetting it left a hole in the
   last row. This lays out whatever it is given — four across a desktop, two on a tablet,
   and a short last row simply reads as a short last row. */
.gallery__grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(15rem, 1fr));
  gap: var(--sp-md);
}
.frame {
  position: relative;
  height: 20rem;
  border-radius: var(--radius-lg);
  overflow: hidden;
  background: var(--surface-high);
}
.frame__img { width: 100%; height: 100%; object-fit: cover; transition: transform .7s ease; }
.frame:hover .frame__img { transform: scale(1.05); }

/* ==========================================================================
   Photo strips
   Three bands carry a row of photographs rather than one: the garden under
   Philosophy, Chef Lupe working under About, and the kitchen beside the
   consulting band. Same component, three widths.

   All three are PORTRAIT boxes, and that is not a style choice — 30 of the 36
   photographs the client sent are 3:4 phone shots. A landscape box would crop
   two thirds of every one of them away. 4:5 is the compromise: near enough to
   the source that little is lost, wide enough that a row of them does not
   turn a band into a column.
   ========================================================================== */

.produce,
.chefstrip,
.opsstrip {
  display: grid;
  gap: var(--sp-md);
}

.produce__item,
.chefstrip__item,
.opsstrip__item {
  position: relative;          /* anchor for .grain::after */
  overflow: hidden;
  border-radius: var(--radius-lg);
  background: var(--surface-high);
}

.produce__img,
.chefstrip__img,
.opsstrip__img {
  display: block;
  width: 100%;
  aspect-ratio: 4 / 5;
  object-fit: cover;
  transition: transform .7s ease;
}

.produce__item:hover .produce__img,
.chefstrip__item:hover .chefstrip__img,
.opsstrip__item:hover .opsstrip__img { transform: scale(1.05); }

/* The garden strip closes the Philosophy band, so it wants air above it and
   none below — the band's own padding finishes the job. */
.produce {
  grid-template-columns: repeat(4, 1fr);
  margin-top: var(--sp-lg);
}

/* Sits under the bio inside the About text column, which is narrower than the
   band. Three shorter frames: at this width 4:5 would push the fold. */
.chefstrip {
  grid-template-columns: repeat(3, 1fr);
  margin-top: var(--sp-lg);
}
.chefstrip__img { aspect-ratio: 1 / 1; }

/* Two photographs under centred copy, so the strip is centred too and held to
   the reading measure — full width would make two pictures look like a gap. */
.opsstrip {
  grid-template-columns: repeat(2, 1fr);
  max-width: var(--measure);
  margin: var(--sp-lg) auto 0;
}

/* ==========================================================================
   Testimonials
   ========================================================================== */

.testimonials__head { margin-bottom: var(--sp-xl); }
.testimonials__head .h2 { color: var(--primary); }
.testimonials__grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: var(--sp-xl);
}
.quote { display: flex; flex-direction: column; gap: var(--sp-md); height: 100%; }
.quote__body { font-size: var(--fs-body-lg); line-height: 1.62; font-style: italic; color: var(--on-surface); }
.quote__who { margin-top: auto; }
.quote__name {
  display: block;
  font-family: var(--sans);
  font-size: var(--fs-title);
  font-weight: 600;
  color: var(--on-surface-var);
}
.quote__role {
  display: block;
  font-size: var(--fs-label);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: var(--tracking-label);
  color: var(--secondary);
}

/* ==========================================================================
   Philosophy creed — the dark band
   Chef Lupe's own four lines, verbatim. The rule between them is the one
   place a light salmon is used: terracotta on charcoal is invisible.
   ========================================================================== */

.creed { max-width: 42ch; margin-inline: auto; }
.creed__label {
  font-family: var(--sans);   /* an h2 for the outline, not for the type */
  font-size: var(--fs-label);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: var(--tracking-wide);
  color: rgba(242, 241, 229, .7);
  margin-bottom: var(--sp-lg);
}
.creed__list { list-style: none; margin: 0; padding: 0; }
.creed__list li {
  font-family: var(--serif);
  font-size: var(--fs-head-sm);
  line-height: 1.4;
  color: var(--inverse-on);
}
.creed__list li + li { margin-top: var(--sp-md); }
.creed__list li + li::before {
  content: "";
  display: block;
  width: 28px;
  height: 2px;
  background: var(--primary-fixed-dim);
  margin: 0 auto var(--sp-md);
}
.creed__list li:last-child { font-style: italic; }

/* (.creed--inline lived here for the About PAGE's copy of this block. The page is
   retired — the bio is the #about section of the front page now, and the creed appears
   once, in the dark band above. Nothing rendered those rules any more.) */

/* ==========================================================================
   FAQ
   Read, not announced: left aligned inside a centred column.
   ========================================================================== */

.faq { max-width: var(--measure); margin-inline: auto; text-align: left; }
.faq details { border-bottom: 1px solid var(--rule); }
.faq summary {
  list-style: none;
  cursor: pointer;
  position: relative;
  padding: var(--sp-md) var(--sp-lg) var(--sp-md) 0;
  font-family: var(--sans);
  font-weight: 600;
  color: var(--on-surface);
  transition: color var(--ease);
}
.faq summary:hover { color: var(--primary); }
.faq summary::-webkit-details-marker { display: none; }
.faq summary::after {
  content: "";
  position: absolute;
  right: var(--sp-xs);
  top: 50%;
  width: 12px;
  height: 2px;
  background: var(--primary-ctr);
  transform: translateY(-50%);
}
.faq summary::before {
  content: "";
  position: absolute;
  right: calc(var(--sp-xs) + 5px);
  top: 50%;
  width: 2px;
  height: 12px;
  background: var(--primary-ctr);
  transform: translateY(-50%);
  transition: opacity var(--ease), transform var(--ease);
}
/* The + folds into a − by rotating its vertical bar away, not just fading. */
.faq details[open] summary::before { opacity: 0; transform: translateY(-50%) rotate(90deg); }
.faq details p { padding-bottom: var(--sp-md); color: var(--on-surface-var); max-width: 62ch; }

/* ==========================================================================
   Contact form
   A real form: nonce, honeypot, server-side validation, wp_mail. The mock-up
   shipped a <button type="button"> that did nothing.
   ========================================================================== */

.contact-card {
  background: var(--surface-ctr);
  border: 1px solid var(--outline-var);
  border-radius: var(--radius-xl);
  padding: var(--sp-lg);
  max-width: 56rem;
  margin-inline: auto;
}
.contact-card__head { text-align: center; margin-bottom: var(--sp-lg); }
.contact-card__head .h2 { color: var(--primary); margin-bottom: var(--sp-sm); }
.contact-card__head .lede { margin-inline: auto; }

.form {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: var(--sp-md);
}
.field { display: flex; flex-direction: column; gap: var(--sp-sm); }
.field--wide { grid-column: 1 / -1; }
.field > label {
  font-size: var(--fs-label);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: var(--tracking-label);
  color: var(--on-surface-var);
}

.field input,
.field select,
.field textarea {
  font-family: var(--sans);
  font-size: var(--fs-body);
  line-height: 1.5;
  color: var(--on-surface);
  background: var(--surface);
  border: 1px solid var(--outline-var);
  border-radius: var(--radius);
  padding: var(--sp-sm);
  width: 100%;
  transition: border-color var(--ease), box-shadow var(--ease);
}
.field textarea { min-height: 9.375rem; resize: vertical; }
.field select {
  appearance: none;
  /* Chevron drawn in the background so the control keeps one border in every
     browser — a native select on macOS otherwise ignores the border entirely. */
  background-image: url('data:image/svg+xml;utf8,%3Csvg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="%2359413a" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"%3E%3Cpath d="m6 9 6 6 6-6"/%3E%3C/svg%3E');
  background-repeat: no-repeat;
  background-position: right var(--sp-sm) center;
  background-size: 1.125rem;
  padding-right: calc(var(--sp-md) + var(--sp-md));
}
.field input:focus,
.field select:focus,
.field textarea:focus {
  outline: none;
  border-color: var(--primary);
  box-shadow: 0 0 0 1px var(--primary);
}
.field input::placeholder,
.field textarea::placeholder { color: rgba(89, 65, 58, .55); }

/* Invalid fields are marked with a border AND a message — colour alone is not
   an accessible error state. */
.field--invalid input,
.field--invalid textarea { border-color: var(--error); }
.field__error { font-size: var(--fs-label); color: var(--on-error-ctr); }

.form__actions { grid-column: 1 / -1; display: flex; justify-content: center; margin-top: var(--sp-sm); }
.form__actions .btn { background: var(--primary); border-color: var(--primary); }
.form__actions .btn:hover { background: var(--primary-ctr); border-color: var(--primary-ctr); }

/* Honeypot. Off-screen rather than display:none — some bots skip hidden
   inputs, and a real user never reaches it because it is aria-hidden and
   removed from the tab order. */
.form__trap {
  position: absolute;
  left: -9999px;
  width: 1px;
  height: 1px;
  overflow: hidden;
}

.notice {
  border-radius: var(--radius);
  padding: var(--sp-sm) var(--sp-md);
  margin-bottom: var(--sp-md);
  font-size: var(--fs-body);
  border: 1px solid transparent;
}
.notice--ok    { background: var(--surface-low); border-color: var(--secondary); color: var(--on-surface); }
.notice--error { background: var(--error-ctr); border-color: var(--error); color: var(--on-error-ctr); }

.contact__note { text-align: center; margin-top: var(--sp-md); }

/* ==========================================================================
   Inner pages
   ========================================================================== */

.pagehead {
  padding-block: var(--sp-section) var(--sp-lg);
  border-bottom: 1px solid var(--rule);
  text-align: center;
}
.pagehead > .shell > * { margin-inline: auto; }
.pagehead .h1 { max-width: 20ch; margin-bottom: var(--sp-md); color: var(--on-surface); }
.pagehead .lede { max-width: var(--measure); }
.pagehead .micro { max-width: var(--measure); margin-top: var(--sp-md); }

/* /book/ used to be a heading and a form on an empty page.

   Held to the reading measure rather than run full-bleed, and 16:9 rather than
   the 3:1 this started as. Both for the same reason: the source is a 3:4 phone
   photograph, and `cover` scales it to fill the WIDTH, so the wider the box the
   less of the picture survives. Full-width 3:1 left an 18% band — a texture,
   not a photograph. At the measure it reads as a picture, and the booking form
   below it stays within reach of the fold, which is the page's whole job. */
.pagehead__media {
  position: relative;
  overflow: hidden;
  border-radius: var(--radius-lg);
  border: 1px solid var(--outline-var);
  background: var(--surface-high);
  max-width: var(--measure);
  margin: var(--sp-lg) auto 0;
}
.pagehead__img {
  display: block;
  width: 100%;
  aspect-ratio: 16 / 9;
  object-fit: cover;
}

/* ---- Service detail rows ---- */
.detail { max-width: var(--measure); margin-inline: auto; scroll-margin-top: 6rem; }
.detail + .detail { border-top: 1px solid var(--rule); margin-top: var(--sp-lg); padding-top: var(--sp-lg); }
.detail__media {
  position: relative;
  aspect-ratio: 3 / 1;
  overflow: hidden;
  border-radius: var(--radius-lg);
  margin-bottom: var(--sp-md);
  background: var(--surface-high);
}
.detail__photo { width: 100%; height: 100%; object-fit: cover; }
.detail__head {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--sp-sm) var(--sp-md);
  margin-bottom: var(--sp-md);
}
.detail__head .h2 { max-width: none; color: var(--primary); }
.detail__meta { display: flex; align-items: baseline; gap: var(--sp-base); }
.detail > p { max-width: var(--measure); }
.detail > p + p { margin-top: var(--sp-sm); }
.detail__terms {
  margin-top: var(--sp-md);
  font-size: var(--fs-label);
  color: var(--on-surface-var);
  padding-top: var(--sp-sm);
  border-top: 1px dashed var(--outline-var);
}

/* ---- Closing band ---- */
.cta-band .h2 { margin-inline: auto; margin-bottom: var(--sp-sm); color: var(--primary); }
.cta-band p { margin-inline: auto; max-width: 48ch; margin-bottom: var(--sp-lg); }

/* ==========================================================================
   Footer
   ========================================================================== */

.site-footer {
  background: var(--surface-lowest);
  border-top: 1px solid var(--rule-soft);
  padding-block: var(--sp-section);
  text-align: center;
}
.site-footer__inner { display: grid; justify-items: center; gap: var(--sp-md); }
/* The full lockup sits on white because the artwork has an opaque white
   background rather than transparency — which is why this band is white and
   not the page's cream. */
.site-footer__logo { width: min(220px, 60vw); height: auto; }
.site-footer__name { font-family: var(--serif); font-size: var(--fs-head-md); color: var(--primary); }

.site-footer__links {
  list-style: none;
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: var(--sp-lg);
  margin: 0;
  padding: 0;
}
.site-footer__links a {
  font-size: var(--fs-label);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: var(--tracking-label);
  color: var(--tertiary);
  text-decoration: none;
  transition: color .3s ease;
}
.site-footer__links a:hover { color: var(--primary); }

.site-footer__nav .nav__list { flex-wrap: wrap; justify-content: center; gap: var(--sp-lg); }
/* The header's button treatment on the last item would be noise down here. */
.site-footer__nav .nav__list li:last-child a {
  background: none;
  border-color: transparent;
  color: var(--tertiary);
  padding: 0;
}
.site-footer__nav .nav__list li:last-child a:hover { background: none; color: var(--primary); }
.site-footer__nav .nav__list a { color: var(--tertiary); }
.site-footer__nav .nav__list .current-menu-item > a,
.site-footer__nav .nav__list .current_page_item > a { box-shadow: none; color: var(--primary); }

.site-footer__legal {
  font-size: var(--fs-body);
  color: var(--on-surface-var);
  opacity: .8;
  max-width: 28rem;
  margin-inline: auto;
}

/* ==========================================================================
   Gutenberg blocks
   The main pages are rendered from content.php as plain semantic markup, so
   only the blocks WordPress itself creates — the draft privacy policy, and
   anything added in wp-admin later — need styling.
   ========================================================================== */

.page-content > :is(.wp-block-group, p, h2, h3, ul, ol) {
  width: 100%;
  max-width: var(--measure);
  margin-inline: auto;
  padding-inline: var(--page-pad);
}
.page-content > h2 { font-size: var(--fs-head-md); margin-top: var(--sp-lg); color: var(--primary); }
.page-content > h3 { font-size: var(--fs-head-sm); margin-top: var(--sp-md); }
.page-content > p  { margin-top: var(--sp-md); color: var(--on-surface-var); }
.page-content > ul, .page-content > ol { margin-top: var(--sp-md); color: var(--on-surface-var); }
.page-content > :not(section):first-child { margin-top: var(--sp-lg); }
.page-content > :not(section):last-child  { margin-bottom: var(--sp-lg); }

/* Ingredient-style bullets: a 4px solid terracotta square, per the brief. */
.page-content > ul { list-style: none; padding-left: var(--sp-md); }
.page-content > ul > li { position: relative; padding-left: var(--sp-md); }
.page-content > ul > li::before {
  content: "";
  position: absolute;
  left: 0;
  top: .62em;
  width: 4px;
  height: 4px;
  background: var(--primary-ctr);
}

.wp-block-button__link {
  background: var(--primary-ctr);
  color: var(--on-primary);
  border-radius: var(--radius);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: var(--tracking-label);
  font-size: var(--fs-label);
  padding: var(--sp-sm) var(--sp-lg);
}
.wp-block-button__link:hover { background: var(--primary); color: var(--on-primary); }

/* ==========================================================================
   LatePoint booking form
   Scoped to .has-booking-form so none of it leaks onto the other pages. These
   overrides fight the PLUGIN's stylesheet, not a theme, so the !important is
   genuinely required. Retinted from the old navy/red pair to the terracotta
   system — the markup and the selectors are unchanged, which is what keeps
   the booking feature working across this redesign.
   ========================================================================== */

.has-booking-form .booking-wrap { max-width: 60rem; margin-inline: auto; }

.has-booking-form .latepoint-w { font-family: var(--sans); }

/* ---- Side panel ----
   Turned into one of the site's dark bands. It is the single change that
   stops the form reading as a third-party embed. */
.has-booking-form .latepoint-w .latepoint-side-panel {
  background: var(--inverse-surface) !important;
  border-radius: var(--radius-lg) 0 0 var(--radius-lg);
  padding: var(--sp-lg) var(--sp-md) !important;
}
.has-booking-form .latepoint-w .latepoint-desc-media { display: none !important; }
.has-booking-form .latepoint-w .latepoint-side-panel .latepoint-desc-title { color: var(--inverse-on) !important; }
.has-booking-form .latepoint-w .latepoint-desc-content,
.has-booking-form .latepoint-w .latepoint-side-panel p { color: rgba(242, 241, 229, .78) !important; }
.has-booking-form .latepoint-w .latepoint-side-panel a { color: var(--primary-fixed-dim) !important; }
.has-booking-form .latepoint-w .latepoint-side-panel h5 {
  color: var(--inverse-on) !important;
  font-family: var(--serif);
  font-size: var(--fs-body);
}

/* The plugin sets these with !important of its own, so matching it is the only way in.
   Its palette is a cool blue-grey (#1f222b ink, #7c85a3 secondary) which is the single
   most obviously foreign thing left on the page once the boxes are right. */
.has-booking-form .latepoint-w .os-item h3,
.has-booking-form .latepoint-w .os-item-name {
  font-family: var(--serif) !important;
  font-size: var(--fs-title) !important;
  color: var(--on-surface) !important;
}

/* Each service carries a photo (wp_latepoint_services.selection_image_id, set
   by build-site.php), which the plugin renders as a background-image here. Its
   default is a small square thumbnail; giving it real size is most of what
   makes the picker stop looking like a plugin. */
.has-booking-form .latepoint-w .os-item-img-w {
  width: 84px !important;
  height: 84px !important;
  min-width: 84px;
  border-radius: var(--radius-lg);
  background-size: cover !important;
  background-position: center;
}

/* Selectable tiles get the same ground, border and lift as the service cards
   elsewhere on the site, so the form reads as part of the page. */
.has-booking-form .latepoint-w .os-item {
  border: 1px solid var(--outline-var) !important;
  border-radius: var(--radius) !important;
  background: var(--surface-ctr) !important;
  padding: var(--sp-sm) !important;
  transition: border-color var(--ease), box-shadow var(--ease), transform var(--ease);
}
/* The plugin nests a SECOND bordered white box (.os-item-i) inside every .os-item.
   Under the old palette both boxes were white so the nesting was invisible; on a cream
   tile it shows as a box inside a box. Flatten the inner one and let the outer carry
   the whole card treatment. */
.has-booking-form .latepoint-w .os-item-i {
  background: transparent !important;
  border: 0 !important;
  border-radius: 0 !important;
  box-shadow: none !important;
}

.has-booking-form .latepoint-w .os-items > * + * { margin-top: var(--sp-sm); }
.has-booking-form .latepoint-w .os-selectable-item:hover {
  border-color: var(--primary-ctr) !important;
  box-shadow: var(--lift);
  transform: translateY(-2px);
}
.has-booking-form .latepoint-w .os-item.selected,
.has-booking-form .latepoint-w .os-item.active {
  border-color: var(--primary) !important;
  box-shadow: inset 0 0 0 1px var(--primary);
}
.has-booking-form .latepoint-w .os-item-desc {
  color: var(--on-surface-var) !important;
  font-size: var(--fs-label) !important;
  line-height: 1.5;
}

/* Headings inside the form, matched to the page's own scale. */
.has-booking-form .latepoint-w .os-heading-text {
  font-family: var(--serif);
  font-size: var(--fs-head-sm);
  color: var(--primary);
}
.has-booking-form .latepoint-w .latepoint-booking-form-element .latepoint-desc-title {
  font-family: var(--serif);
  color: var(--primary);
  font-size: var(--fs-title);
}

/* Calendar and time slots. */
.has-booking-form .latepoint-w .dp-timebox,
.has-booking-form .latepoint-w .timeslots .dp-timepicker-trigger { border-radius: var(--radius); }
.has-booking-form .latepoint-w .os-selected-date,
.has-booking-form .latepoint-w .dp-day.selected {
  background: var(--primary) !important;
  color: var(--on-primary) !important;
}

/* Form fields. */
.has-booking-form .latepoint-w input[type="text"],
.has-booking-form .latepoint-w input[type="email"],
.has-booking-form .latepoint-w input[type="tel"],
.has-booking-form .latepoint-w textarea {
  border-radius: var(--radius) !important;
  font-family: var(--sans);
  font-size: var(--fs-body);
}
.has-booking-form .latepoint-w input:focus,
.has-booking-form .latepoint-w textarea:focus {
  border-color: var(--primary) !important;
  box-shadow: var(--ring) !important;
}

/* Style the two button variants SEPARATELY. A blanket rule on .latepoint-btn
   also hits .latepoint-btn-white (the "Back" button), whose text colour stays
   dark — dark on dark reads as no button at all. Always set background AND
   colour together. */
.has-booking-form .latepoint-w .latepoint-btn {
  border-radius: var(--radius) !important;
  font-family: var(--sans);
  font-weight: 600;
  transition: background-color var(--ease), border-color var(--ease), color var(--ease);
}
.has-booking-form .latepoint-w .latepoint-btn-primary {
  background: var(--primary-ctr) !important;
  border: 1px solid var(--primary-ctr) !important;
  color: var(--on-primary) !important;
}
.has-booking-form .latepoint-w .latepoint-btn-primary:hover:not(.disabled) {
  background: var(--primary) !important;
  border-color: var(--primary) !important;
  color: var(--on-primary) !important;
}
.has-booking-form .latepoint-w .latepoint-btn-white {
  background: var(--surface-lowest) !important;
  border: 1px solid var(--outline-var) !important;
  color: var(--on-surface) !important;
}
.has-booking-form .latepoint-w .latepoint-btn-white:hover:not(.disabled) {
  border-color: var(--primary-ctr) !important;
  color: var(--primary-ctr) !important;
}
/* Icons and labels must inherit or they keep the plugin's own colour. */
.has-booking-form .latepoint-w .latepoint-btn i,
.has-booking-form .latepoint-w .latepoint-btn span { color: inherit !important; }
.has-booking-form .latepoint-w .latepoint-btn.disabled { opacity: .45; cursor: not-allowed; }

/* On phones the booking page must reach the form quickly: tighter band, and
   the consulting tags give way (they stay in the markup — they are discovery
   copy, and the visitor here has already decided). */
@media (max-width: 48em) {
  .has-booking-form .band { padding-block: var(--sp-lg); }
}
@media (max-width: 30em) {
  .has-booking-form .pagehead .chips { display: none; }
  .has-booking-form .latepoint-w .os-item-img-w { width: 64px; height: 64px; min-width: 64px; }
}

/* ==========================================================================
   Responsive
   Breakpoints in em so they respect the user's own font size.
   ========================================================================== */

/* --- Tablet: the editorial split and the four-up gallery stop working --- */
@media (max-width: 64em) {          /* 1024px */
  .hero__inner { grid-template-columns: 1fr; gap: var(--sp-lg); min-height: 0; }
  .hero__copy { order: 1; }
  .hero__media { order: 2; height: clamp(20rem, 12rem + 32vw, 31.25rem); }
  .hero .h1 { max-width: 18ch; }

  .ethos { grid-template-columns: 1fr; gap: var(--sp-md); }
  .ethos__head, .ethos__body { grid-column: 1 / -1; }
  .ethos__cards { margin-top: var(--sp-lg); }

  /* Portrait above the bio, and no longer full-bleed tall: a 3:4 image at 100%
     of a phone is most of a screen before a word has been read. */
  .about { grid-template-columns: 1fr; gap: var(--sp-md); }
  .about__media, .about__body { grid-column: 1 / -1; }
  .about__media { max-width: 22rem; }

  .gallery__grid { grid-template-columns: repeat(2, 1fr); gap: var(--sp-sm); }
  .frame { height: 16rem; }

  /* Same rule as the gallery: four across a tablet gives each photograph about
     150px, which is a thumbnail, not a picture. Two rows of two. The counts in
     content.php are multiples of four so this never leaves a hole. */
  .produce { grid-template-columns: repeat(2, 1fr); gap: var(--sp-sm); }

  .testimonials__grid { gap: var(--sp-lg); }
}

/* --- Steps carry a paragraph each, so they need width sooner than the facts.
       Below 960px they become a numbered list: marker beside the text. --- */
@media (max-width: 60em) {          /* 960px */
  .steps { grid-template-columns: 1fr; gap: var(--sp-md); max-width: var(--measure); margin-inline: auto; }
  .step { display: grid; grid-template-columns: 2.75rem 1fr; gap: var(--sp-md); align-items: start; text-align: left; }
  .step__num { margin: 0; }
  .step p { max-width: none; margin-inline: 0; }

  /* The step is a numbered list item here, and its photograph has to escape the
     2.75rem marker column or it is not a photograph any more — full width above,
     marker and text beneath. The overlap goes with it: nothing to overlap once
     the picture is wide and short. */
  .step--photo .step__media { grid-column: 1 / -1; }
  .step--photo .step__num { margin-top: 0; box-shadow: none; }
}

@media (max-width: 48em) {          /* 768px */
  .facts__grid { grid-template-columns: 1fr; gap: var(--sp-md); }
  .cards { grid-template-columns: 1fr; }
  .ethos__cards { grid-template-columns: 1fr; gap: var(--sp-md); }

  /* The strips stay in grid where everything else stacks. Two-up at 375px is
     about 165px a frame, which still reads as a photograph — and stacking a
     dozen full-width pictures would add three screens of scroll to the page
     for no gain. The chef strip keeps its three because they are square and
     already the smallest boxes on the site. */
  .produce, .opsstrip { grid-template-columns: repeat(2, 1fr); gap: var(--sp-sm); }
  .chefstrip { gap: var(--sp-sm); }
  .opsstrip { margin-top: var(--sp-md); }
  .testimonials__grid { grid-template-columns: 1fr; }
  .form { grid-template-columns: 1fr; }
  .contact-card { padding: var(--sp-md); }
  .site-footer__links, .site-footer__nav .nav__list { gap: var(--sp-md); }
}

/* --- Laptop: the nav fits, but only just ---
   The five items need about 1200px at the full 48px gap. Between the point the
   hamburger hands over (1024px) and there, the gap comes down rather than the
   items coming off — four fewer pixels of air is invisible, a collapsed menu on
   a laptop is not. */
@media (max-width: 75em) {          /* 1200px */
  .site-header .nav__list { gap: var(--sp-md); }
}

/* --- Tablet: the header runs out of room before the content does ---
   Five nav items at a 48px gap need about 1000px beside the logo. Between
   768px and 1024px they fit only by wrapping "Request a Date" onto three
   lines inside its own button, which is what used to happen. The collapse
   therefore starts at 1024px, not 768px, while everything BELOW stays on the
   768px breakpoint where it belongs — those are content rules, this is a
   header-width rule, and they were only ever coincidentally the same number. */
@media (max-width: 64em) {          /* 1024px */
  /* --- Mobile nav ---
     The toggle is as JS-gated as the collapse itself: without the script it
     would be a dead button whose aria-expanded="false" is a lie. */
  .has-js .nav-toggle { display: block; }

  /* Only collapse the menu once JS has confirmed it can reopen it, so a
     script failure cannot leave the site with no navigation at all. Every
     rule is scoped through .nav — the footer renders the same ul.nav__list,
     and unscoped these turned it into a second stacked menu. */
  .has-js .nav {
    position: fixed;
    inset: 5rem 0 0;
    background: var(--surface);
    border-top: 1px solid var(--rule);
    padding: var(--sp-md) var(--page-pad);
    transform: translateY(-100%);
    opacity: 0;
    visibility: hidden;
    transition: transform .22s ease, opacity .22s ease, visibility .22s;
    overflow-y: auto;
    overscroll-behavior: contain;
  }
  .has-js .nav .nav__list { flex-direction: column; align-items: stretch; gap: 0; }
  .has-js .nav .nav__list li + li { border-top: 1px solid var(--rule); }
  .has-js .nav .nav__list a {
    display: block;
    padding: var(--sp-md) 0;
    font-size: var(--fs-title);
    font-family: var(--serif);
    text-transform: none;
    letter-spacing: 0;
    color: var(--on-surface);
  }
  /* In the stacked panel the desktop underline would run edge to edge — the
     current page gets a left bar instead. */
  .has-js .nav .nav__list a.is-current,
  .has-js .nav .nav__list .current-menu-item > a,
  .has-js .nav .nav__list .current_page_item > a {
    box-shadow: inset 3px 0 0 var(--primary-ctr);
    padding-left: var(--sp-md);
    color: var(--primary);
  }
  .has-js .nav .nav__list a.is-current:focus-visible,
  .has-js .nav .nav__list .current-menu-item > a:focus-visible,
  .has-js .nav .nav__list .current_page_item > a:focus-visible {
    box-shadow: inset 3px 0 0 var(--primary-ctr), var(--ring);
  }
  .has-js .nav .nav__list li:last-child a {
    margin-top: var(--sp-md);
    text-align: center;
    padding: var(--sp-sm) var(--sp-lg);
    font-family: var(--sans);
    font-size: var(--fs-label);
    text-transform: uppercase;
    letter-spacing: var(--tracking-label);
    color: var(--on-primary);
  }
  .has-js .nav .nav__list li:last-child { border-top: 0; }

  .nav-open .nav { transform: translateY(0); opacity: 1; visibility: visible; }
  .nav-open { overflow: hidden; }

  .nav-open .nav-toggle__bars { background: transparent; }
  .nav-open .nav-toggle__bars::before { transform: translateY(6px) rotate(45deg); }
  .nav-open .nav-toggle__bars::after  { transform: translateY(-6px) rotate(-45deg); }
}

/* --- Small phones --- */
@media (max-width: 30em) {          /* 480px */
  .h1, .h2 { max-width: none; }
  .brand__name { font-size: var(--fs-title); }
  .brand__mark { width: 2.25rem; height: 2.25rem; }
  .detail__head { flex-direction: column; align-items: flex-start; }
  .gallery__grid { gap: var(--sp-base); }
  .frame { height: 11rem; }

  /* A 5rem sticky bar is a lot of a small screen. The nav panel inset and the
     scroll-padding are coupled to this height — change them together. */
  .site-header__inner { min-height: 4rem; }
  .has-js .nav { inset: 4rem 0 0; }
  html { scroll-padding-top: 5rem; }
  .detail { scroll-margin-top: 5rem; }

  /* Full-width actions: at 375px two 208px buttons cannot sit side by side. */
  .hero__actions, .hero__actions .btn { width: 100%; }
  .card .btn { align-self: stretch; }
  .btn { padding-inline: var(--sp-md); }
}

/* ==========================================================================
   Thank-you page — "while you are here"
   Three onward links after the form is sent. A dead end is a wasted page:
   somebody who just enquired is the most engaged visitor the site gets.
   ========================================================================== */

.nextsteps {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: var(--sp-md);
  list-style: none;
  max-width: var(--content);
  margin-inline: auto;
}
.nextstep {
  display: flex;
  flex-direction: column;
  gap: var(--sp-base);
  padding: var(--sp-md);
  background: var(--surface-ctr);
  border: 1px solid var(--outline-var);
  border-radius: var(--radius-xl);
  transition: box-shadow .3s ease, transform .3s ease;
}
.nextstep:hover { box-shadow: var(--lift-lg); transform: translateY(-3px); }
.nextstep__link {
  font-family: var(--serif);
  font-size: var(--fs-head-sm);
  color: var(--primary);
}
.nextstep__note { font-size: var(--fs-body); color: var(--on-surface-var); }

@media (max-width: 48em) {
  .nextsteps { grid-template-columns: 1fr; }
}

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

/* ==========================================================================
   Placeholder testimonials
   Only rendered while `testimonials.placeholder` is true in content.php.
   Loud on purpose: this marks two quotes nobody said, and the whole reason
   they are allowed on the page at all is that a reader cannot miss the label.
   Both rules disappear the moment the flag is false.
   ========================================================================== */

.sample-note {
  display: inline-block;
  margin-top: var(--sp-sm);
  padding: var(--sp-base) var(--sp-sm);
  border: 1px dashed var(--primary);
  border-radius: var(--radius);
  font-size: var(--fs-label);
  letter-spacing: var(--tracking-label);
  text-transform: uppercase;
  color: var(--primary);
}

.quote--sample { opacity: .82; }
.quote__tag {
  display: inline-block;
  margin-left: var(--sp-base);
  padding: 1px var(--sp-base);
  border: 1px solid currentColor;
  border-radius: 999px;
  font-family: var(--sans);
  font-size: .6875rem;
  letter-spacing: var(--tracking-label);
  text-transform: uppercase;
  vertical-align: middle;
  opacity: .75;
}

/* ==========================================================================
   Hero byline
   His own copy puts his name on its own line under the headline, so the hero
   carries it there. Serif, not the label sans — it is a signature on the
   promise above it, not a kicker.
   ========================================================================== */

.hero__byline {
  font-family: var(--serif);
  font-size: var(--fs-title);
  color: var(--primary);
  margin-top: calc(var(--sp-md) * -1);
}

/* ==========================================================================
   Statement band
   His positioning copy where it opens a page rather than a hero: centred and
   held to the reading measure, so it reads as a stated position and not as a
   second hero competing with the one on the front page.
   ========================================================================== */

.statement {
  max-width: var(--measure);
  margin-inline: auto;
  text-align: center;
}
.statement .h2 { color: var(--primary); }
.statement .hero__byline { margin-top: var(--sp-sm); }
.statement .lede { margin-top: var(--sp-md); }
