/* ==========================================================================
   Paradise Ziplines — prototype stylesheet
   All values derive from brand/tokens.md. Change tokens there first.
   ========================================================================== */

/* --------------------------------------------------------------------------
   1. Tokens
   -------------------------------------------------------------------------- */

/* THEME COPY — this file, not prototype/, is the source of truth from here on.
   Each token reads its value from the matching theme.json preset with the
   original hex as a fallback, so editing a colour in Appearance > Editor >
   Styles propagates through every rule below without touching code. The
   fallback means the stylesheet still stands up on its own. */

:root {
  /* Brand palette */
  --pz-sky:      var(--wp--preset--color--sky, #00aeef);
  --pz-sky-40:   var(--wp--preset--color--sky-40, #8ed8f8);
  --pz-sky-25:   var(--wp--preset--color--sky-25, #b9e5fb);
  --pz-sky-10:   var(--wp--preset--color--sky-10, #e2f4fd);
  --pz-forest:   var(--wp--preset--color--forest, #00512f);
  --pz-green:    var(--wp--preset--color--green-brand, #009445);
  --pz-lime:     var(--wp--preset--color--lime, #7bc143);
  --pz-white:    var(--wp--preset--color--white, #fff);
  --pz-black: #000;

  /* Derived UI shades — see brand/tokens.md. --pz-green is 3.95:1 on white and
     fails AA for any label under 18.66px, which includes the 17px header CTA.
     The brand green is unchanged; the interface paints this darkened value. */
  --pz-green-ui:       var(--wp--preset--color--green-ui, #00753a);
  --pz-green-ui-hover: #005c2d;
  --pz-border-input:   #7e8782;

  /* Derived neutrals */
  --pz-ink:       var(--wp--preset--color--ink, #1a1d1b);
  --pz-ink-muted: var(--wp--preset--color--ink-muted, #5a625e);
  --pz-rule:      var(--wp--preset--color--rule, #dde3e0);
  --pz-surface:   var(--wp--preset--color--surface, #f6f8f7);

  /* Semantic */
  --color-text: var(--pz-ink);
  --color-text-muted: var(--pz-ink-muted);
  --color-heading: var(--pz-forest);
  --color-link: var(--pz-forest);
  --color-cta: var(--pz-green-ui);
  --color-cta-hover: var(--pz-green-ui-hover);
  --color-cta-text: var(--pz-white);
  /* Small green text — eyebrows, link hover. Same value as the CTA fill so it
     is safe at any size and can't be broken by a font-size edit in the builder. */
  --color-green-text: var(--pz-green-ui);
  --color-accent: var(--pz-lime);
  --color-border-input: var(--pz-border-input);
  /* Swapped to white on dark surfaces further down, rather than restated
     per component. --pz-sky was 2.53:1 here and failed 1.4.11. */
  --color-focus: var(--pz-forest);
  --color-bg: var(--pz-white);
  --color-bg-alt: var(--pz-sky-10);
  --color-bg-dark: var(--pz-forest);

  /* Type */
  --font-display: 'Roboto Slab', Georgia, 'Times New Roman', serif;
  --font-body: 'Source Sans 3', -apple-system, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;

  --fs-hero: clamp(2.5rem, 1.4rem + 4.7vw, 4.5rem);
  --fs-h1: clamp(2rem, 1.4rem + 2.6vw, 3.25rem);
  --fs-h2: clamp(1.6rem, 1.25rem + 1.5vw, 2.5rem);
  --fs-h3: clamp(1.25rem, 1.1rem + 0.65vw, 1.625rem);
  --fs-h4: 1.125rem;
  --fs-lead: clamp(1.125rem, 1.05rem + 0.3vw, 1.3rem);
  --fs-body: 1.0625rem;
  --fs-small: 0.9375rem;
  --fs-stat: clamp(2.75rem, 2rem + 3.2vw, 4.5rem);

  /* Space */
  --space-3xs: 0.25rem;
  --space-2xs: 0.5rem;
  --space-xs: 0.75rem;
  --space-s: 1rem;
  --space-m: 1.5rem;
  --space-l: 2rem;
  --space-xl: 3rem;
  --space-2xl: 4rem;
  --space-3xl: 6rem;
  --section-y: clamp(3.5rem, 2rem + 6vw, 7rem);

  /* Layout */
  --width-content: 1180px;
  --width-wide: 1440px;
  --width-prose: 720px;
  --gutter: clamp(1.25rem, 4vw, 2.5rem);
  /* --header-min is the DESIGN token: the header's minimum height. It is static
     and must never be written to by JS.
     --header-h is the MEASURED runtime height, written by JS for things that
     need the real number (scroll-padding, the journey deck's sticky offsets).
     These have to be two separate variables. When they were one, JS wrote the
     measured height into the same token .site-header__inner uses for its
     min-height, so each measurement grew the header by its 1px border and the
     ResizeObserver fired again — the page grew without limit on every load. */
  --header-min: 76px;
  --header-h: 77px;
  --book-bar-h: 92px;
  /* Height of the hero's angled edge. The zipline cable and the badges that
     ride it are both derived from this, so they can never drift apart. */
  --edge-h: clamp(64px, 8vw, 118px);

  /* Radii / shadow / motion */
  --radius-s: 4px;
  --radius-m: 8px;
  --radius-l: 16px;
  --radius-pill: 999px;
  --shadow-s: 0 1px 2px rgba(0, 0, 0, .06), 0 2px 6px rgba(0, 0, 0, .05);
  --shadow-m: 0 4px 12px rgba(0, 0, 0, .08), 0 12px 28px rgba(0, 0, 0, .07);
  --shadow-l: 0 10px 30px rgba(0, 0, 0, .12), 0 30px 60px rgba(0, 0, 0, .1);
  --ease: cubic-bezier(.2, .7, .3, 1);
  --dur-fast: 150ms;
  --dur: 250ms;
  --dur-slow: 450ms;
}

/* --------------------------------------------------------------------------
   2. Reset & base
   -------------------------------------------------------------------------- */

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

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
  /* Without this every in-page anchor lands under the sticky header — the skip
     link, and faq.html#cancellations in all seven footers. */
  scroll-padding-top: calc(var(--header-h) + var(--wp-admin--admin-bar--height, 0px) + 1rem);
}
@media (prefers-reduced-motion: reduce) { html { scroll-behavior: auto; } }

body {
  font-family: var(--font-body);
  font-size: var(--fs-body);
  line-height: 1.65;
  color: var(--color-text);
  background: var(--color-bg);
  -webkit-font-smoothing: antialiased;
  /* Contains the hero badges' zip-in, which starts each disc off-screen left
     at translateX(calc(var(--k) * -100vw - 160px)). Kept deliberately, and
     named, rather than left as an unexplained global suppressant. */
  overflow-x: hidden;
}

img, svg, video { display: block; max-width: 100%; height: auto; }
button, input, textarea, select { font: inherit; color: inherit; }

h1, h2, h3, h4 {
  font-family: var(--font-display);
  font-weight: 700;
  line-height: 1.12;
  letter-spacing: -0.015em;
  color: var(--color-heading);
  text-wrap: balance;
}
h1 { font-size: var(--fs-h1); }
h2 { font-size: var(--fs-h2); }
h3 { font-size: var(--fs-h3); }
h4 { font-size: var(--fs-h4); }

p { text-wrap: pretty; }

a { color: var(--color-link); text-decoration-thickness: 1px; text-underline-offset: 3px; }
a:hover { color: var(--color-green-text); }

:focus-visible {
  outline: 3px solid var(--color-focus);
  outline-offset: 2px;
  border-radius: 2px;
}

/* Dark surfaces flip the ring to white (9.5:1 on forest). One rule, so a new
   dark section inherits a correct ring without anyone remembering to add it. */
.hero, .page-hero, .section--dark, .cta-band,
.nav-drawer, .site-footer, .book-bar, .proto-bar {
  --color-focus: var(--pz-white);
}

.skip-link {
  position: absolute; left: var(--space-s); top: -100%;
  z-index: 200; padding: var(--space-xs) var(--space-s);
  background: var(--pz-forest); color: #fff; border-radius: var(--radius-m);
  text-decoration: none;
}
.skip-link:focus { top: var(--space-s); color: #fff; }

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

/* --------------------------------------------------------------------------
   3. Layout primitives
   -------------------------------------------------------------------------- */

.container { width: min(100% - (var(--gutter) * 2), var(--width-max, var(--width-content))); margin-inline: auto; }
.container--wide { --width-max: var(--width-wide); }
.container--prose { --width-max: var(--width-prose); }

.section { padding-block: var(--section-y); }
.section--alt { background: var(--color-bg-alt); }
.section--dark { background: var(--color-bg-dark); color: #fff; }
.section--dark h2, .section--dark h3 { color: #fff; }

.eyebrow {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: var(--fs-small);
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--color-green-text);
  margin-bottom: var(--space-xs);
}
/* Lime is 4.31:1 on forest and is decorative-only per tokens.md — white here. */
.section--dark .eyebrow { color: var(--pz-white); }

.lead { font-size: var(--fs-lead); color: var(--color-text-muted); max-width: 62ch; }
.section--dark .lead { color: rgba(255, 255, 255, .82); }

.section-head { max-width: 62ch; margin-bottom: var(--space-xl); }

/* Utilities — small, named, and few. These replace inline style attributes,
   which do not survive a block editor or a visual builder cleanly. */
.mt-s  { margin-top: var(--space-s); }
.mt-m  { margin-top: var(--space-m); }
.mt-xl { margin-top: var(--space-xl); }
.measure { max-width: 60ch; }
.text-meta { font-size: var(--fs-small); color: var(--color-text-muted); }

/* --------------------------------------------------------------------------
   4. Buttons
   -------------------------------------------------------------------------- */

.btn {
  display: inline-flex; align-items: center; justify-content: center;
  gap: var(--space-2xs);
  min-height: 44px;
  padding: var(--space-xs) var(--space-m);
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 1.0625rem;
  letter-spacing: .01em;
  text-decoration: none;
  border: 2px solid transparent;
  border-radius: var(--radius-m);
  cursor: pointer;
  transition: background var(--dur) var(--ease), color var(--dur) var(--ease),
              border-color var(--dur) var(--ease), transform var(--dur-fast) var(--ease);
}
.btn:active { transform: translateY(1px); }

.btn--primary { background: var(--color-cta); color: #fff; box-shadow: var(--shadow-s); }
.btn--primary:hover { background: var(--color-cta-hover); color: #fff; }

.btn--ghost { background: transparent; color: var(--pz-forest); border-color: var(--pz-forest); }
.btn--ghost:hover { background: var(--pz-forest); color: #fff; }

.btn--on-dark { background: transparent; color: #fff; border-color: rgba(255, 255, 255, .6); }
.btn--on-dark:hover { background: #fff; color: var(--pz-forest); }

.btn--lg { min-height: 54px; padding-inline: var(--space-l); font-size: 1.1875rem; }
.btn--block { width: 100%; }

/* --------------------------------------------------------------------------
   5. Header
   -------------------------------------------------------------------------- */

.site-header {
  position: sticky; top: 0; z-index: 100;
  background: rgba(255, 255, 255, .96);
  backdrop-filter: blur(10px);
  border-bottom: 1px solid var(--pz-rule);
  transition: transform var(--dur) var(--ease), box-shadow var(--dur) var(--ease);
}
.site-header.is-stuck { box-shadow: var(--shadow-s); }
.site-header.is-hidden { transform: translateY(-100%); }

.site-header__inner {
  display: flex; align-items: center; gap: var(--space-m);
  /* --header-min, never --header-h: see the note on those tokens. */
  min-height: var(--header-min);
  width: min(100% - (var(--gutter) * 2), var(--width-wide));
  margin-inline: auto;
  padding-block: var(--space-2xs);
}

/* Horizontal lockup: circular mark + wordmark. The supplied lockup is stacked
   (badge over wordmark) and goes unreadable at header height, so the header
   pairs the mark artwork with the wordmark set in the display face. */
.site-logo {
  display: flex; align-items: center; gap: var(--space-2xs);
  flex: none; text-decoration: none;
}
.site-logo img { height: 54px; width: auto; }
.site-logo__word {
  display: none;
  font-family: var(--font-display);
  font-weight: 800;
  line-height: .95;
  letter-spacing: .01em;
  color: var(--pz-ink);
  text-transform: uppercase;
}
.site-logo__word small { display: block; font-size: .6875rem; letter-spacing: .18em; font-weight: 700; }
.site-logo__word strong { display: block; font-size: 1.375rem; font-weight: 800; }
@media (min-width: 360px) { .site-logo__word { display: block; } }

.site-nav { margin-left: auto; display: none; }
.site-nav ul { display: flex; align-items: center; gap: clamp(1rem, 2vw, 2rem); list-style: none; padding: 0; }
.site-nav a {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 1rem;
  color: var(--pz-forest);
  text-decoration: none;
  padding-block: var(--space-2xs);
  border-bottom: 2px solid transparent;
  transition: border-color var(--dur) var(--ease), color var(--dur) var(--ease);
}
.site-nav a:hover { border-bottom-color: var(--color-green-text); }
.site-nav a[aria-current='page'] { border-bottom-color: var(--color-cta); }

.header-actions { margin-left: auto; display: flex; align-items: center; gap: var(--space-xs); }

.price-flag {
  display: none;
  align-items: center;
  gap: var(--space-3xs);
  padding: var(--space-3xs) var(--space-s);
  background: var(--pz-lime);
  /* forest on lime is 4.31:1 and fails at 15px; ink is 9.5:1 */
  color: var(--pz-ink);
  font-family: var(--font-display);
  font-weight: 700;
  font-size: var(--fs-small);
  border-radius: var(--radius-pill);
  white-space: nowrap;
}

.nav-toggle {
  display: inline-flex; align-items: center; justify-content: center;
  width: 46px; height: 46px;
  background: transparent;
  border: 2px solid var(--pz-forest);
  border-radius: var(--radius-m);
  cursor: pointer;
}
.nav-toggle svg { width: 22px; height: 22px; }
.nav-toggle .icon-close { display: none; }
.nav-toggle[aria-expanded='true'] .icon-open { display: none; }
.nav-toggle[aria-expanded='true'] .icon-close { display: block; }

/* Slide-in drawer */
.nav-drawer {
  position: fixed; inset: 0 0 0 auto;
  width: min(88vw, 380px);
  z-index: 150;
  background: var(--pz-forest);
  color: #fff;
  padding: var(--space-l) var(--space-l) var(--space-2xl);
  transform: translateX(100%);
  transition: transform var(--dur-slow) var(--ease);
  overflow-y: auto;
  display: flex; flex-direction: column; gap: var(--space-m);
}
.nav-drawer.is-open { transform: translateX(0); }
.nav-drawer__head { display: flex; align-items: center; justify-content: space-between; }
.nav-drawer__head img { height: 76px; }
.nav-drawer__close {
  width: 46px; height: 46px; display: inline-flex; align-items: center; justify-content: center;
  background: transparent; border: 2px solid rgba(255, 255, 255, .5);
  border-radius: var(--radius-m); color: #fff; cursor: pointer;
}
.nav-drawer ul { list-style: none; padding: 0; display: flex; flex-direction: column; }
.nav-drawer li + li { border-top: 1px solid rgba(255, 255, 255, .16); }
.nav-drawer a {
  display: block; padding: var(--space-s) 0;
  font-family: var(--font-display); font-weight: 600; font-size: 1.25rem;
  color: #fff; text-decoration: none;
}
.nav-drawer a:hover { text-decoration: underline; text-decoration-color: var(--color-accent);
  text-decoration-thickness: 3px; text-underline-offset: 4px; }
.nav-drawer__meta { font-size: var(--fs-small); color: rgba(255, 255, 255, .75); }
.nav-drawer__meta a { display: inline; font-size: inherit; font-family: var(--font-body); padding: 0; }

.nav-scrim {
  position: fixed; inset: 0; z-index: 140;
  background: rgba(0, 20, 12, .5);
  opacity: 0; visibility: hidden;
  transition: opacity var(--dur) var(--ease), visibility var(--dur) var(--ease);
}
.nav-scrim.is-open { opacity: 1; visibility: visible; }

body.nav-open { overflow: hidden; }

/* Below desktop the header is logo + hamburger only (per the wireframe). The
   sticky bottom bar already carries Book Now, so a second one here is noise. */
@media (max-width: 1023px) {
  .header-actions .btn { display: none; }
}

@media (min-width: 1024px) {
  .site-nav { display: block; }
  /* Push from the logo, not the nav. The Navigation block sets its own margins,
     which killed `.site-nav { margin-left: auto }` and left the nav, price flag
     and Book Now bunched in the middle. A margin on the logo can't be undone by
     anything the block does to itself. */
  .site-header__inner > .site-logo { margin-right: auto; }
  .site-nav,
  .site-nav + .header-actions { margin-left: 0; }
  .price-flag { display: inline-flex; }
  .nav-toggle { display: none; }
}

/* --------------------------------------------------------------------------
   6. Mobile sticky book bar
   -------------------------------------------------------------------------- */

.book-bar {
  position: fixed; left: 0; right: 0; bottom: 0; z-index: 120;
  display: flex; align-items: center; gap: var(--space-s);
  padding: var(--space-2xs) var(--space-s);
  padding-bottom: max(var(--space-2xs), env(safe-area-inset-bottom));
  background: var(--pz-forest);
  border-top: 3px solid var(--pz-lime);
  box-shadow: 0 -4px 20px rgba(0, 0, 0, .18);
}
.book-bar__price { color: #fff; line-height: 1.2; }
.book-bar__price strong { display: block; font-family: var(--font-display); font-size: 1.25rem; }
.book-bar__price span { font-size: .8125rem; color: rgba(255, 255, 255, .75); }
.book-bar .btn { margin-left: auto; flex: 1; max-width: 200px; }

@media (min-width: 1024px) { .book-bar { display: none; } }
body:has(.book-bar) .site-footer { padding-bottom: calc(var(--book-bar-h) + var(--space-s)); }
@media (min-width: 1024px) { body:has(.book-bar) .site-footer { padding-bottom: var(--space-xl); } }

/* --------------------------------------------------------------------------
   7. Hero
   -------------------------------------------------------------------------- */

.hero {
  position: relative;
  min-height: clamp(520px, 78vh, 760px);
  display: flex; align-items: flex-end;
  padding-bottom: clamp(5rem, 4rem + 6vw, 8rem);
  overflow: hidden;
  isolation: isolate;
}
.hero__media { position: absolute; inset: 0; z-index: -2; }
.hero__media img, .hero__media video { width: 100%; height: 100%; object-fit: cover; }

/* Prototype stand-in for the hero video — a brand-tinted field plus a corner
   slate, so the placeholder never competes with the headline. */
.media-proto,
.hero__media--proto {
  background:
    radial-gradient(120% 90% at 78% 18%, rgba(0, 174, 239, .55), transparent 62%),
    radial-gradient(100% 80% at 12% 88%, rgba(123, 193, 67, .38), transparent 60%),
    linear-gradient(155deg, #0b3b28 0%, #0a5a3c 48%, #06304a 100%);
}
.hero__slate {
  position: absolute; top: var(--space-2xs); left: var(--space-2xs);
  max-width: min(30ch, 58vw);
  padding: var(--space-2xs) var(--space-xs);
  background: rgba(0, 0, 0, .55);
  border-radius: var(--radius-s);
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: .6875rem;
  line-height: 1.5;
  color: rgba(255, 255, 255, .88);
}
.hero::after {
  content: ''; position: absolute; inset: 0; z-index: -1;
  /* Two layers. The vertical one is the base wash, tuned against the still
     poster. The horizontal one only covers the left column, because that is
     where the headline, lead and rating sit - it buys the contrast the moving
     video needs without dulling the right of the frame, which is where the
     rider is.
     Measured against five real frames of the video (the poster plus the 25/50/
     75% frames), sampling the glyph line boxes only: H1 5.19:1, lead 7.15:1,
     rating 9.96:1. Requirements are 3:1 for the H1 (large text) and 4.5:1 for
     the lead. Without the horizontal layer those frames measured 3.26 and 4.26,
     i.e. the lead failed. Re-measure if the video, the hero height or the text
     position changes. */
  background:
    linear-gradient(90deg,
      rgba(0, 30, 18, .35) 0%,
      rgba(0, 30, 18, .35) 55%,
      rgba(0, 30, 18, 0) 90%),
    linear-gradient(180deg,
      rgba(0, 30, 18, .34) 0%,
      rgba(0, 30, 18, .48) 40%,
      rgba(0, 30, 18, .54) 70%,
      rgba(0, 30, 18, .70) 100%);
}

/* Below 768 the text runs nearly the full width, so a left-weighted band would
   leave the ends of the lines uncovered. Carry the same strength straight
   across instead. */
@media (max-width: 767px) {
  .hero::after {
    background:
      linear-gradient(90deg,
        rgba(0, 30, 18, .35) 0%,
        rgba(0, 30, 18, .35) 100%),
      linear-gradient(180deg,
        rgba(0, 30, 18, .34) 0%,
        rgba(0, 30, 18, .48) 40%,
        rgba(0, 30, 18, .54) 70%,
        rgba(0, 30, 18, .70) 100%);
  }
}

.hero__content { position: relative; z-index: 3; color: #fff; max-width: 680px; }
.hero h1 {
  font-size: var(--fs-hero);
  color: #fff;
  text-shadow: 0 2px 18px rgba(0, 0, 0, .45);
  margin-bottom: var(--space-s);
}
.hero__sub {
  font-size: var(--fs-lead);
  color: rgba(255, 255, 255, .94);
  text-shadow: 0 1px 10px rgba(0, 0, 0, .5);
  margin-bottom: var(--space-m);
  max-width: 420px;
}
.hero__actions { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-m); }

.rating-inline { display: flex; align-items: center; gap: var(--space-2xs); color: #fff; font-size: var(--fs-small); text-shadow: 0 1px 6px rgba(0, 0, 0, .5); }
.stars { color: var(--pz-lime); letter-spacing: .08em; font-size: 1.0625rem; }

/* Angled edge + zipline cable ------------------------------------------------
   The wedge and the cable share one geometry: the line runs from the hero's
   bottom-left corner (viewBox y=12) up to a quarter of the edge height on the
   right (y=3), i.e. it climbs 75% of --edge-h across the full width. Badge
   positions are computed from that same figure via --k, so they sit exactly on
   the cable at any viewport width instead of being nudged into place by eye. */

.hero__edge {
  position: absolute; left: 0; right: 0; bottom: -1px; z-index: 2;
  height: var(--edge-h);
  pointer-events: none;
}
.hero__edge svg { width: 100%; height: 100%; display: block; }

.badge-wire {
  --rise: calc(var(--edge-h) * .75);
  --disc: clamp(64px, 6.4vw, 92px);
  position: relative;
  z-index: 3;
  height: var(--edge-h);
  margin-top: calc(var(--edge-h) * -1);
  /* Discs are centred on the cable, so the lowest one hangs half its height
     below the container. Reserve that or it lands on the award line. */
  margin-bottom: calc(var(--disc) / 2);
  pointer-events: none;
}
.badge-wire__track { position: absolute; inset: 0; }

/* The riders start off-screen to the RIGHT, and unlike left-side overflow that
   IS scrollable — it pushed the document to 1476px at a 1280px viewport. Clip
   the horizontal axis only: `clip` (not `hidden`) leaves the vertical axis
   genuinely visible, so the discs still hang below the cable without being cut. */
.badge-wire { overflow-x: clip; overflow-y: visible; }

.badge-wire__item {
  position: absolute;
  left: calc(var(--k) * 100%);
  bottom: calc(var(--rise) * var(--k));
  transform: translate(-50%, 50%);
}

/* Award medallion. These stand in for the real Travellers' Choice artwork,
   which is pending Chris confirming the certification and supplying the files.
   Until then they should still read as awards rather than as plain type in a
   circle: a double ring for the medal edge, the year carrying the weight, and
   the award name small above it. The old version bottomed out at 8px type,
   which was both illegible and cheap-looking. */
.badge-wire__disc {
  display: grid;
  place-items: center;
  align-content: center;
  gap: 1px;
  text-align: center;
  width: var(--disc);
  aspect-ratio: 1;
  border-radius: 50%;
  background:
    radial-gradient(circle at 50% 38%, #ffffff 0%, #ffffff 62%, #f2f6f4 100%);
  border: 2px solid var(--pz-white);
  box-shadow:
    0 0 0 2px var(--pz-lime),
    var(--shadow-m);
  font-family: var(--font-display);
  color: var(--pz-forest);
  line-height: 1;
  padding: 6%;
}
.badge-wire__disc .badge-wire__award {
  display: block;
  font-size: clamp(.375rem, .58vw, .5rem);
  font-weight: 700;
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--pz-ink-muted);
}
.badge-wire__disc .badge-wire__year {
  display: block;
  font-size: clamp(.8125rem, 1.15vw, 1.0625rem);
  font-weight: 800;
  letter-spacing: -.01em;
}
.badge-wire__disc .badge-wire__mark {
  display: block;
  font-size: clamp(.5rem, .72vw, .625rem);
  font-weight: 700;
  letter-spacing: .04em;
  text-transform: uppercase;
}

/* Riders arrive under gravity. The cable runs low at the left and high at the
   right, so a rider enters from off-screen RIGHT and travels DOWN-LEFT along
   the line — it previously ran uphill, left to right, which read as wrong
   because it is. X and Y are derived from the same --k and --rise as the
   resting position, so the path sits exactly on the cable the whole way. */
@media (prefers-reduced-motion: no-preference) {
  .badge-wire__disc {
    animation: zip-in 1s cubic-bezier(.16, .84, .3, 1) backwards;
    animation-delay: calc(var(--i) * 130ms + 250ms);
  }
  @keyframes zip-in {
    from {
      opacity: 0;
      transform: translate(
        calc((1 - var(--k)) * 100vw + 160px),
        calc(var(--rise) * (var(--k) - 1))
      );
    }
    to { opacity: 1; transform: translate(0, 0); }
  }
}

/* Mobile: the cable is too short to hold six badges and the sticky Book Now bar
   covers the hero's bottom edge, so the run becomes a marquee below the hero —
   the badges travel across the viewport instead of sitting on the line. */
@media (max-width: 767px) {
  .badge-wire {
    --disc: 62px;
    height: auto;
    margin-top: 0;
    margin-bottom: 0;
    overflow: hidden;
    padding-block: var(--space-m) var(--space-2xs);
    -webkit-mask-image: linear-gradient(90deg, transparent, #000 10%, #000 90%, transparent);
            mask-image: linear-gradient(90deg, transparent, #000 10%, #000 90%, transparent);
  }
  .badge-wire__track {
    position: static;
    display: flex;
    width: max-content;
    align-items: center;
    gap: var(--space-m);
  }
  .badge-wire__item { position: static; transform: none; flex: none; }
  .badge-wire__disc { --disc: 62px; animation: none; opacity: 1; }

  .badge-wire__track.is-marquee { animation: badge-marquee 26s linear infinite; }
  @keyframes badge-marquee { to { transform: translateX(calc(-50% - (var(--space-m) / 2))); } }
}

@media (max-width: 767px) and (prefers-reduced-motion: reduce) {
  .badge-wire { overflow-x: auto; scroll-snap-type: x proximity; }
  .badge-wire__track.is-marquee { animation: none; }
  .badge-wire__item { scroll-snap-align: center; }
}

.award-line {
  text-align: center;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: var(--fs-small);
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--pz-forest);
  padding-block: var(--space-s);
}

/* Page hero (interior pages) */
.page-hero {
  position: relative;
  padding-block: clamp(3rem, 2rem + 5vw, 6rem);
  background: var(--pz-forest);
  color: #fff;
  isolation: isolate;
  overflow: hidden;
}
.page-hero--media::after {
  content: ''; position: absolute; inset: 0; z-index: -1;
  background: linear-gradient(180deg, rgba(0, 40, 24, .55), rgba(0, 40, 24, .8));
}
.page-hero__media { position: absolute; inset: 0; z-index: -2; }
.page-hero__media img { width: 100%; height: 100%; object-fit: cover; }
/* Interior heroes are short, so the prototype slate goes bottom-right where it
   can't collide with the breadcrumb and headline. */
.page-hero__media .hero__slate {
  top: auto; left: auto;
  bottom: var(--space-2xs); right: var(--space-2xs);
  max-width: 24ch;
}
.page-hero h1 { color: #fff; margin-bottom: var(--space-s); }
.page-hero .lead { color: rgba(255, 255, 255, .88); }
.page-hero .lead a { color: #fff; }
.page-hero__actions { display: flex; flex-wrap: wrap; gap: var(--space-s); margin-top: var(--space-m); }

.breadcrumb { font-size: var(--fs-small); color: rgba(255, 255, 255, .75); margin-bottom: var(--space-s); }
.breadcrumb a { color: #fff; }
.breadcrumb span { padding-inline: var(--space-3xs); }

/* --------------------------------------------------------------------------
   8. Stat bar
   -------------------------------------------------------------------------- */

.stat-bar {
  border-block: 3px solid var(--pz-forest);
  background: #fff;
}
/* Trailing rules are pushed outside the box by the negative margins rather
   than cancelled per-child, so any number of stats renders correctly. The
   previous nth-child resets assumed exactly four. */
.stat-bar__grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  margin-right: -1px;
  margin-bottom: -1px;
}
.stat-bar__item {
  text-align: center;
  padding: var(--space-m) var(--space-2xs);
  border-right: 1px solid var(--pz-rule);
  border-bottom: 1px solid var(--pz-rule);
}
.stat-bar__num {
  font-family: var(--font-display); font-weight: 800;
  font-size: clamp(2rem, 1.4rem + 2.4vw, 3.25rem);
  line-height: 1; color: var(--pz-forest);
}
.stat-bar__label {
  font-size: .8125rem; letter-spacing: .1em; text-transform: uppercase;
  color: var(--color-text-muted); margin-top: var(--space-3xs);
}
@media (min-width: 768px) {
  .stat-bar__grid { grid-template-columns: repeat(4, 1fr); }
}

/* --------------------------------------------------------------------------
   9. Media placeholders (prototype only — replaced by real photography)
   -------------------------------------------------------------------------- */

.ph {
  display: grid; place-items: center;
  text-align: center;
  padding: var(--space-s);
  background:
    repeating-linear-gradient(120deg, var(--pz-sky-10), var(--pz-sky-10) 10px, #eef7fb 10px, #eef7fb 20px);
  border: 1px dashed var(--pz-sky-40);
  border-radius: var(--radius-m);
  color: var(--color-text-muted);
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: .75rem;
  line-height: 1.4;
  aspect-ratio: 4 / 3;
}
.ph--wide { aspect-ratio: 16 / 9; }

.note {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: .75rem;
  line-height: 1.5;
  color: var(--color-text-muted);
  background: var(--pz-surface);
  border-left: 3px solid var(--pz-sky-40);
  padding: var(--space-2xs) var(--space-xs);
  border-radius: 0 var(--radius-s) var(--radius-s) 0;
  margin-top: var(--space-s);
}
.section--dark .note { background: rgba(255, 255, 255, .07); color: rgba(255, 255, 255, .72); border-left-color: var(--pz-lime); }
.note--flush { margin-top: 0; }
.note--wide { max-width: 70ch; margin-inline: auto; }

/* --------------------------------------------------------------------------
   10. Highlights
   -------------------------------------------------------------------------- */

.highlights__grid {
  display: grid;
  gap: var(--space-m);
  grid-template-columns: 1fr;
}
@media (min-width: 768px) { .highlights__grid { grid-template-columns: repeat(3, 1fr); } }

.highlight-card {
  display: flex; flex-direction: column; gap: var(--space-xs);
}
.highlight-card .ph { aspect-ratio: 4 / 3; }
.highlight-card h3 { font-size: var(--fs-h3); }
.highlight-card p { color: var(--color-text-muted); font-size: var(--fs-small); }

/* Horizontal scroll on small screens */
@media (max-width: 767px) {
  .highlights__grid {
    /* Clear the explicit track or the first card lands in it and collapses
       while the rest take the 78% auto columns. */
    grid-template-columns: none;
    grid-auto-flow: column;
    grid-auto-columns: 78%;
    overflow-x: auto;
    scroll-snap-type: x mandatory;
    padding-bottom: var(--space-s);
    scrollbar-width: thin;
  }
  .highlight-card { scroll-snap-align: start; }
}

.rotator { display: inline-block; color: var(--color-cta); }

/* --------------------------------------------------------------------------
   11. Reviews carousel
   -------------------------------------------------------------------------- */

.reviews { text-align: center; }

/* All slides share one grid cell so the block is as tall as the longest quote —
   no height jump, and slides cross-fade instead of flashing empty. */
.reviews__viewport {
  display: grid;
  max-width: 62ch;
  margin-inline: auto;
}
.reviews__slide {
  grid-area: 1 / 1;
  opacity: 0;
  visibility: hidden;
  transform: translateY(8px);
  transition: opacity var(--dur-slow) var(--ease), transform var(--dur-slow) var(--ease),
              visibility 0s linear var(--dur-slow);
}
.reviews__slide.is-active {
  opacity: 1;
  visibility: visible;
  transform: none;
  transition-delay: 0s;
}
@media (prefers-reduced-motion: reduce) {
  .reviews__slide { transition: none; transform: none; }
}

.reviews__quote {
  font-family: var(--font-display);
  font-size: clamp(1.125rem, 1rem + .8vw, 1.5rem);
  line-height: 1.45;
  color: #fff;
  margin-block: var(--space-s);
}
.reviews__author { font-size: var(--fs-small); color: rgba(255, 255, 255, .72); }
.reviews__controls { display: flex; align-items: center; justify-content: center; gap: var(--space-s); margin-top: var(--space-m); }
.reviews__btn {
  width: 44px; height: 44px; display: inline-flex; align-items: center; justify-content: center;
  background: transparent; border: 2px solid rgba(255, 255, 255, .5); border-radius: 50%;
  color: #fff; cursor: pointer; transition: background var(--dur) var(--ease);
}
.reviews__btn:hover { background: rgba(255, 255, 255, .14); }
.reviews__dots { display: flex; gap: var(--space-2xs); }

/* WCAG 2.2.2 — autoplay needs a stop, and hover/focus does not exist on touch. */
.reviews__playpause {
  width: 44px; height: 44px; display: inline-flex; align-items: center; justify-content: center;
  background: transparent; border: 2px solid rgba(255, 255, 255, .5); border-radius: 50%;
  color: #fff; cursor: pointer; transition: background var(--dur) var(--ease);
}
.reviews__playpause:hover { background: rgba(255, 255, 255, .14); }
.reviews__playpause .icon-pause { display: none; }
.reviews__playpause.is-playing .icon-pause { display: block; }
.reviews__playpause.is-playing .icon-play { display: none; }
/* Current slide is marked by size as well as hue — colour alone fails 1.4.1. */
.reviews__dot {
  width: 10px; height: 10px; padding: 0; border-radius: 50%;
  background: rgba(255, 255, 255, .5); border: 0; cursor: pointer;
  transition: background var(--dur) var(--ease), transform var(--dur) var(--ease);
}
.reviews__dot[aria-current='true'] { background: var(--color-accent); transform: scale(1.5); }
@media (prefers-reduced-motion: reduce) { .reviews__dot { transition: none; } }

.trust-strip {
  display: flex; flex-wrap: wrap; align-items: center; justify-content: center;
  gap: var(--space-s) var(--space-m);
  margin-top: var(--space-xl);
  padding-top: var(--space-m);
  border-top: 1px solid rgba(255, 255, 255, .18);
}
.trust-badge {
  flex: none;
  display: grid; place-items: center; text-align: center;
  width: 74px; aspect-ratio: 1; border-radius: 50%;
  background: rgba(255, 255, 255, .95); color: var(--pz-forest);
  font-family: var(--font-display); font-weight: 700; font-size: .625rem; line-height: 1.2;
}
/* Wireframe: badges scroll horizontally on mobile rather than wrapping */
@media (max-width: 767px) {
  .trust-strip {
    flex-wrap: nowrap;
    overflow-x: auto;
    justify-content: flex-start;
    scroll-snap-type: x proximity;
    padding-bottom: var(--space-2xs);
  }
  .trust-badge { scroll-snap-align: start; }
}

/* --------------------------------------------------------------------------
   12. Drive / split panel
   -------------------------------------------------------------------------- */

.split {
  display: grid;
  gap: var(--space-l);
  align-items: center;
  grid-template-columns: 1fr;
}
@media (min-width: 768px) {
  .split { grid-template-columns: 1.15fr 1fr; gap: var(--space-2xl); }
}

/* --------------------------------------------------------------------------
   13. Specials
   -------------------------------------------------------------------------- */

.specials__grid { display: grid; gap: var(--space-m); grid-template-columns: 1fr; }
@media (min-width: 640px) { .specials__grid { grid-template-columns: repeat(2, 1fr); } }

.special-card {
  display: flex; flex-direction: column; gap: var(--space-2xs);
  padding: var(--space-m);
  background: #fff;
  border: 2px solid var(--pz-lime);
  border-radius: var(--radius-l);
  box-shadow: var(--shadow-s);
}
.special-card__tag {
  align-self: flex-start;
  font-family: var(--font-display); font-weight: 700; font-size: .75rem;
  letter-spacing: .1em; text-transform: uppercase;
  color: var(--pz-ink); background: var(--pz-lime);
  padding: 2px var(--space-2xs); border-radius: var(--radius-s);
}
.special-card p { color: var(--color-text-muted); font-size: var(--fs-small); }
.special-card a { margin-top: auto; font-weight: 600; }

/* --------------------------------------------------------------------------
   14. Journey — accordion (desktop) / stacked cards (mobile)
   -------------------------------------------------------------------------- */

.journey { display: flex; flex-direction: column; }

.journey__step {
  border-bottom: 1px solid var(--pz-rule);
}
.journey__step:first-child { border-top: 1px solid var(--pz-rule); }

.journey__trigger {
  width: 100%;
  display: flex; align-items: center; gap: var(--space-m);
  padding: var(--space-m) 0;
  background: transparent; border: 0; cursor: pointer;
  text-align: left;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: var(--fs-h3);
  color: var(--pz-forest);
}
.journey__num {
  flex: none;
  width: 44px; height: 44px;
  display: grid; place-items: center;
  border-radius: 50%;
  background: var(--pz-sky-10);
  color: var(--pz-forest);
  font-size: 1.0625rem;
}
.journey__step.is-open .journey__num { background: var(--pz-lime); color: var(--pz-ink); }
.journey__chevron { margin-left: auto; flex: none; transition: transform var(--dur) var(--ease); }
.journey__step.is-open .journey__chevron { transform: rotate(180deg); }

.journey__panel {
  display: grid;
  grid-template-rows: 0fr;
  transition: grid-template-rows var(--dur) var(--ease);
}
.journey__step.is-open .journey__panel { grid-template-rows: 1fr; }
.journey__panel > div { overflow: hidden; }
.journey__body {
  padding: 0 0 var(--space-m) calc(44px + var(--space-m));
  max-width: 68ch;
  color: var(--color-text-muted);
}
.journey__body p + p { margin-top: var(--space-s); }

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

/* Mobile: stacked scroll deck.
   Each step becomes a full panel that sticks, with the next one sliding up and
   settling on top — by the last step they sit as a deck with each card's top
   edge peeking out. Cards butt up against each other (no margin) so a card is
   always fully covered by the one after it; a gap would let the panel
   underneath bleed through. Panels are always open here — the accordion is a
   desktop-only affordance. */
@media (max-width: 767px) {
  .journey--stack { display: block; }
  .journey--stack .journey__step {
    position: sticky;
    border: 2px solid var(--pz-forest);
    border-radius: var(--radius-l);
    background: #fff;
    box-shadow: var(--shadow-l);
    padding: var(--space-m);
    margin-bottom: 0;
    min-height: 58vh;
  }
  .journey--stack .journey__step:first-child { border-top: 2px solid var(--pz-forest); }
  /* Each card settles 0.75rem below the one before it. Derived from --i on the
     step, so adding or removing a step in WordPress just works — the previous
     nth-child list silently broke at anything other than five. */
  .journey--stack .journey__step { top: calc(var(--header-h) + 0.5rem + (var(--i, 0) * 0.75rem)); }

  .journey--stack .journey__trigger { padding: 0 0 var(--space-s); pointer-events: none; }
  .journey--stack .journey__chevron { display: none; }
  .journey--stack .journey__num { background: var(--pz-lime); color: var(--pz-ink); }

  /* always expanded on mobile */
  .journey--stack .journey__panel { grid-template-rows: 1fr; }
  .journey--stack .journey__body { padding: 0; }

  /* room for the last card to settle into the deck */
  .journey--stack::after { content: ''; display: block; height: 24vh; }
}

/* --------------------------------------------------------------------------
   15. FAQ accordion
   -------------------------------------------------------------------------- */

.faq-group + .faq-group { margin-top: var(--space-2xl); }
.faq-group__title {
  font-size: var(--fs-h3);
  padding-bottom: var(--space-2xs);
  border-bottom: 3px solid var(--pz-lime);
  margin-bottom: var(--space-s);
}

.faq-item { border-bottom: 1px solid var(--pz-rule); }
.faq-item__trigger {
  width: 100%;
  display: flex; align-items: flex-start; gap: var(--space-s);
  padding: var(--space-s) 0;
  background: transparent; border: 0; cursor: pointer; text-align: left;
  font-family: var(--font-display); font-weight: 600; font-size: var(--fs-h4);
  color: var(--pz-forest);
}
.faq-item__icon {
  margin-left: auto; flex: none;
  width: 28px; height: 28px; display: grid; place-items: center;
  border-radius: 50%; background: var(--pz-sky-10); color: var(--pz-forest);
  font-size: 1.125rem; line-height: 1;
  transition: background var(--dur) var(--ease), transform var(--dur) var(--ease);
}
.faq-item.is-open .faq-item__icon { background: var(--pz-lime); color: var(--pz-ink); transform: rotate(45deg); }
.faq-item__panel { display: grid; grid-template-rows: 0fr; transition: grid-template-rows var(--dur) var(--ease); }
.faq-item.is-open .faq-item__panel { grid-template-rows: 1fr; }
.faq-item__panel > div { overflow: hidden; }
.faq-item__body { padding-bottom: var(--space-m); max-width: 68ch; color: var(--color-text-muted); }
.faq-item__body p + p { margin-top: var(--space-s); }
@media (prefers-reduced-motion: reduce) { .faq-item__panel { transition: none; } }

/* --------------------------------------------------------------------------
   16. Info list / spec table
   -------------------------------------------------------------------------- */

.spec-list { list-style: none; padding: 0; display: grid; gap: var(--space-2xs); }
.spec-list li {
  display: flex; gap: var(--space-s); justify-content: space-between;
  padding: var(--space-2xs) 0;
  border-bottom: 1px solid var(--pz-rule);
}
.spec-list dt, .spec-list__label { color: var(--color-text-muted); }
.spec-list__value { font-weight: 600; text-align: right; }

.info-panel {
  background: #fff;
  border: 2px solid var(--pz-forest);
  border-radius: var(--radius-l);
  padding: var(--space-l);
  box-shadow: var(--shadow-s);
}
.info-panel > h2 { font-size: var(--fs-h3); margin-bottom: var(--space-s); }
.info-panel address { font-style: normal; line-height: 1.9; }
.section--alt .info-panel { background: #fff; }

/* --------------------------------------------------------------------------
   17. CTA band
   -------------------------------------------------------------------------- */

.cta-band {
  background: var(--pz-forest);
  color: #fff;
  padding-block: clamp(2.5rem, 1.8rem + 3vw, 4rem);
}
.cta-band__inner {
  display: grid; gap: var(--space-m); align-items: center;
  grid-template-columns: 1fr;
  text-align: center;
}
.cta-band blockquote { font-family: var(--font-display); font-size: var(--fs-h3); color: #fff; }
.cta-band cite { display: block; font-style: normal; font-size: var(--fs-small); color: rgba(255, 255, 255, .72); margin-top: var(--space-2xs); }
@media (min-width: 768px) {
  .cta-band__inner { grid-template-columns: 1fr auto; text-align: left; gap: var(--space-2xl); }
}

/* --------------------------------------------------------------------------
   18. Booking
   -------------------------------------------------------------------------- */

.widget-frame {
  border: 2px dashed var(--pz-sky);
  border-radius: var(--radius-l);
  background: var(--pz-sky-10);
  padding: var(--space-l);
  display: grid; gap: var(--space-m);
}
.widget-frame__label {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: .8125rem; color: var(--pz-forest);
}
.widget-frame__mock {
  background: #fff; border-radius: var(--radius-m); padding: var(--space-m);
  display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-m);
  box-shadow: var(--shadow-s);
}
.widget-frame__mock .who { font-weight: 600; }
.widget-frame__mock .when { font-size: var(--fs-small); color: var(--color-text-muted); }
.widget-frame__mock .price { font-family: var(--font-display); font-weight: 800; font-size: 1.75rem; color: var(--pz-forest); }
.widget-frame__mock .btn { margin-left: auto; }

.reassure {
  display: flex; flex-wrap: wrap; gap: var(--space-m);
  margin-top: var(--space-m);
  font-size: var(--fs-small); color: var(--color-text-muted);
}
.reassure span { display: flex; align-items: center; gap: var(--space-3xs); }

/* --------------------------------------------------------------------------
   19. Blog
   -------------------------------------------------------------------------- */

.post-grid { display: grid; gap: var(--space-xl); grid-template-columns: 1fr; }
@media (min-width: 640px) { .post-grid { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 1024px) { .post-grid { grid-template-columns: repeat(3, 1fr); } }

.post-card { display: flex; flex-direction: column; gap: var(--space-2xs); }
.post-card__meta { font-size: .8125rem; letter-spacing: .06em; text-transform: uppercase; color: var(--color-text-muted); }
/* On the dark post hero. Lime here was 4.31:1 at 15px and failed AA. */
.post-eyebrow {
  font-size: var(--fs-small); letter-spacing: .08em; text-transform: uppercase;
  color: #fff; font-family: var(--font-display); font-weight: 700;
}
.post-card h3 a { text-decoration: none; }
.post-card p { color: var(--color-text-muted); font-size: var(--fs-small); }

.prose { max-width: var(--width-prose); }
.prose > * + * { margin-top: var(--space-m); }
.prose h2 { margin-top: var(--space-xl); }
.prose ul, .prose ol { padding-left: 1.25rem; display: grid; gap: var(--space-2xs); }
.prose blockquote {
  border-left: 4px solid var(--pz-lime);
  padding-left: var(--space-m);
  font-family: var(--font-display);
  font-size: var(--fs-lead);
  color: var(--pz-forest);
}

.tag-list { display: flex; flex-wrap: wrap; gap: var(--space-2xs); list-style: none; padding: 0; }
.tag-list a {
  display: inline-block;
  padding: 2px var(--space-2xs);
  background: var(--pz-sky-10);
  border-radius: var(--radius-s);
  font-size: var(--fs-small);
  text-decoration: none;
}

/* --------------------------------------------------------------------------
   20. Forms
   -------------------------------------------------------------------------- */

.form { display: grid; gap: var(--space-m); }
.field { display: grid; gap: var(--space-3xs); }
.field label { font-weight: 600; font-size: var(--fs-small); }
.field input, .field textarea {
  width: 100%;
  padding: var(--space-xs) var(--space-s);
  background: #fff;
  /* --pz-rule is 1.30:1 and fails 1.4.11 for a control boundary. */
  border: 2px solid var(--color-border-input);
  border-radius: var(--radius-m);
  transition: border-color var(--dur) var(--ease);
}
.field input:focus, .field textarea:focus { border-color: var(--pz-forest); }
.field textarea { min-height: 150px; resize: vertical; }

/* --------------------------------------------------------------------------
   21. Footer
   -------------------------------------------------------------------------- */

.site-footer {
  background: var(--pz-forest);
  color: rgba(255, 255, 255, .82);
  padding-block: var(--space-2xl) var(--space-xl);
  font-size: var(--fs-small);
}
.site-footer__grid {
  display: grid; gap: var(--space-xl);
  grid-template-columns: 1fr;
}
@media (min-width: 640px) { .site-footer__grid { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 1024px) { .site-footer__grid { grid-template-columns: 1.4fr 1fr 1fr 1fr; } }

/* The class lands on the <figure> in the block editor and on the <img> in plain
   markup, so both have to be covered. When only img.footer-logo was targeted the
   rule matched nothing in WordPress and the SVG rendered at its natural 349px,
   which is what pushed every footer column down the page. */
.site-footer .footer-logo { margin-bottom: var(--space-s); max-width: 200px; }
.site-footer .footer-logo,
.site-footer .footer-logo img,
.site-footer img.footer-logo { height: 68px; width: auto; }
/* White text, lime as the rule beneath it — lime is 4.31:1 and decorative only. */
.site-footer h2 {
  font-size: .8125rem; letter-spacing: .12em; text-transform: uppercase;
  color: var(--pz-white); margin-bottom: var(--space-s);
  padding-bottom: var(--space-3xs);
  border-bottom: 2px solid var(--color-accent);
}
/* Scoped away from .social-list, which needs to stay horizontal. .site-footer ul
   is (0,1,1) and beat the (0,1,0) .social-list rule regardless of source order,
   which stacked the social icons vertically. */
.site-footer ul:not(.social-list) { list-style: none; padding: 0; display: grid; gap: var(--space-2xs); }
.site-footer a { color: #fff; text-decoration: none; }
.site-footer a:hover { text-decoration: underline; text-decoration-color: var(--color-accent);
  text-decoration-thickness: 2px; text-underline-offset: 3px; }
.site-footer address { font-style: normal; line-height: 1.9; }
.site-footer__hours { margin-top: var(--space-s); color: rgba(255, 255, 255, .7); }

.footer-badges { display: flex; gap: var(--space-2xs); flex-wrap: wrap; }
.footer-badges .ph {
  width: 64px; aspect-ratio: 1; border-radius: var(--radius-m);
  font-size: .5rem; line-height: 1.25; overflow: hidden; padding: 4px;
}

.site-footer__bottom {
  display: flex; flex-wrap: wrap; gap: var(--space-s);
  align-items: center; justify-content: space-between;
  margin-top: var(--space-2xl); padding-top: var(--space-m);
  border-top: 1px solid rgba(255, 255, 255, .18);
  font-size: .8125rem;
}
.site-footer .social-list,
.social-list { display: flex; flex-direction: row; gap: var(--space-xs); list-style: none; padding: 0; margin: 0; }
.social-list a {
  width: 40px; height: 40px; display: grid; place-items: center;
  /* .3 was 2.20:1; .5 gives 3.59:1 for a non-text boundary. */
  border: 1px solid rgba(255, 255, 255, .5); border-radius: 50%;
}
.social-list svg { width: 18px; height: 18px; }

/* --------------------------------------------------------------------------
   22. Scroll reveal
   -------------------------------------------------------------------------- */

/* --------------------------------------------------------------------------
   Scroll reveals
   Scoped to .js-enabled, set by an inline script in <head>. Without it a failed
   or blocked script would leave every revealed section invisible.

   TUNE THE WHOLE SITE FROM HERE - these four values drive every variant:
   -------------------------------------------------------------------------- */

:root {
  --reveal-distance: 22px;   /* how far it travels */
  --reveal-duration: 620ms;  /* how long it takes */
  --reveal-ease:     cubic-bezier(.2, .7, .3, 1);
  --reveal-stagger:  90ms;   /* gap between siblings in a staggered group */
}

@media (prefers-reduced-motion: no-preference) {

  .js-enabled .reveal {
    opacity: 0;
    transform: translateY(var(--reveal-distance));
    transition:
      opacity   var(--reveal-duration) var(--reveal-ease),
      transform var(--reveal-duration) var(--reveal-ease);
    transition-delay: var(--reveal-delay, 0ms);
    will-change: opacity, transform;
  }
  .js-enabled .reveal.is-visible { opacity: 1; transform: none; }

  /* Variants. Put any of these in the block editor under
     Advanced > Additional CSS class(es) - no code needed. */
  .js-enabled .reveal-fade          { transform: none; }
  .js-enabled .reveal-down          { transform: translateY(calc(var(--reveal-distance) * -1)); }
  .js-enabled .reveal-left          { transform: translateX(calc(var(--reveal-distance) * -1)); }
  .js-enabled .reveal-right         { transform: translateX(var(--reveal-distance)); }
  .js-enabled .reveal-scale         { transform: scale(.94); }
  .js-enabled .reveal-zip           { transform: translate(calc(var(--reveal-distance) * 1.6), calc(var(--reveal-distance) * -.6)); }
  .js-enabled .reveal-slow          { --reveal-duration: 1100ms; }
  .js-enabled .reveal-fast          { --reveal-duration: 320ms; }
  .js-enabled .reveal-far           { --reveal-distance: 56px; }
  .js-enabled .reveal-near          { --reveal-distance: 8px; }
  .js-enabled [class*="reveal-"].is-visible { transform: none; }

  /* Stagger children of a group: add reveal-stagger to the parent. */
  .js-enabled .reveal-stagger > * { --reveal-delay: calc(var(--i, 0) * var(--reveal-stagger)); }
}

/* --------------------------------------------------------------------------
   23. Prototype banner
   -------------------------------------------------------------------------- */

.proto-bar {
  background: var(--pz-ink); color: #fff;
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: .75rem;
  padding: var(--space-2xs) var(--gutter);
  display: flex; flex-wrap: wrap; gap: var(--space-s); align-items: center; justify-content: center;
  text-align: center;
}
.proto-bar strong { color: var(--pz-lime); }

/* --------------------------------------------------------------------------
   24. WordPress block bridge
   Maps core blocks onto the design system so the editor produces the approved
   look without anyone hand-writing classes.
   -------------------------------------------------------------------------- */

/* Core buttons adopt the .btn rules via registered block styles. */
.wp-block-button__link { 
  display: inline-flex; align-items: center; justify-content: center; gap: var(--space-2xs);
  min-height: 44px; padding: var(--space-xs) var(--space-m);
  font-family: var(--font-display); font-weight: 700; font-size: 1.0625rem; letter-spacing: .01em;
  text-decoration: none; border: 2px solid transparent; border-radius: var(--radius-m); cursor: pointer;
  transition: background var(--dur) var(--ease), color var(--dur) var(--ease), border-color var(--dur) var(--ease);
}
.is-style-pz-primary .wp-block-button__link { background: var(--color-cta); color: #fff; box-shadow: var(--shadow-s); }
.is-style-pz-primary .wp-block-button__link:hover { background: var(--color-cta-hover); color: #fff; }
.is-style-pz-ghost .wp-block-button__link { background: transparent; color: var(--pz-forest); border-color: var(--pz-forest); }
.is-style-pz-ghost .wp-block-button__link:hover { background: var(--pz-forest); color: #fff; }
.is-style-pz-on-dark .wp-block-button__link { background: transparent; color: #fff; border-color: rgba(255,255,255,.6); }
.is-style-pz-on-dark .wp-block-button__link:hover { background: #fff; color: var(--pz-forest); }

/* Core query loops stand in for the prototype's hand-written grids. The block
   renders <ul class="wp-block-post-template"><li class="wp-block-post">, so BOTH
   wrappers have to collapse or the real card/slide is a grandchild of the grid
   and never becomes a grid item — which stacked the carousel vertically instead
   of cross-fading it in one cell. */
.specials__grid .wp-block-post-template,
.specials__grid .wp-block-post,
.post-grid .wp-block-post-template,
.post-grid .wp-block-post,
.reviews__viewport .wp-block-post-template,
.reviews__viewport .wp-block-post,
.journey .wp-block-post-template,
.journey .wp-block-post { display: contents; }
.wp-block-post-template { list-style: none; padding: 0; margin: 0; }

/* WordPress's admin bar is position:fixed at the top of the viewport for logged
   in users, so a sticky header pinned to top:0 slides underneath it and gets its
   top 32px clipped. WP exposes its height as a custom property; fall back to 0
   for logged-out visitors, who have no admin bar. */
.site-header { top: var(--wp-admin--admin-bar--height, 0px); }

/* Reviews quote comes through post-content rather than a blockquote. */
.reviews__slide .reviews__quote p { margin: 0; }
.reviews__slide .wp-block-post-content { font-family: var(--font-display); }

/* The documented deviation #4 — header CTA hidden below desktop, because the
   sticky bottom bar already carries Book Now. The original rule targeted .btn;
   core renders .wp-block-button, so it needs both. */
@media (max-width: 1023px) {
  .header-actions .btn,
  .header-actions .wp-block-buttons,
  .header-actions .wp-block-button { display: none; }
}

/* Core's Navigation block supplies the mobile overlay and its own toggle, in
   place of the prototype's bespoke drawer. Give its button the same 46px target
   and forest outline the design specifies. */
.wp-block-navigation__responsive-container-open,
.wp-block-navigation__responsive-container-close {
  width: 46px; height: 46px;
  display: inline-flex; align-items: center; justify-content: center;
  border: 2px solid var(--pz-forest);
  border-radius: var(--radius-m);
  color: var(--pz-forest);
}
/* The open menu is position:fixed, and the header's backdrop-filter (or the
   transform that hides it on scroll) makes the header the box it is fixed to.
   That squeezed the whole menu into the 76px header: one link showing and the
   close button off screen. Core adds has-modal-open to <html> while it is open,
   so drop both for that moment. The longer selectors are needed because core's
   own white background and black text otherwise win. */
.has-modal-open .site-header { backdrop-filter: none; transform: none; }
.site-header .wp-block-navigation.site-nav .wp-block-navigation__responsive-container.is-menu-open {
  background-color: var(--pz-forest); color: #fff; padding: var(--space-l);
}
.site-header .site-nav .wp-block-navigation__responsive-container.is-menu-open a { color: #fff; }
.wp-block-navigation__responsive-container.is-menu-open .wp-block-navigation__responsive-container-close { border-color: rgba(255,255,255,.5); color: #fff; }

/* --------------------------------------------------------------------------
   25. Hero video facade
   Poster is a real Image block so it can be swapped in the editor. The YouTube
   iframe is only injected on activation, so nothing third-party touches first
   paint - which was the whole point of the facade in the proposal.
   -------------------------------------------------------------------------- */

.hero__media .hero__poster { position: absolute; inset: 0; margin: 0; }
.hero__media .hero__poster img { width: 100%; height: 100%; object-fit: cover; }

/* Compact and out of the headline's way. A full-bleed hit area put the play
   circle straight through the H1. */
.hero__play {
  position: absolute; z-index: 4;
  right: var(--gutter); bottom: calc(var(--edge-h) + var(--space-m));
  display: grid; place-items: center;
  background: transparent; border: 0; padding: 0; cursor: pointer;
  color: #fff;
}
@media (max-width: 767px) { .hero__play { bottom: calc(var(--edge-h) + var(--space-2xl)); } }
.hero__play-icon {
  display: grid; place-items: center;
  width: 60px; height: 60px; border-radius: 50%;
  background: rgba(0, 81, 47, .72);
  border: 3px solid rgba(255, 255, 255, .9);
  box-shadow: var(--shadow-m);
  padding-left: 6px;
  transition: transform var(--dur) var(--ease), background var(--dur) var(--ease);
}
.hero__play:hover .hero__play-icon { background: var(--color-cta); transform: scale(1.06); }
@media (prefers-reduced-motion: reduce) { .hero__play:hover .hero__play-icon { transform: none; } }
/* Once the iframe is in, the button has done its job. */
/* Hidden once the player reports it is actually playing - not merely once an
   iframe exists. If autoplay is refused the poster stays and the button is
   still there to press. */
.hero__media.is-playing .hero__play { display: none; }

/* Certified badges are Image blocks now, not .ph divs. */
.footer-badges .footer-badge { margin: 0; }
.footer-badges .footer-badge img {
  width: 64px; height: 64px; object-fit: contain;
  background: rgba(255, 255, 255, .92);
  border-radius: var(--radius-m); padding: 6px;
}

/* Specials can carry a featured image. */
.special-card__media { margin: 0 0 var(--space-xs); }
.special-card__media img { width: 100%; aspect-ratio: 16 / 9; object-fit: cover; border-radius: var(--radius-m); }

/* Grid images crop to a consistent ratio, so a row stays tidy whatever
   dimensions the uploaded photography happens to have. */
.highlights__grid figure.wp-block-image,
.post-grid figure.wp-block-image,
.split > figure.wp-block-image { margin: 0; }
.highlights__grid figure.wp-block-image img,
.post-grid figure.wp-block-image img {
  width: 100%; aspect-ratio: 4 / 3; object-fit: cover; border-radius: var(--radius-m);
}
.highlight-card figure.wp-block-image img { aspect-ratio: 4 / 3; }
.post-grid figure.wp-block-image img { aspect-ratio: 16 / 9; }
.split > figure.wp-block-image img { width: 100%; aspect-ratio: 16 / 9; object-fit: cover; border-radius: var(--radius-m); }
.info-panel figure.wp-block-image img { width: 100%; aspect-ratio: 16 / 9; object-fit: cover; border-radius: var(--radius-m); }

/* Core applies a blockGap margin to every child after the first. Inside our own
   grids that pushed cards 2 and 3 down by 24px while card 1 stayed put, so the
   headings never lined up. Grid and flex gaps already handle the spacing here. */
.highlights__grid > *,
.post-grid > *,
.specials__grid > *,
.split > *,
.site-footer__grid > *,
.hero__actions > *,
.header-actions > * { margin-block-start: 0 !important; margin-block-end: 0 !important; }

/* Every page header carries a photo behind the scrim. */
.page-hero { position: relative; isolation: isolate; overflow: hidden; }
.page-hero .page-hero__media {
  position: absolute; inset: 0; z-index: -2; margin: 0;
}
.page-hero .page-hero__media img { width: 100%; height: 100%; object-fit: cover; }
.page-hero::after {
  content: ""; position: absolute; inset: 0; z-index: -1;
  background: linear-gradient(180deg, rgba(0, 40, 24, .62), rgba(0, 40, 24, .84));
}

/* IBIS booking widget. The vendor ships its own stylesheet; this only sets the
   frame it sits in and a visible failure state, so a blocked CDN or a CORS
   rejection is obvious rather than a silent blank gap. */
.pz-ibis { min-height: 120px; }
.pz-ibis--failed .ibis-spinner { display: none; }

/* Two cuts of the hero footage: landscape for desktop, portrait for phones, so
   a 16:9 video isn't letterboxed into a tall hero. Only the matching poster is
   in the layout; the other is display:none so it is never fetched or painted. */
.hero__poster--portrait { display: none; }
@media (max-width: 767px) {
  .hero__poster--landscape { display: none; }
  .hero__poster--portrait { display: block; }
}

/* Background video.
   Two things YouTube forces on us:
   1. The player is ALWAYS 16:9, even for a Short - a portrait video is
      pillarboxed inside it. So the iframe must stay 16:9; sizing width and
      height independently (max() on both) breaks the ratio and YouTube then
      letterboxes on top, which is what put black bars behind the mobile hero.
   2. The title and logo are always painted over the frame - modestbranding and
      showinfo are both deprecated. The only reliable fix is to overscale so the
      chrome falls outside the visible box.
   Hence: fixed 16:9, then scale until the actual picture covers the hero. */

.hero__media .hero__video {
  position: absolute;
  /* Revealed by .is-playing, which JS sets on the player's own "playing"
     event. Before that the iframe is a black rectangle over the poster. */
  opacity: 0;
  transition: opacity .5s var(--ease, ease);
  top: 50%;
  left: 50%;
  width: 100%;
  height: auto;
  aspect-ratio: 16 / 9;
  transform: translate(-50%, -50%) scale(var(--hero-video-scale, 1.3));
  transform-origin: center;
  border: 0;
  pointer-events: none;
  z-index: 0;
}

.hero__media.is-playing .hero__video { opacity: 1; }
@media (prefers-reduced-motion: reduce) {
  .hero__media .hero__video { transition: none; }
}

@media (max-width: 767px) {
  /* A tall hero needs the video sized by HEIGHT, not width. At 375px wide a
     16:9 box is only ~211px tall, so covering a 633px hero by scaling alone
     needs 3x+ and the picture turns to mush. Deriving width from height keeps
     the ratio and leaves the scale doing only its real job: cropping the
     YouTube chrome off the edges. */
  .hero__media .hero__video {
    width: auto;
    height: 100%;
    --hero-video-scale: 1.35;
  }
}

/* The tag is optional. With no value the bound paragraph still renders, which
   left an empty coloured pill on the card - hide it rather than show a blank
   badge. Same for any other bound field that can legitimately be empty. */
.special-card__tag:empty,
.reviews__author:empty,
.post-card__meta:empty { display: none; }

/* Book Now sits at the foot of each offer card, pushed down so cards of
   different copy length still line their buttons up. */
.special-card__cta { margin-top: auto; padding-top: var(--space-s); }
.special-card__cta .wp-block-button__link { width: 100%; }

/* ---------------------------------------------------------------------------
   WPForms — mapped onto the designed form styles.

   The enquiry form is WPForms Lite now, so it actually sends. Its own markup
   uses different class names, so these rules give it the same grid, labels,
   inputs and button as the hand-built .form it replaced. Written against
   WPForms' classes rather than editing its templates, so a plugin update does
   not undo it.
   --------------------------------------------------------------------------- */
.wpforms-container .wpforms-form { display: grid; gap: var(--space-m); }
.wpforms-container .wpforms-field { display: grid; gap: var(--space-3xs); padding: 0; }
.wpforms-container .wpforms-field-label {
  font-weight: 600;
  font-size: var(--fs-small);
  margin: 0;
}
.wpforms-container .wpforms-field input[type="text"],
.wpforms-container .wpforms-field input[type="email"],
.wpforms-container .wpforms-field textarea {
  width: 100%;
  padding: var(--space-xs) var(--space-s);
  background: #fff;
  border: 2px solid var(--color-border-input);
  border-radius: var(--radius-m);
  font: inherit;
  max-width: none;
}
.wpforms-container .wpforms-field input:focus,
.wpforms-container .wpforms-field textarea:focus { border-color: var(--pz-forest); outline: none; }
.wpforms-container .wpforms-field textarea { min-height: 150px; resize: vertical; }

/* The submit button reuses the primary button rules. !important is needed
   because WPForms ships its own button colours at a higher specificity. */
.wpforms-container .wpforms-submit {
  padding: var(--space-xs) var(--space-l) !important;
  background: var(--color-cta) !important;
  color: #fff !important;
  border: 0 !important;
  border-radius: var(--radius-m) !important;
  font: inherit !important;
  font-weight: 700 !important;
  cursor: pointer;
}
.wpforms-container .wpforms-submit:hover { background: var(--color-cta-hover) !important; }

/* Validation messages, in the site's own error colour rather than WPForms red. */
.wpforms-container label.wpforms-error { font-size: var(--fs-small); color: #b3261e; }
.wpforms-container .wpforms-field input.wpforms-error,
.wpforms-container .wpforms-field textarea.wpforms-error { border-color: #b3261e; }
.wpforms-confirmation-container-full {
  padding: var(--space-s) var(--space-m);
  border: 2px solid var(--pz-forest);
  border-radius: var(--radius-m);
  background: #fff;
}

/* ---------------------------------------------------------------------------
   Hero video — true cover at every viewport.

   The iframe was sized as 100% width at 16:9, scaled up 1.3, which covers a
   wide viewport but not a narrow, tall one: at roughly 768-1024px wide with a
   tall window (a tablet held upright), 16:9 at that width is shorter than the
   hero, so the poster showed above and below the video as a seam.

   object-fit does not apply to an iframe, so cover is done with container
   query units instead: the frame takes the larger of the container's own size
   and the size the other axis demands at 16:9. The older rules above stay as
   the fallback for a browser without container units.
   --------------------------------------------------------------------------- */
@supports (width: 1cqw) {
  .hero__media { container-type: size; }

  .hero__media .hero__video {
    width: max(100cqw, calc(100cqh * 16 / 9));
    height: max(100cqh, calc(100cqw * 9 / 16));
    aspect-ratio: auto;
    /* A little over 1 so the edges of the frame stay off-screen while the
       player letterboxes its own content during buffering. */
    transform: translate(-50%, -50%) scale(var(--hero-video-scale, 1.22));
  }

  @media (max-width: 767px) {
    /* Phones crop harder: the landscape cut has to fill a tall hero, and the
       rider sits centre-frame, so scaling up keeps them in shot. */
    .hero__media .hero__video { --hero-video-scale: 1.3; }
  }
}

/* ===========================================================================
   Client-editable sections (Kelsey, 24 Sep)

   The badges, counters, rating, detail lists and rotating headline were
   shortcodes, which meant the client could not see or change them in the
   editor. They are ordinary blocks now — images, headings, paragraphs and
   tables — so everything is visible and editable on the page. These rules give
   those blocks the same appearance the shortcodes produced.
   =========================================================================== */

/* --- Award badges, now image blocks ---------------------------------------
   Position along the cable used to come from an inline --k per badge, written
   by PHP. It comes from the badge's position in the list instead, so the
   client can add, remove or swap a badge image and the spacing still works.
   Designed for four to six badges. */
.badge-wire__track > .badge-wire__item:nth-child(1) { --k: .10; --i: 5; }
.badge-wire__track > .badge-wire__item:nth-child(2) { --k: .25; --i: 4; }
.badge-wire__track > .badge-wire__item:nth-child(3) { --k: .40; --i: 3; }
.badge-wire__track > .badge-wire__item:nth-child(4) { --k: .55; --i: 2; }
.badge-wire__track > .badge-wire__item:nth-child(5) { --k: .70; --i: 1; }
.badge-wire__track > .badge-wire__item:nth-child(6) { --k: .85; --i: 0; }
.badge-wire__track > .badge-wire__item:nth-child(7) { --k: .95; --i: 0; }

/* A badge image behaves as the disc did: a white circle on the cable. */
.badge-wire__item.wp-block-image { margin: 0; }
.badge-wire__item.wp-block-image img {
  width: var(--disc);
  height: var(--disc);
  object-fit: contain;
  padding: 7px;
  background: #fff;
  border-radius: 50%;
  box-shadow: 0 6px 18px rgba(0, 0, 0, .18);
  animation: zip-in 1s cubic-bezier(.16, .84, .3, 1) backwards;
  animation-delay: calc(var(--i, 0) * 130ms + 250ms);
  transition: transform var(--dur, .25s) var(--ease, ease);
}
.badge-wire__item.wp-block-image img:hover { transform: translateY(-4px) scale(1.04); }

@media (max-width: 767px) {
  .badge-wire__item.wp-block-image img { animation: none; }
}
@media (prefers-reduced-motion: reduce) {
  .badge-wire__item.wp-block-image img { animation: none; transition: none; }
  .badge-wire__item.wp-block-image img:hover { transform: none; }
}

/* --- Counters, now heading + paragraph blocks -----------------------------
   The block editor wraps these in its own elements, so the theme's margins
   have to be reset or each figure sits low in its cell. */
.stat-bar__grid.wp-block-group { display: grid; }
/* Core adds a top margin to every block after the first, which dropped
   counters two to four 24px below the first one. */
.stat-bar__grid.wp-block-group > * { margin-block: 0; }
.stat-bar__item.wp-block-group > * { margin-block: 0; }
.stat-bar__num.wp-block-heading { margin: 0; }

/* --- Detail lists, now table blocks ---------------------------------------
   A table is editable in place — the client clicks a cell and types — where
   the old list was markup inside a shortcode. Styled to read as the original
   label/value rows, not as a spreadsheet. */
.spec-table.wp-block-table { margin: 0; }
.spec-table.wp-block-table table { border-collapse: collapse; width: 100%; }
.spec-table.wp-block-table td {
  padding: var(--space-2xs) 0;
  border: 0;
  border-bottom: 1px solid var(--pz-rule);
  word-break: normal;
}
.spec-table.wp-block-table tr td:first-child { color: var(--color-text-muted); }
.spec-table.wp-block-table tr td:last-child { font-weight: 600; text-align: right; }
.spec-table.wp-block-table tr:last-child td { border-bottom: 0; }

/* --- The rotating headline ------------------------------------------------
   The phrases are a plain list on the page, which is what the client edits.
   JS swaps the first one in and hides the rest; without JS the list simply
   reads as a list, which is an acceptable fallback. */
.rotator-source { display: none; }
.rotator { display: inline-block; color: var(--color-cta); }

/* --- Google map embed ----------------------------------------------------- */
.pz-map {
  position: relative;
  aspect-ratio: 16 / 10;
  border-radius: var(--radius-m);
  overflow: hidden;
  background: var(--pz-mist, #eef2f0);
}
.pz-map iframe { position: absolute; inset: 0; width: 100%; height: 100%; border: 0; }
.pz-map__empty {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  padding: var(--space-m);
  text-align: center;
  color: var(--color-text-muted);
  font-size: var(--fs-small);
}

/* --- Blog listing ---------------------------------------------------------
   The cards were styled against .wp-block-image, but a featured image renders
   as .wp-block-post-featured-image, so none of it applied: full-width photos
   at whatever shape they happened to be, in a single column. */
/* The blog listing was built as one grid on .post-grid, with the list and each
   post set to display:contents so every post's parts became grid items. With
   four parts per post that put the photo, date, title and excerpt of different
   posts into the same row — the "showing up weird" Kelsey reported.

   The grid moves onto the list, and each post becomes a flex column card. That
   means .post-grid must stop being a grid itself, or the list lands inside a
   single column of it and the cards are squeezed to a third of their width. */
.post-grid { display: block; }

/* Core gives every list item after the first a blockGap margin, which pushed
   cards two and three down while card one stayed put. The grid gap handles the
   spacing. Same reason as the .post-grid > * reset further up, but the grid
   lives on the list now, so the reset has to follow it. */
.post-grid .wp-block-post-template > * { margin-block-start: 0 !important; margin-block-end: 0 !important; }

.post-grid .wp-block-post-template {
  display: grid;
  gap: var(--space-xl);
  grid-template-columns: 1fr;
}
@media (min-width: 640px) {
  .post-grid .wp-block-post-template { grid-template-columns: repeat(2, 1fr); }
}
@media (min-width: 1024px) {
  .post-grid .wp-block-post-template { grid-template-columns: repeat(3, 1fr); }
}
.post-grid .wp-block-post {
  display: flex;
  flex-direction: column;
  gap: var(--space-2xs);
}
.post-grid .wp-block-post-featured-image {
  margin: 0 0 var(--space-3xs);
  border-radius: var(--radius-m);
  overflow: hidden;
}
.post-grid .wp-block-post-featured-image img {
  width: 100%;
  aspect-ratio: 16 / 9;
  object-fit: cover;
  display: block;
  transition: transform .5s var(--ease, ease);
}
.post-grid .wp-block-post-featured-image a:hover img,
.post-grid .wp-block-post-featured-image a:focus-visible img { transform: scale(1.04); }
.post-grid .wp-block-post-title { margin: 0; font-size: 1.25rem; line-height: 1.3; }
.post-grid .wp-block-post-title a { text-decoration: none; }
.post-grid .wp-block-post-title a:hover { text-decoration: underline; }
.post-grid .wp-block-post-date { margin: 0; }
.post-grid .wp-block-post-excerpt { margin: 0; }
.post-grid .wp-block-post-excerpt p { color: var(--color-text-muted); font-size: var(--fs-small); margin: 0; }
.post-grid .wp-block-query-pagination { margin-top: var(--space-xl); }

/* Single post: the featured image reads as the page header. */
.page-hero__media.wp-block-post-featured-image { margin: 0; }
.page-hero__media.wp-block-post-featured-image img { width: 100%; height: 100%; object-fit: cover; }

/* Category and tag pills under a post. */
.tag-list a {
  display: inline-block;
  margin: 0 var(--space-3xs) var(--space-3xs) 0;
  padding: 2px var(--space-2xs);
  border: 1px solid var(--pz-rule);
  border-radius: 999px;
  font-size: var(--fs-small);
  text-decoration: none;
  transition: background var(--dur, .25s) var(--ease, ease), border-color var(--dur, .25s) var(--ease, ease);
}
.tag-list a:hover { background: var(--pz-forest); border-color: var(--pz-forest); color: #fff; }

.post-nav { margin-top: var(--space-xl); gap: var(--space-m); }
.post-nav .wp-block-post-navigation-link a { text-decoration: none; font-weight: 600; }
.post-nav .wp-block-post-navigation-link a:hover { text-decoration: underline; }

@media (prefers-reduced-motion: reduce) {
  .post-grid .wp-block-post-featured-image img,
  .tag-list a { transition: none; }
  .post-grid .wp-block-post-featured-image a:hover img { transform: none; }
}

/* The wordmark beside the logo is a link home too, so either half of the
   masthead works the way a visitor expects. */
a.site-logo__word { text-decoration: none; color: inherit; }
a.site-logo__word:hover small,
a.site-logo__word:hover strong { color: var(--pz-forest); }
a.site-logo__word small,
a.site-logo__word strong { transition: color var(--dur, .25s) var(--ease, ease); }
.custom-logo-link img { transition: transform var(--dur, .25s) var(--ease, ease); }
.custom-logo-link:hover img { transform: rotate(-4deg) scale(1.05); }
@media (prefers-reduced-motion: reduce) {
  a.site-logo__word small, a.site-logo__word strong, .custom-logo-link img { transition: none; }
  .custom-logo-link:hover img { transform: none; }
}

/* ===========================================================================
   Booking page
   ===========================================================================
   The calendar sat in a dashed grey box left over from the wireframe stage,
   with build notes printed above and below it. It now reads as a booking panel,
   and when the calendar cannot load the visitor gets somewhere to go instead of
   an error message over a month of struck-out dates. */

.booking-card {
  background: #fff;
  border: 1px solid var(--pz-rule);
  border-top: 4px solid var(--pz-forest);
  border-radius: var(--radius-l);
  padding: var(--space-l);
  box-shadow: var(--shadow-m);
}
.booking-card > h2 { font-size: var(--fs-h3); margin: 0 0 var(--space-3xs); }
.booking-card > .measure { color: var(--color-text-muted); margin-bottom: var(--space-m); }

@media (max-width: 599px) {
  .booking-card { padding: var(--space-m); }
}

/* The fallback only exists once the widget has reported failure. */
.pz-ibis__fallback { display: none; }
.pz-ibis--failed .pz-ibis__fallback {
  display: block;
  padding: var(--space-m);
  border: 1px solid var(--pz-rule);
  border-radius: var(--radius-m);
  background: var(--pz-mist, #f4f7f5);
  text-align: center;
}
.pz-ibis__fallback h3 { font-size: var(--fs-h4, 1.25rem); margin: 0 0 var(--space-3xs); }
.pz-ibis__fallback p { color: var(--color-text-muted); margin: 0 auto var(--space-m); max-width: 44ch; }
.pz-ibis__actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-s);
  justify-content: center;
}

/* Hide the vendor's own broken calendar once we have taken over, so the visitor
   is not choosing between our panel and a month of unavailable dates. */
.pz-ibis--failed [class^="ibis-widget-"] { display: none; }

/* The reassurance points read as three ticked cards rather than a run-on line. */
.reassure {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--space-s);
  margin-top: var(--space-l);
}
@media (min-width: 720px) {
  .reassure { grid-template-columns: repeat(3, 1fr); }
}
.reassure span {
  display: flex;
  align-items: flex-start;
  gap: var(--space-2xs);
  padding: var(--space-s);
  background: #fff;
  border: 1px solid var(--pz-rule);
  border-radius: var(--radius-m);
  font-size: var(--fs-small);
  line-height: 1.5;
  color: var(--color-text);
  transition: border-color var(--dur, .25s) var(--ease, ease), transform var(--dur, .25s) var(--ease, ease);
}
.reassure span:hover { border-color: var(--pz-forest); transform: translateY(-2px); }

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

/* ===========================================================================
   The editor's view (Kelsey, 27 Sep)
   ===========================================================================
   These styles are loaded into the block editor as well as the site, so
   anything positioned for the front end lands in the editor too. Two things
   suffered: the award badges hang off an invisible cable and piled on top of
   each other, and the list of rotating phrases was hidden by the very rule that
   hides it from visitors — so it could not be edited. */

/* The phrase list is hidden on the site only. .wp-site-blocks exists on the
   front end and never in the editor, which is what separates the two. */
.wp-site-blocks .rotator-source { display: none; }

.editor-styles-wrapper .rotator-source {
  display: block;
  margin: var(--space-2xs) 0 0;
  padding: var(--space-2xs) var(--space-s);
  border-left: 3px solid var(--pz-lime);
  background: #f6f9f4;
  font-size: var(--fs-small);
}
.editor-styles-wrapper .rotator-source::before {
  content: "Rotating phrases — edit, add or remove a line. Hidden on the website.";
  display: block;
  margin-bottom: var(--space-3xs);
  font-weight: 600;
  color: var(--color-text-muted);
}

/* In the editor the badges sit as a plain row, so they can be clicked,
   replaced and reordered without overlapping each other. */
.editor-styles-wrapper .badge-wire { height: auto; margin: var(--space-s) 0; overflow: visible; }
.editor-styles-wrapper .badge-wire__track {
  position: static;
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-s);
  width: auto;
  animation: none;
}
.editor-styles-wrapper .badge-wire__item { position: static; transform: none; }
.editor-styles-wrapper .badge-wire__item.wp-block-image img { animation: none; }

/* The editor makes every block position:relative, which collapsed the hero
   backdrop to nothing: no poster behind the headline, and the video shortcode
   squashed into a sliver in the corner. Put the backdrop back and park the
   shortcode top right as a small box that can still be clicked and edited. */
.editor-styles-wrapper .hero .hero__media { position: absolute; z-index: auto; }
.editor-styles-wrapper .hero__media .hero__poster { z-index: -2; }
.editor-styles-wrapper .hero__media .wp-block-shortcode {
  position: absolute;
  top: var(--space-s);
  right: var(--space-s);
  z-index: 3;
  width: 21rem;
  max-width: 60%;
  margin: 0;
}

/* The angled white edge under the hero is decoration. It used to be a shortcode
   block sitting in the page, which the client could delete by accident and
   which showed as an unexplained grey box in the editor. It is drawn here
   instead, so there is nothing to see or break. */
.hero::before {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: -1px;
  height: var(--edge-h);
  z-index: 2;
  pointer-events: none;
  background:
    url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 12" preserveAspectRatio="none"><path d="M0 12 L100 3 L100 12 Z" fill="%23fff"/><line x1="0" y1="12" x2="100" y2="3" stroke="%231a1d1b" stroke-width="0.35" stroke-linecap="round"/></svg>')
    no-repeat center / 100% 100%;
}

/* The star rating is an image now rather than five ★ characters, which drew
   differently on Windows and Android. It arrives two ways: as a bare <img>
   from [pz_stars], and as an Image block in the homepage hero, where the class
   lands on the <figure> and the <img> sits inside it. Size the <img> in both
   cases, or the hero one renders at its full width. Inline-block so the stars
   follow the text alignment of whatever they sit in. The block editor writes
   an inline height:auto on the image, so max-height carries the size there. */
img.stars--img, .stars--img img { display: inline-block; vertical-align: middle; width: auto; max-width: none; height: var(--stars-h, 1.05em); max-height: var(--stars-h, 1.05em); }
figure.stars--img { flex: none; margin: 0; line-height: 0; }
.rating-inline .stars--img { --stars-h: .95em; }
.reviews__slide .stars--img, .faq-group .stars--img { --stars-h: 1.15em; }

/* ===========================================================================
   Refinements from the client review (Kelsey's October notes)
   =========================================================================== */

/* --- Hero: the video is the centrepiece ------------------------------------
   Taller, so the video fills the screen down to just above the fold. Below
   1024px the sticky Book Now bar covers the bottom of the viewport, so the
   hero stops above it rather than running underneath. */
.hero {
  /* Half a badge plus a margin, so the badges on the join stay in view. */
  --hero-foot: calc(46px + var(--space-l));
  min-height: clamp(560px, calc(100svh - var(--header-h) - var(--hero-foot)), 1000px);
}
@media (max-width: 1023px) {
  .hero { --hero-foot: calc(var(--book-bar-h) + var(--space-s)); }
}
/* With badges straddling the join, stop high enough that they clear the bar. */
@media (min-width: 768px) and (max-width: 1023px) {
  .hero { --hero-foot: calc(var(--book-bar-h) + 46px + var(--space-s)); }
}

/* The content block sits on the left, lined up with the logo, instead of in
   a centred 680px column. The text itself keeps its 680px measure. */
.hero .hero__content {
  max-width: none;
  width: min(100% - (var(--gutter) * 2), var(--width-wide));
}
.hero .hero__content > * { max-width: 680px; }

/* Lighter scrim. Only the bottom left, where the text sits, is darkened; the
   rest of the frame is left close to the raw video. Measured against the
   poster frame, sampling the text boxes: the brightest tenth of the lead's
   background gives 5.0:1 (H1 5.7:1, rating 11.8:1). The old scrim gave 9.0:1
   there, which is why the video looked muddy. Re-measure if the text moves or
   the video changes. Below 1024px the text runs most of the width, so an even
   wash from the bottom is used instead. */
.hero::after {
  background:
    radial-gradient(110% 95% at 0% 100%,
      rgba(0, 30, 18, .72) 0%,
      rgba(0, 30, 18, .50) 40%,
      rgba(0, 30, 18, 0) 75%),
    linear-gradient(180deg,
      rgba(0, 30, 18, .14) 0%,
      rgba(0, 30, 18, 0) 28%,
      rgba(0, 30, 18, 0) 62%,
      rgba(0, 30, 18, .30) 100%);
}
@media (max-width: 1023px) {
  .hero::after {
    background: linear-gradient(180deg,
      rgba(0, 30, 18, .14) 0%,
      rgba(0, 30, 18, .06) 32%,
      rgba(0, 30, 18, .50) 64%,
      rgba(0, 30, 18, .70) 100%);
  }
}

/* --- Flat join, badges straddling it ----------------------------------------
   The angled white edge is gone: the video runs full width to the bottom of
   the hero, and the thin line is the zipline cable the badges hang on. */
.hero::before {
  height: 2px;
  bottom: 0;
  background: #1a1d1b;
}

@media (min-width: 768px) {
  .badge-wire {
    --rise: 0px;
    height: var(--disc);
    margin-top: calc(var(--disc) / -2);
    margin-bottom: var(--space-s);
  }
  /* A flat, evenly spaced row on the content width. The wire itself stays
     full width so the badges still slide in from the edge of the screen. */
  .badge-wire__track {
    position: static;
    display: flex;
    align-items: center;
    justify-content: space-between;
    height: 100%;
    width: min(100% - (var(--gutter) * 2), var(--width-content));
    margin-inline: auto;
  }
  .badge-wire__item { position: static; transform: none; }

  .hero__play { bottom: calc(var(--space-xl) + 46px); }
}
@media (max-width: 767px) {
  .hero__play { bottom: var(--space-l); }
}

/* --- Mobile header -----------------------------------------------------------
   Hamburger on the right; a larger logo that hangs over the top of the hero. */
@media (max-width: 1023px) {
  .site-header__inner > .site-logo { margin-right: auto; }
}

/* Search sits before the hamburger on phones, so the menu button is the one
   on the far right. */
@media (max-width: 599px) {
  .site-header__inner > .site-search { order: 2; }
  .site-header__inner > .site-nav { order: 3; }
  .site-header__inner > .header-actions { order: 4; }
}
@media (max-width: 767px) {
  .site-logo .wp-block-site-logo {
    position: relative;
    z-index: 2;
    align-self: flex-start;
    margin-bottom: -34px;
  }
  .site-logo .wp-block-site-logo img {
    width: 76px;
    height: 76px;
    border-radius: 50%;
    background: #fff;
    box-shadow: 0 4px 14px rgba(0, 0, 0, .2);
  }
}

/* --- Search ------------------------------------------------------------------
   Core's Search block, set to a magnifier that opens a field when clicked.
   Styled to match the menu button: 46px, forest outline. */
.site-search .wp-block-search__button {
  width: 46px;
  height: 46px;
  min-width: 46px;
  margin: 0;
  padding: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: transparent;
  color: var(--pz-forest);
  border: 0;
  border-radius: 50%;
  transition: color var(--dur) var(--ease), transform var(--dur) var(--ease);
}
.site-search .wp-block-search__button svg { width: 24px; height: 24px; fill: currentColor; }
/* No box: the icon itself changes colour and grows slightly on hover, and
   stays green while the field is open. */
.site-search .wp-block-search__button:hover,
.site-search .wp-block-search__button:focus-visible,
.site-search:not(.wp-block-search__searchfield-hidden) .wp-block-search__button { color: var(--pz-green); transform: scale(1.15); }
.site-search .wp-block-search__button:active { transform: scale(.95); }

/* --- Photo backgrounds on the reviews and quote bands ------------------------
   Both are Cover blocks now, so the photo and how dark it is can be changed in
   the editor. Undo the cover's own 430px minimum height and side padding; the
   sections keep their existing spacing. */
.wp-block-cover.reviews,
.wp-block-cover.cta-band { min-height: 0; padding-inline: 0; }
.wp-block-cover.reviews > .wp-block-cover__inner-container,
.wp-block-cover.cta-band > .wp-block-cover__inner-container { width: 100%; }

/* --- Full-width photo on The Tour ------------------------------------------ */
.wp-block-image.feature-image { margin-block: 0; }
.wp-block-image.feature-image img { display: block; width: 100%; min-height: 280px; }
.wp-block-image.feature-image + .wp-block-group { margin-block-start: 0; }

/* ===========================================================================
   Motion (Kelsey's October notes, V2)
   Scroll reveals, photo unveils, parallax, hover zoom and page transitions.
   All of it switches off under prefers-reduced-motion.
   =========================================================================== */

/* --- Page to page --------------------------------------------------------
   Browsers that support cross-document view transitions cross-fade between
   pages instead of flashing white. Others simply load as before. */
@view-transition { navigation: auto; }
::view-transition-old(root),
::view-transition-new(root) { animation-duration: .35s; }

/* --- Hero entrance ---------------------------------------------------------
   The headline, lead and buttons rise in one after another on page load. */
@keyframes pz-rise {
  from { opacity: 0; transform: translateY(28px); }
  to { opacity: 1; transform: none; }
}
@keyframes pz-fade { from { opacity: 0; } to { opacity: 1; } }
@media (prefers-reduced-motion: no-preference) {
  .js-enabled .hero__content > *,
  .js-enabled .page-hero .container > * {
    animation: pz-rise .9s var(--reveal-ease) both;
  }
  .js-enabled .hero__content > :nth-child(2),
  .js-enabled .page-hero .container > :nth-child(2) { animation-delay: .14s; }
  .js-enabled .hero__content > :nth-child(3),
  .js-enabled .page-hero .container > :nth-child(3) { animation-delay: .28s; }
  .js-enabled .hero__content > :nth-child(n+4) { animation-delay: .42s; }
  /* These carry their own entrance, so the scroll reveal must not hide them. */
  .js-enabled .hero__content .reveal,
  .js-enabled .page-hero .reveal { opacity: 1; transform: none; transition: none; }
  .js-enabled .hero__media .hero__poster img { animation: pz-fade 1.2s ease both; }
}

/* --- Photo unveil -----------------------------------------------------------
   The frame opens upward and the picture settles from slightly zoomed in. */
@media (prefers-reduced-motion: no-preference) {
  .pz-unveil { overflow: hidden; }
  .pz-unveil:not(.is-in) { clip-path: inset(14% 0 0 0 round var(--radius-m)); opacity: 0; }
  .pz-unveil {
    clip-path: inset(0 0 0 0 round var(--radius-m));
    transition: clip-path 1s var(--reveal-ease), opacity .6s ease;
    transition-delay: var(--reveal-delay, 0ms);
  }
  .pz-unveil img { scale: 1.12; transition: scale 1.4s var(--reveal-ease), transform .7s var(--reveal-ease); transition-delay: var(--reveal-delay, 0ms), 0ms; }
  .pz-unveil.is-in img { scale: 1; }
}

/* --- Hover zoom inside the frame ----------------------------------------------
   Gallery photos, highlight photos and blog and special cards. The photo grows
   within its box; the box itself stays put. */
.highlights__grid figure,
.split > figure.wp-block-image,
.post-grid .wp-block-post-featured-image,
.special-card__media,
.highlight-card figure { overflow: hidden; border-radius: var(--radius-m); }
@media (hover: hover) and (prefers-reduced-motion: no-preference) {
  .highlights__grid figure img,
  .split > figure.wp-block-image img,
  .post-grid .wp-block-post-featured-image img,
  .special-card__media img,
  .highlight-card figure img { transition: transform .7s var(--reveal-ease), filter .7s var(--reveal-ease); }
  .highlights__grid figure:hover img,
  .split > figure.wp-block-image:hover img,
  .post-grid .wp-block-post:hover .wp-block-post-featured-image img,
  .special-card:hover .special-card__media img,
  .highlight-card:hover figure img { transform: scale(1.08); filter: saturate(1.12); }

  /* Cards lift slightly as well. */
  .post-grid .wp-block-post,
  .special-card { transition: transform .45s var(--reveal-ease), box-shadow .45s var(--reveal-ease); }
  .post-grid .wp-block-post:hover,
  .special-card:hover { transform: translateY(-4px); }
  .special-card:hover { box-shadow: var(--shadow-l); }
}

/* --- Parallax ------------------------------------------------------------------
   The script moves these as the page scrolls. They are oversized so the edge
   never shows while they drift. */
.wp-block-cover__image-background.pz-parallax { top: -22%; bottom: auto; height: 144%; will-change: transform; }
.page-hero .page-hero__media img.pz-parallax { position: absolute; left: 0; top: -22%; height: 144%; will-change: transform; }
.feature-image { overflow: hidden; }
.feature-image img.pz-parallax { scale: 1.3; will-change: transform; }
.hero__media.pz-parallax { will-change: transform; }

/* --- Buttons and links ------------------------------------------------------ */
@media (prefers-reduced-motion: no-preference) {
  .wp-block-button__link {
    transition: background-color var(--dur) var(--ease), color var(--dur) var(--ease),
                border-color var(--dur) var(--ease), transform var(--dur) var(--ease),
                box-shadow var(--dur) var(--ease);
  }
  .wp-block-button__link:hover { transform: translateY(-2px); box-shadow: 0 8px 20px rgba(0, 60, 35, .22); }
  .wp-block-button__link:active { transform: translateY(0); box-shadow: none; }

  /* Menu links get an underline that grows from the left. */
  .site-nav .wp-block-navigation-item__content { position: relative; }
  .site-nav .wp-block-navigation-item__content::after {
    content: "";
    position: absolute; left: 0; right: 0; bottom: -4px;
    height: 2px;
    background: var(--color-cta);
    transform: scaleX(0);
    transform-origin: left;
    transition: transform var(--dur-slow) var(--reveal-ease);
  }
  .site-nav .wp-block-navigation-item__content:hover::after,
  .site-nav .current-menu-item .wp-block-navigation-item__content::after { transform: scaleX(1); }
}

/* --- Reading progress -------------------------------------------------------
   A thin lime line along the bottom of the header fills as the page scrolls.
   Browsers without scroll-linked animation simply do not show it. */
@supports (animation-timeline: scroll()) {
  @media (prefers-reduced-motion: no-preference) {
    .site-header::after {
      content: "";
      position: absolute; left: 0; right: 0; bottom: -1px;
      height: 3px;
      background: var(--pz-lime);
      transform-origin: left;
      animation: pz-progress linear both;
      animation-timeline: scroll(root);
    }
    @keyframes pz-progress { from { transform: scaleX(0); } to { transform: scaleX(1); } }
  }
}

/* --- Hero video, now a file in the Media Library --------------------------------
   Two Video blocks sit in the hero: landscape and portrait. The script keeps
   the one that suits the screen. Hidden until it is actually playing, so a
   video that never starts leaves the poster rather than a black box. */
.hero__media .hero__file { position: absolute; inset: 0; margin: 0; z-index: 1; opacity: 0; transition: opacity .8s ease; }
.hero__media .hero__file video { width: 100%; height: 100%; object-fit: cover; display: block; }
.hero__media.is-playing .hero__file { opacity: 1; }
.hero__media.has-file-video .hero__play { display: none; }

.hero__toggle {
  position: absolute; z-index: 4;
  right: var(--gutter);
  bottom: calc(46px + var(--space-l));
  width: 40px; height: 40px;
  display: grid; place-items: center;
  border-radius: 50%;
  border: 2px solid rgba(255, 255, 255, .75);
  background: rgba(0, 41, 26, .45);
  color: #fff;
  cursor: pointer;
  opacity: .8;
  transition: opacity var(--dur) var(--ease), background var(--dur) var(--ease);
}
.hero__toggle:hover, .hero__toggle:focus-visible { opacity: 1; background: rgba(0, 41, 26, .75); }
.hero__toggle .icon-play { display: none; }
.hero__toggle.is-paused .icon-play { display: block; }
.hero__toggle.is-paused .icon-pause { display: none; }
@media (max-width: 767px) { .hero__toggle { bottom: var(--space-m); } }

/* In the editor the two videos sit as small boxes top right, so they can be
   clicked and swapped without covering the headline. */
.editor-styles-wrapper .hero__media .hero__file {
  position: absolute; inset: auto; top: var(--space-s); right: var(--space-s);
  width: 12rem; opacity: 1; z-index: 3;
}
.editor-styles-wrapper .hero__media .hero__file--portrait { top: calc(var(--space-s) + 8rem); width: 5rem; }

/* --- The Tour: "How the day runs" ---------------------------------------------
   The text was held to a narrow column while the accordion runs the full
   width, so on a laptop it wrapped early and left the right half empty. Let it
   widen with the screen, still short of a line too long to read comfortably. */
@media (min-width: 768px) {
  .container:has(> .journey) > .section-head { max-width: min(100%, 52rem); }
  .container:has(> .journey) > .section-head .lead { max-width: none; }
  .journey__body { max-width: min(100%, 56rem); }
}

/* ===========================================================================
   Kelsey's October notes, V3
   =========================================================================== */

/* --- Section headings ----------------------------------------------------------
   Same change as "How the day runs": the intro text was held to a narrow
   column on the left while the cards below run the full width. Every section
   heading now widens with the screen, still short of an uncomfortable line. */
@media (min-width: 768px) {
  .section-head { max-width: min(100%, 52rem); }
  .section-head .lead { max-width: none; }
}

/* --- Stat bar ----------------------------------------------------------------------
   The grid draws a line to the right of and under every stat, and relied on a
   -1px margin to push the last ones outside the box. Nothing clipped them, so
   a stray line showed down the right-hand edge. Clip the wrapper so only the
   dividers between stats remain. */
.container:has(> .stat-bar__grid) { overflow: hidden; }

/* --- Contact: "Find us" ---------------------------------------------------------------
   Sits level with the top of the form instead of halfway down it, and stays in
   view while the visitor scrolls the form. --sticky-top is set by the script:
   below the header when the panel fits the screen, or low enough that its
   bottom stays reachable on a short laptop screen. */
@media (min-width: 768px) {
  .split:has(> .info-panel) { align-items: start; }
  .split > .info-panel {
    position: sticky;
    top: var(--sticky-top, calc(var(--header-h) + var(--wp-admin--admin-bar--height, 0px) + 1rem));
  }
}

/* --- Booking panel ---------------------------------------------------------------------
   The calendar is centred in the card but its text was held to a narrow
   column on the left. Let it use the card's full width. */
.booking-card .measure { max-width: none; }

/* ===========================================================================
   Kelsey's October notes, round 4
   =========================================================================== */

/* --- Stat bar: a blank stat never shows -------------------------------------------
   If a stat is added in the editor and left empty, it is skipped rather than
   drawn as an empty bordered box. */
.stat-bar__item:empty { display: none; }
.stat-bar__item:not(:has(.stat-bar__num:not(:empty), .stat-bar__label:not(:empty))) { display: none; }

/* --- Tour: jump to the essentials -------------------------------------------------- */
.page-hero .wp-block-buttons { margin-top: var(--space-m); }
@media (prefers-reduced-motion: no-preference) {
  .page-hero .container > .wp-block-buttons { animation: pz-rise .9s var(--reveal-ease) .42s both; }
}

/* --- Tour: video below the gallery ---------------------------------------------------
   Takes the place of the full-width photo. Nothing downloads until it is
   scrolled near; the poster (the old photo) holds the space until then. */
.wp-block-video.feature-video { position: relative; margin-block: 0; background: var(--pz-forest); }
.wp-block-video.feature-video video {
  display: block; width: 100%;
  aspect-ratio: 16 / 9; max-height: 85vh; min-height: 280px;
  object-fit: cover;
}
.wp-block-video.feature-video + .wp-block-group { margin-block-start: 0; }
.feature-video .hero__toggle { bottom: var(--space-m); }

/* ===========================================================================
   Kelsey's October notes, round 5
   =========================================================================== */

/* --- Tour: the promo film, played from YouTube on click -----------------------------
   An ordinary Image block, linked to the YouTube video. Until it is clicked
   it is just a photo, so nothing from YouTube loads with the page; the click
   swaps it for the player, already playing. Without JavaScript the link
   simply opens the video on YouTube. */
.wp-block-image.pz-youtube { position: relative; background: var(--pz-forest); }
.wp-block-image.pz-youtube img { aspect-ratio: 16 / 9; max-height: 85vh; object-fit: cover; }
.pz-youtube > a { display: block; position: relative; }
.pz-youtube > a::after {
  content: "";
  position: absolute; left: 50%; top: 50%;
  width: 88px; height: 88px;
  margin: -44px 0 0 -44px;
  border-radius: 50%;
  background: rgba(0, 41, 26, .55) url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M9 6.5v11l9-5.5z' fill='%23fff'/%3E%3C/svg%3E") center / 46px no-repeat;
  border: 3px solid #fff;
  box-shadow: 0 10px 30px rgba(0, 0, 0, .35);
  transition: transform var(--dur) var(--ease), background-color var(--dur) var(--ease);
}
.pz-youtube > a:hover::after,
.pz-youtube > a:focus-visible::after { transform: scale(1.1); background-color: var(--color-cta); }
.pz-youtube > a:focus-visible { outline: 3px solid var(--pz-lime); outline-offset: -6px; }
.pz-youtube iframe {
  display: block; width: 100%;
  aspect-ratio: 16 / 9; max-height: 85vh;
  border: 0; background: #000;
}
@media (max-width: 767px) {
  .pz-youtube > a::after { width: 68px; height: 68px; margin: -34px 0 0 -34px; background-size: 36px; }
}

/* --- Home: specials show their full text ---------------------------------------------
   The cards used a 30-word excerpt, which cut offers off mid-sentence with a
   "…" that looked like a link. They now show the whole special, so Chris can
   add terms and conditions as extra paragraphs or a list. */
.special-card__body { color: var(--color-text-muted); font-size: var(--fs-small); }
.special-card__body > * { margin-block: 0; }
.special-card__body > * + * { margin-block-start: var(--space-2xs); }
.special-card__body ul,
.special-card__body ol { padding-inline-start: 1.25em; }
.special-card__body p:empty { display: none; }

/* ===========================================================================
   Kelsey's notes, 15 and 16 Oct
   =========================================================================== */

/* --- Hero badges: shown at their own shape -------------------------------------------
   The badges are transparent PNGs cut to their own shape, so there is no card
   behind them: a drop shadow that follows the outline lifts them off the video
   instead. Each one is sized by height so any badge artwork lines up. */
.badge-wire__item.wp-block-image img {
  box-sizing: border-box;
  width: auto;
  height: calc(var(--disc) * 1.3);
  padding: 0;
  background: none;
  border-radius: 0;
  box-shadow: none;
  filter: drop-shadow(0 6px 10px rgba(0, 0, 0, .28));
}
/* The editor writes height:auto onto every image, which showed the badges at
   full width there and filled the screen. Keep them the same size as the site. */
.editor-styles-wrapper .badge-wire__item.wp-block-image img {
  width: auto !important;
  height: calc(var(--disc) * 1.3) !important;
}
.editor-styles-wrapper .badge-wire__track { padding-inline: var(--space-m); }
/* On phones the strip clips its overflow for the marquee; give the shadow room. */
@media (max-width: 767px) {
  .badge-wire { padding-block-end: 20px; }
}

/* --- Footer: Certified logos ---------------------------------------------------------
   Every logo in the Certified group shows at the same height, whatever size
   or width it was given in the editor, so logos can be swapped in and out
   without breaking the row. The row wraps rather than squashing a logo, and
   there is no box behind them: transparent PNGs sit straight on the green. */
.footer-badges {
  flex-wrap: wrap !important;
  align-items: center;
  gap: 16px 20px !important;
}
.footer-badges > .wp-block-image { flex: 0 0 auto; margin: 0 !important; }
.footer-badges > .wp-block-image img {
  width: auto !important;
  height: 72px !important;
  max-width: 160px;
  object-fit: contain;
  padding: 0;
  background: none;
  border-radius: 0 !important;
}

/* --- Tour: the promo film, uploaded to the Media Library -----------------------------
   A Video block with the class "pz-promo". site.js lays a play button over the
   poster; nothing is downloaded until someone presses it, and then the film
   plays with sound and the normal controls. */
.wp-block-video.pz-promo { position: relative; margin-block: 0; background: var(--pz-forest); }
.wp-block-video.pz-promo video {
  display: block; width: 100%;
  aspect-ratio: 16 / 9; max-height: 85vh;
  object-fit: cover; background: #000;
}
.wp-block-video.pz-promo + .wp-block-group { margin-block-start: 0; }
.pz-promo__play {
  position: absolute; inset: 0; z-index: 1;
  width: 100%; height: 100%; margin: 0; padding: 0;
  border: 0; background: none; cursor: pointer;
}
.pz-promo__play::after {
  content: "";
  position: absolute; left: 50%; top: 50%;
  width: 88px; height: 88px;
  margin: -44px 0 0 -44px;
  border-radius: 50%;
  background: rgba(0, 41, 26, .55) url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M9 6.5v11l9-5.5z' fill='%23fff'/%3E%3C/svg%3E") center / 46px no-repeat;
  border: 3px solid #fff;
  box-shadow: 0 10px 30px rgba(0, 0, 0, .35);
  transition: transform var(--dur) var(--ease), background-color var(--dur) var(--ease);
}
.pz-promo__play:hover::after,
.pz-promo__play:focus-visible::after { transform: scale(1.1); background-color: var(--color-cta); }
.pz-promo__play:focus-visible { outline: 3px solid var(--pz-lime); outline-offset: -6px; }
.pz-promo.is-playing .pz-promo__play { display: none; }
@media (max-width: 767px) {
  .pz-promo__play::after { width: 68px; height: 68px; margin: -34px 0 0 -34px; background-size: 36px; }
}
