/* Trafalgar Park Community Hub — heading scale
   Loaded by pan-site-base, after tokens.css.

   This file exists because **Elementor free has no H1–H6 typography controls** —
   its kit exposes body and links only. Rather than set headings widget-by-widget
   (which drifts) or in Blocksy's Customizer (which dies with the theme), the scale
   lives here: one source of truth, survives a theme switch, matches where the
   fonts already live.

   Sizes are fluid via clamp() so there are no breakpoint jumps. The numbers are
   the same ones in tokens/elementor-globals.md. */

h1, h2, h3, h4, h5, h6,
.elementor-heading-title {
  font-family: var(--font-heading, "Poppins", system-ui, sans-serif);
  color: var(--hub-green, #2E6B4F);
  letter-spacing: var(--ls-head, -0.01em);
  text-wrap: balance; /* stops a lone word dropping to its own line */
}

h1, .elementor-widget-heading h1.elementor-heading-title {
  font-size: var(--step-h1, clamp(2.125rem, 1.55rem + 2.4vw, 3rem));
  line-height: var(--lh-tight, 1.15);
  font-weight: 700;
}

h2, .elementor-widget-heading h2.elementor-heading-title {
  font-size: var(--step-h2, clamp(1.75rem, 1.42rem + 1.4vw, 2.25rem));
  line-height: 1.2;
  font-weight: 600;
}

h3, .elementor-widget-heading h3.elementor-heading-title {
  font-size: var(--step-h3, clamp(1.375rem, 1.24rem + 0.55vw, 1.625rem));
  line-height: 1.3;
  font-weight: 600;
}

h4, .elementor-widget-heading h4.elementor-heading-title {
  font-size: var(--step-h4, clamp(1.125rem, 1.07rem + 0.22vw, 1.25rem));
  line-height: 1.35;
  font-weight: 600;
}

/* Body defaults. Elementor's kit also sets these, so this is the belt to its
   braces — and the only thing standing if the kit is ever reset. */
body {
  font-family: var(--font-body, "Lato", Arial, sans-serif);
  font-size: var(--step-body, clamp(1.0625rem, 1.03rem + 0.14vw, 1.125rem));
  line-height: var(--lh-body, 1.65);
  color: var(--charcoal, #2B2B2B);
  background-color: var(--cream, #F7F2E9);
}

/* Long-form pages (About, Privacy, hire terms) read better at a bounded measure. */
.pan-measure { max-width: var(--container-narrow, 720px); }

/* Lead paragraph — the one under a page title. */
.pan-lead {
  font-size: var(--step-lead, clamp(1.1875rem, 1.09rem + 0.38vw, 1.3125rem));
  line-height: 1.55;
}

/* Captions, photo credits, form hints. Muted is 6.2:1 on cream — still AA. */
.pan-small,
figcaption,
.wp-caption-text {
  font-size: var(--step-small, 0.9375rem);
  line-height: 1.5;
  color: var(--muted, #5A5A5A);
}

/* 🔴 Accessibility guards, from the measured contrast table. These are not
   preferences — each pairing below fails WCAG AA and is easy to reach for by
   accident in a page builder. */
.pan-on-amber { color: var(--charcoal, #2B2B2B); }  /* white on amber = 2.2:1 */
.pan-on-green { color: var(--cream, #F7F2E9); }     /* brand rule: cream, not white */

/* 🔴 Blocksy's header CTA takes the global link colour ahead of its own button
   text variable. With the brand palette in place that lands Hub Green on Warm
   Amber — measured 2.92:1, which fails AA. The variable is already set correctly
   by the theme (verified: `--theme-button-text-initial-color: #2B2B2B`); this
   makes the element actually honour it.

   Deliberately narrow. We are not restyling the theme — we are holding a
   measured accessibility floor that the theme's own default breaks, which is
   exactly what this plugin is for. */
.ct-button,
.ct-header-cta .ct-button {
  color: var(--theme-button-text-initial-color, var(--charcoal, #2B2B2B));
}

/* --- Rate tables -----------------------------------------------------------
   Real halls publish a plain table and so do we. Scrolls inside its own box on
   a phone rather than forcing the page sideways. */
.pan-table-wrap { overflow-x: auto; margin: var(--space-lg, 24px) 0; }

.pan-table {
  width: 100%;
  border-collapse: collapse;
  background: var(--white, #fff);
  border: 1px solid var(--line, #E0D7C6);
  border-radius: var(--radius-md, 12px);
  overflow: hidden;
  font-size: var(--step-body, 1.0625rem);
}

.pan-table th,
.pan-table td {
  padding: var(--space-md, 16px);
  text-align: left;
  border-bottom: 1px solid var(--line, #E0D7C6);
  vertical-align: top;
}

.pan-table thead th {
  background: var(--cream-deep, #EFE7D8);
  font-family: var(--font-heading, "Poppins", sans-serif);
  font-weight: 600;
  color: var(--deep-green, #24543E);
}

.pan-table tbody tr:last-child td { border-bottom: 0; }

/* Tighter on small screens so the common case fits without sideways scrolling.
   It still scrolls inside its wrapper when it has to — the page never does. */
@media (max-width: 600px) {
  .pan-table { font-size: 1rem; }
  .pan-table th, .pan-table td { padding: 12px 10px; }
}
.pan-table td strong { font-size: 1.0625em; }
.pan-table .pan-rate { white-space: nowrap; }

/* --- Provisional content marker ---------------------------------------------
   🔴 Anything the committee has not yet answered is marked, not guessed and not
   quietly omitted. Deliberately conspicuous: these must be impossible to miss in
   review and trivial to find before launch (search the page for "pan-tbc"). */
.pan-tbc {
  display: inline-block;
  background: #FBEBD2;
  border: 1px dashed var(--warm-amber, #E8A33D);
  border-radius: var(--radius-sm, 6px);
  padding: 0.1em 0.5em;
  color: #7A4E12;
  font-size: 0.94em;
  font-weight: 600;
}

/* Elementor's entrance animations do not honour the OS reduced-motion setting on
   their own. Vestibular disorders are common in an older audience, and a hall
   site is not worth making anyone unwell. Motion off means off. */
@media (prefers-reduced-motion: reduce) {
  .elementor-invisible { visibility: visible !important; }
  .animated { animation: none !important; }
}

/* --- Scroll reveal, done without hiding anything ----------------------------
   🔴 Elementor's own entrance animations mark each section `.elementor-invisible`
   (visibility: hidden) in the SERVED HTML and only unhide it from JavaScript. On
   a page carrying hire rates and conditions of hire, content that depends on a
   script to become visible is the wrong trade — and a CSS failsafe could not
   reliably beat it, which was tested rather than assumed.

   So Elementor's animation is not used. This is a CSS scroll-driven animation
   instead: no JavaScript, and crucially it **fails visible** — browsers without
   `animation-timeline` support simply show the content, they do not hide it. */
@supports (animation-timeline: view()) {
  @media (prefers-reduced-motion: no-preference) {
    /* Targets Elementor's own top-level container selector rather than a custom
       class — the `_css_classes` setting does not render on containers when the
       page is authored as data, which was tested. This selector is stable. */
    .e-con.e-parent,
    .pan-reveal {
      animation: pan-rise linear both;
      animation-timeline: view();
      animation-range: entry 0% entry 45%;
    }
    @keyframes pan-rise {
      from { opacity: 0; transform: translateY(22px); }
      to   { opacity: 1; transform: none; }
    }
  }
}

/* Photo placeholder captions — clearly provisional, never mistaken for real copy. */
.pan-small:has(+ *) , figcaption { font-style: normal; }

/* Focus visible everywhere — keyboard users are a real part of "accessible hall". */
:where(a, button, input, select, textarea, [tabindex]):focus-visible {
  outline: 3px solid var(--color-focus, #24543E);
  outline-offset: 2px;
}

/* --- Events -------------------------------------------------------------- */

/* [pan_upcoming_events] — our own markup, so it inherits the brand rather than
   The Events Calendar's blue-grey defaults. */
.pan-events { list-style: none; margin: var(--space-lg, 24px) 0; padding: 0; }

.pan-event {
  display: grid;
  grid-template-columns: minmax(11rem, auto) 1fr;
  gap: 2px var(--space-lg, 24px);
  align-items: baseline;
  padding: var(--space-md, 16px) 0;
  border-bottom: 1px solid var(--color-border, #E0D7C6);
}

.pan-event:last-child { border-bottom: 0; }

.pan-event-when {
  font-family: var(--font-heading, sans-serif);
  font-weight: 600;
  color: var(--color-link, #2E6B4F);
}

.pan-event-title { font-weight: 700; }

.pan-event-time {
  grid-column: 2;
  color: var(--color-text-muted, #5A5A5A);
  font-size: var(--step-small, 0.9375rem);
}

@media (max-width: 600px) {
  /* Stack rather than squeeze: a two-column date/title grid at 375px leaves
     four words per line. */
  .pan-event { grid-template-columns: 1fr; }
  .pan-event-time { grid-column: 1; }
}

/* The Events Calendar ships its own palette and type scale. These pull the
   parts a visitor actually sees back onto the tokens. Scoped to TEC's own
   classes so nothing else on the site is touched. */
.tribe-common .tribe-common-h4,
.tribe-common .tribe-common-h5,
.tribe-common .tribe-common-h6,
.tribe-common .tribe-common-h7,
.tribe-common .tribe-common-h8 {
  font-family: var(--font-heading, sans-serif);
}

.tribe-common .tribe-common-b1,
.tribe-common .tribe-common-b2,
.tribe-common .tribe-common-b3 {
  font-family: var(--font-body, sans-serif);
}

.tribe-events .tribe-events-calendar-list__event-title-link,
.tribe-events .tribe-events-calendar-month__calendar-event-title-link {
  color: var(--color-link, #2E6B4F);
}

.tribe-events .tribe-events-calendar-list__event-title-link:hover,
.tribe-events .tribe-events-calendar-month__calendar-event-title-link:hover {
  color: var(--color-link-hover, #24543E);
}

.tribe-common .tribe-common-c-btn,
.tribe-common a.tribe-common-c-btn {
  background-color: var(--color-cta-bg, #E8A33D);
  color: var(--color-cta-text, #2B2B2B);   /* never white — 2.2:1 on amber */
  border-radius: 999px;
}

.tribe-events .tribe-events-calendar-list__event-date-tag-daynum {
  color: var(--color-link, #2E6B4F);
}

/* The Events Calendar injects a hidden <h1>Events</h1> for screen readers when
   the theme prints no visible title. Our archive intro is therefore an <h2> —
   one H1 per page, and the heading a sighted visitor reads is still the biggest
   thing on it. */
.pan-archive-title {
  font-size: var(--step-h1, 2.5rem);
  margin-bottom: var(--space-md, 16px);
}

/* --- Tap targets ---------------------------------------------------------- */

/* Measured on a 375px viewport: Blocksy's mobile menu trigger renders 18x18 and
   the header CTA 34px tall. Both are well under the 44x44 that WCAG 2.5.5 and
   both platform guidelines ask for — and this site's audience is largely older
   people booking a hall on a phone, which is exactly who a small target fails.

   Padding rather than width/height so the icon stays its designed size and only
   the hit area grows. */
.ct-header-trigger {
  min-width: 44px;
  min-height: 44px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}

.ct-button,
.elementor-button,
.wpbc_button,
.fluentform .ff-btn-submit,
button[type="submit"],
input[type="submit"] {
  min-height: 44px;
}

/* Inline links inside a paragraph are exempt — a 44px line box in running text
   would wreck the measure, and WCAG exempts inline links for that reason. */

/* --- Card grids ----------------------------------------------------------- */

/* Elementor containers used as cards size to their own content, so a row of
   them ends up ragged — "The green" runs to eight lines while "The hall" runs
   to two, and the row reads as broken rather than designed. Stretch is the
   default for flex children; Elementor sets flex-start. */
.e-con.e-parent > .e-con-inner > .e-con,
.e-con > .e-con-inner > .e-con {
  align-self: stretch;
}

/* A card that lifts slightly on hover reads as a considered object rather than
   a box of text. Kept small — this is a hall, not a SaaS landing page — and
   removed entirely for anyone who has asked for less motion. */
@media (prefers-reduced-motion: no-preference) {
  .e-con[class*="wygcard"],
  .pan-card {
    transition: transform .18s ease, box-shadow .18s ease;
  }

  .e-con[class*="wygcard"]:hover,
  .pan-card:hover {
    transform: translateY(-2px);
    box-shadow: 0 6px 20px rgba(43, 43, 43, .08);
  }
}

/* --- Price hierarchy ------------------------------------------------------ */

/* On the rates table the amount is what every visitor is scanning for, and it
   was set at body weight — level with the description beside it. */
.pan-table .pan-rate strong,
.pan-table td.pan-rate strong {
  font-family: var(--font-heading, sans-serif);
  font-size: 1.35em;
  font-weight: 700;
  color: var(--color-link, #2E6B4F);
  line-height: 1.1;
}

/* --- Site title on phones ------------------------------------------------- */

/* Measured on the staging site at 375px: the title renders at 25px inside a
   137px column - the logo, menu trigger and Enquire button take the rest - so
   every one of the four words lands on its own line and the block stands 150px
   tall before a visitor sees any content. Leni saw this on a real phone.

   Reduced rather than hidden. The wordmark is the only place the Hub's full
   name appears above the fold, and a tree logo alone tells a first-time visitor
   nothing about whose site they are on. At 16px "Trafalgar Park" fits one line
   and "Community Hub" the next.

   The proper fix is the horizontal lockup in the polish brief; this holds until
   that exists. Re-measure after any Blocksy update - the column width is the
   theme's, not ours. */
@media (max-width: 600px) {
  .site-title {
    font-size: 16px;
    line-height: 1.2;
  }
}

/* Below ~360px even two words per line is tight. */
@media (max-width: 380px) {
  .site-title {
    font-size: 15px;
  }
}

/* --- Cards that are actually clickable ------------------------------------
   🔴 The "Have a look around" cards lifted on hover, so they read as buttons —
   and only 8% of each card was a link. Measured: 1 of 15 sample points, and the
   cursor never changed. A card that looks interactive and isn't is worse than a
   plain paragraph, because the reader blames themselves for the missed click.

   The fix is the stretched-link pattern: the heading's own anchor grows a
   pseudo-element that covers the whole card. No extra markup, one anchor, so
   screen readers still announce a single link with the heading as its name —
   which a wrapping <a> around the whole card would not do half as well.

   The arrow link inside sits above it so it stays independently clickable,
   and the card is the positioning context for both. */
.e-con[class*="wygcard"] {
  position: relative;
  overflow: hidden;
}

/* 🔴 Two things trap the overlay inside the heading, and both are invisible
   until you hit-test the card rather than look at it:

   ① Elementor gives every WIDGET `position: relative`, so the heading widget —
      not the card — was the anchor's containing block. `inset: 0` then covered
      the title line and nothing else. That is the 8%.

   ② The scroll-reveal above animates `transform` on `.e-con.e-parent`, and in
      this build EVERY container carries `e-parent`, including the card's inner
      box. A transformed element becomes the containing block for absolutely
      positioned descendants whatever its `position` is — so killing the
      animation inside a card is not cosmetic, it is what makes ① fixable.

   The card keeps its own transform and stays the containing block. */
.e-con[class*="wygcard"] .elementor-widget,
.e-con[class*="wygcard"] .elementor-widget-container {
  position: static;
}

.e-con[class*="wygcard"] .e-con {
  position: static;
  animation: none;
  transform: none;
}

.e-con[class*="wygcard"] .elementor-widget-heading a::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 1;
}

.e-con[class*="wygcard"] .elementor-widget-text-editor a {
  position: relative;
  z-index: 2;
}

/* The whole card takes the focus ring, not just the four words of the heading. */
.e-con[class*="wygcard"]:has(a:focus-visible) {
  outline: 3px solid var(--color-focus, #24543E);
  outline-offset: 2px;
}

.e-con[class*="wygcard"]:has(a:focus-visible) .elementor-widget-heading a:focus-visible {
  outline: none;
}

/* Image-led cards: the photo bleeds to the card edge, the words get the padding. */
.e-con[class*="wygcard"] > .e-con-inner > .elementor-widget-image,
.e-con[class*="wygcard"] > .elementor-widget-image {
  margin: 0;
}

.e-con[class*="wygcard"] .elementor-widget-image img {
  display: block;
  width: 100%;
  aspect-ratio: 3 / 2;
  object-fit: cover;
}

/* --- [pan_gallery] — a swipeable photo strip -------------------------------
   CSS scroll-snap, so touch swipe, momentum and keyboard scrolling are all the
   browser's own. No carousel library, and with scripting off it stays a working
   horizontal scroller rather than a stack of hidden slides.

   The edge peek is deliberate: a slide cut off at the right-hand edge is the
   only affordance that reliably says "there is more, push me sideways". */
.pan-gal {
  position: relative;
  margin: var(--space-lg, 24px) 0;
}

.pan-gal-track {
  display: flex;
  gap: 16px;
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  scroll-behavior: smooth;
  scroll-padding-left: 0;
  list-style: none;
  margin: 0;
  padding: 0 0 12px;
  -webkit-overflow-scrolling: touch;
  overscroll-behavior-x: contain;
}

.pan-gal-slide {
  scroll-snap-align: start;
  margin: 0;
}

.pan-gal-slide figure {
  margin: 0;
}

.pan-gal-slide img {
  display: block;
  width: 100%;
  height: auto;
  aspect-ratio: 3 / 2;
  object-fit: cover;
  border-radius: var(--radius-md, 12px);
  background: #EFE7D8;
}

.pan-gal-slide figcaption {
  margin-top: 8px;
}

/* A focusable scroll region must show that it has focus. */
.pan-gal-track:focus-visible {
  outline: 3px solid var(--color-focus, #24543E);
  outline-offset: 4px;
  border-radius: var(--radius-md, 12px);
}

/* 🔴 The scrollbar is the ONLY affordance when scripting is off, so it is never
   hidden outright. Once the script has added arrows and dots it is redundant
   clutter, and only then does it go — the class is added by the script. */
.pan-gal.is-enhanced .pan-gal-track { scrollbar-width: none; }
.pan-gal.is-enhanced .pan-gal-track::-webkit-scrollbar { height: 0; }

/* Slimmer scrollbar where the browser lets us style it; it is a real
   affordance on desktop, so it is thinned rather than hidden. */
.pan-gal-track::-webkit-scrollbar {
  height: 8px;
}

.pan-gal-track::-webkit-scrollbar-thumb {
  background: #D8CDBA;
  border-radius: 999px;
}

.pan-gal-track::-webkit-scrollbar-track {
  background: transparent;
}

.pan-gal-nav {
  display: flex;
  gap: 8px;
  justify-content: flex-end;
  margin-top: 4px;
}

.pan-gal-btn {
  width: 44px;
  height: 44px;
  border-radius: 999px;
  border: 1px solid #E0D7C6;
  background: #FFFFFF;
  color: var(--color-link, #2E6B4F);
  font-size: 1.1rem;
  line-height: 1;
  cursor: pointer;
}

.pan-gal-btn:hover {
  background: var(--cream, #F7F2E9);
  border-color: var(--color-link, #2E6B4F);
}

/* 🔴 Slide width follows the GALLERY, using min() alone — NOT a container query.
   The problem was real: `@media (min-width: 782px)` asks how wide the WINDOW is,
   so the hall and kitchen galleries — sitting in a 481px column on Spaces — were
   handed 46% of 481 ≈ 220px and came out postage-stamp sized, while the
   full-width galleries lower down the same page at the same screen width looked
   right.

   ⚠️ The first fix was `container-type: inline-size`, and it BROKE THE PAGE.
   Container-type applies layout containment, and Elementor's section then sized
   itself without the gallery's height: **every section holding a gallery came up
   130–170px short and the next section rode up over it.** On mobile that put
   "How to book" straight through a photograph. Reported by Jeremy from
   screenshots; my own mobile sweep had missed it because it tested horizontal
   overflow and never once checked whether sections VERTICALLY overlap.

   Proved by experiment rather than argued: removing container-type took the
   spill from 150px to −1, and placing it on the inner viewport instead still
   left 114px.

   `min(86%, 560px)` needs no containment and does the same job — the percentage
   already resolves against the gallery's own width:
     • 1140px container → 86% = 980, capped at 560 → two slides
     •  481px container → 86% = 413, under the cap → one slide and a peek
     •  330px on a phone → 284 → one slide and a peek
   Measured at both widths, both layouts, before shipping. */
.pan-gal-slide {
  flex: 0 0 min(86%, 560px);
}

/* --- At-a-glance summary panel -------------------------------------------
   For pages that are long and legally worded — Hire & pricing runs to a
   thousand words — a short panel up top that answers the four things everyone
   actually came to find out. It never replaces the detail below it. */
.pan-glance {
  background: #FFFFFF;
  border: 1px solid #E0D7C6;
  border-radius: var(--radius-md, 12px);
  padding: 24px 28px;
  margin: var(--space-lg, 24px) 0;
}

.pan-glance ul {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: 14px 32px;
}

@media (min-width: 782px) {
  .pan-glance ul {
    grid-template-columns: 1fr 1fr;
  }
}

.pan-glance li {
  margin: 0;
  padding-left: 26px;
  position: relative;
}

.pan-glance li::before {
  content: "";
  position: absolute;
  left: 0;
  top: 0.55em;
  width: 10px;
  height: 10px;
  border-radius: 999px;
  background: var(--warm-amber, #E8A33D);
}

.pan-glance strong {
  font-family: var(--font-heading, sans-serif);
  color: var(--color-link, #2E6B4F);
}

/* --- Facts strip ----------------------------------------------------------
   Three numbers that say "this place is used", which is the thing a hall has
   to prove and prose never quite does. */
.pan-facts {
  display: grid;
  gap: 20px;
  grid-template-columns: 1fr;
  margin: var(--space-lg, 24px) 0 0;
  padding: 0;
  list-style: none;
}

/* 0.50.0 - the facts strip went to three columns at 640px, which left each one
   about 212px wide. At 2.1rem the second and third headings wrapped to two lines
   while the first stayed on one, so the row read as ragged rather than as a set.
   Hold one column until there is genuinely room for three (measured: 900px was
   still too tight for "The whole facility" at the clamped size). */
@media (min-width: 1000px) {
  .pan-facts {
    grid-template-columns: repeat(3, 1fr);
  }
}

.pan-facts li {
  margin: 0;
}

.pan-facts .pan-facts-n {
  display: block;
  font-family: var(--font-heading, sans-serif);
  /* Fluid rather than fixed, so the heading shrinks before it wraps. */
  font-size: clamp(1.6rem, 1.15rem + 1.4vw, 1.9rem);
  font-weight: 700;
  line-height: 1.1;
  color: var(--color-link, #2E6B4F);
}

.pan-facts .pan-facts-t {
  display: block;
  margin-top: 2px;
}

/* ==========================================================================
   0.37.0 — the polish pass
   Depth and motion, on the palette that already exists. No new brand colours:
   every tone below is Hub Green, Warm Amber, Cream or Charcoal at an opacity.
   ========================================================================== */

:root {
  --shadow-xs: 0 1px 2px rgba(43, 43, 43, .06);
  --shadow-sm: 0 2px 6px rgba(43, 43, 43, .07);
  --shadow-md: 0 6px 18px rgba(43, 43, 43, .10);
  --shadow-lg: 0 14px 40px rgba(43, 43, 43, .14);

  /* Tints, derived — not new colours. */
  --green-tint: rgba(46, 107, 79, .07);
  --green-line: rgba(46, 107, 79, .18);
  --amber-tint: rgba(232, 163, 61, .14);
  --hairline: #E3DACA;

  --ease: cubic-bezier(.2, .7, .3, 1);
}

/* --- One button language ---------------------------------------------------
   🔴 There were three. The header CTA rendered in `-apple-system` at 3px radius
   with 5px of vertical padding; page buttons were Poppins pills at 999px; form
   submits were whatever the plugin shipped. Same site, three vocabularies, and
   none of them had a hover state worth the name.

   This is the shared shape. Colour is left to each element so Elementor's
   per-widget settings still win — we are fixing the FEEL, not overriding the
   brand choices already made in the page data. */
/* 🔴 0,1,0 is not enough here — measured, twice. Elementor emits per-widget CSS
   and Blocksy styles buttons at 0,1,1, so a bare `.elementor-button` lost its
   shadow and its transition while the header CTA (a different selector) kept
   both. Every selector below is lifted to at least 0,2,0 by pairing it with the
   wrapper it always ships inside. */
.elementor-widget-button .elementor-button,
.elementor-widget-container .elementor-button,
.entry-content .elementor-button,
.ct-button,
.wpbc_button,
.frm-fluent-form .ff_submit_btn_wrapper .ff-btn-submit,
.frm-fluent-form .ff-btn.ff-btn-submit,
.entry-content button[type="submit"],
.entry-content input[type="submit"] {
  font-family: var(--font-heading, sans-serif);
  font-weight: 600;
  letter-spacing: .01em;
  border-radius: 999px;
  padding: 14px 30px;
  box-shadow: var(--shadow-sm);
  transition: transform .18s var(--ease), box-shadow .18s var(--ease), background-color .18s var(--ease), filter .18s var(--ease);
  will-change: transform;
}

@media (prefers-reduced-motion: no-preference) {
  .elementor-widget-button .elementor-button:hover,
  .entry-content .elementor-button:hover,
  .ct-button:hover,
  .wpbc_button:hover,
  .frm-fluent-form .ff_submit_btn_wrapper .ff-btn-submit:hover,
  .frm-fluent-form .ff-btn.ff-btn-submit:hover,
  .entry-content button[type="submit"]:hover,
  .entry-content input[type="submit"]:hover {
    transform: translateY(-2px);
    box-shadow: var(--shadow-md);
    filter: saturate(1.06);
  }
}

.elementor-widget-button .elementor-button:active,
.entry-content .elementor-button:active,
.ct-button:active,
.wpbc_button:active,
.frm-fluent-form .ff_submit_btn_wrapper .ff-btn-submit:active,
.frm-fluent-form .ff-btn.ff-btn-submit:active,
.entry-content button[type="submit"]:active,
.entry-content input[type="submit"]:active {
  transform: translateY(0);
  box-shadow: var(--shadow-xs);
}

/* The header CTA was the worst offender — system font, 3px radius, 5px of
   vertical padding. It is the most-seen button on the site. */
.ct-header-cta .ct-button,
.ct-button.ct-header-cta-btn {
  padding: 11px 22px;
  font-size: .95rem;
}

/* An arrow that slides on hover, on any button whose label ends in one.
   Motion that means "forward", and off entirely under reduced-motion. */
@media (prefers-reduced-motion: no-preference) {
  .elementor-button .elementor-button-text {
    transition: transform .18s var(--ease);
  }
}

/* --- Links that respond ---------------------------------------------------- */
.entry-content a:not(.elementor-button):not(.ct-button):not(.pan-gal-dot) {
  text-underline-offset: .18em;
  text-decoration-thickness: .07em;
  transition: color .15s var(--ease), text-decoration-color .15s var(--ease);
}

/* --- Section rhythm --------------------------------------------------------
   Every section was the same padding on cream or white, so a page read as one
   flat column and nothing told the eye where it was. Alternate the ground and
   give the bands a hairline so the change is deliberate rather than accidental. */
.elementor > .e-con:nth-of-type(even) {
  background-color: var(--cream, #F7F2E9);
}

.elementor > .e-con + .e-con {
  border-top: 1px solid var(--hairline);
}

/* --- The gallery, second pass ---------------------------------------------
   Arrows now sit ON the image edges and dots track the current slide, which is
   the pattern everyone already knows from a phone gallery. The bottom-right
   pills the first version used read as an afterthought. */
.pan-gal-viewport {
  position: relative;
}

/* 🔴 Blocksy styles `.entry-content button` — specificity 0,1,1 — which beats a
   bare `.pan-gal-dot` at 0,1,0. So a 9px dot rendered 56x28 and a 46px arrow
   rendered 56x46, carrying the theme's `padding: 14px 28px` with `box-sizing:
   border-box` clamping the box to the padding.
   Measured with getBoundingClientRect, then traced by asking the element which
   selectors it matches — the stylesheet walk found nothing, because most of the
   40 sheets on this page throw on `cssRules`.
   Fixed by out-specifying it (0,2,0) rather than reaching for !important. */
.pan-gal-viewport .pan-gal-arrow,
.pan-gal-dots .pan-gal-dot {
  box-sizing: border-box;
  padding: 0;
  min-width: 0;
  min-height: 0;
  appearance: none;
  -webkit-appearance: none;
  font: inherit;
}

.pan-gal-viewport .pan-gal-arrow {
  position: absolute;
  top: calc(50% - 22px);
  z-index: 3;
  width: 46px;
  height: 46px;
  display: grid;
  place-items: center;
  border: 0;
  border-radius: 999px;
  background: rgba(255, 255, 255, .92);
  box-shadow: var(--shadow-md);
  color: var(--color-link, #2E6B4F);
  cursor: pointer;
  transition: background-color .18s var(--ease), transform .18s var(--ease), opacity .18s var(--ease);
}

.pan-gal-arrow svg {
  width: 22px;
  height: 22px;
  fill: none;
  stroke: currentColor;
  stroke-width: 2.4;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.pan-gal-viewport .pan-gal-arrow--prev { left: 10px; }
.pan-gal-viewport .pan-gal-arrow--next { right: 10px; }

.pan-gal-arrow:hover { background: #fff; }

@media (prefers-reduced-motion: no-preference) {
  .pan-gal-arrow:hover { transform: scale(1.06); }
}

/* An arrow with nowhere to go fades rather than vanishing — the control staying
   put is less jarring than the row of buttons changing width mid-swipe. */
.pan-gal-viewport .pan-gal-arrow[disabled] {
  opacity: .35;
  cursor: default;
  box-shadow: var(--shadow-xs);
}

.pan-gal-arrow[disabled]:hover { transform: none; background: rgba(255,255,255,.92); }

.pan-gal-dots {
  display: flex;
  justify-content: center;
  gap: 9px;
  margin-top: 14px;
}

.pan-gal-dots .pan-gal-dot {
  width: 9px;
  height: 9px;
  padding: 0;
  border: 0;
  border-radius: 999px;
  background: var(--green-line);
  cursor: pointer;
  transition: background-color .2s var(--ease), width .2s var(--ease);
}

/* The active dot stretches rather than just darkening — legible at a glance,
   and it still reads for anyone who cannot separate the two greens. */
.pan-gal-dots .pan-gal-dot.is-active {
  width: 26px;
  background: var(--color-link, #2E6B4F);
}

/* 🔴 A 9px dot is a 9px tap target. Grow it back to 44px with a transparent
   pseudo-element rather than by making the dot itself bigger. */
.pan-gal-dots .pan-gal-dot {
  position: relative;
}

.pan-gal-dots .pan-gal-dot::after {
  content: "";
  position: absolute;
  left: 50%;
  top: 50%;
  width: 44px;
  height: 44px;
  transform: translate(-50%, -50%);
}

.pan-gal-slide img {
  box-shadow: var(--shadow-sm);
}

/* --- Cards, with elevation ------------------------------------------------- */
.e-con[class*="wygcard"] {
  box-shadow: var(--shadow-sm);
  transition: transform .2s var(--ease), box-shadow .2s var(--ease);
}

@media (prefers-reduced-motion: no-preference) {
  .e-con[class*="wygcard"]:hover {
    transform: translateY(-4px);
    box-shadow: var(--shadow-lg);
  }
}

/* The photograph leans in slightly as the card lifts. */
.e-con[class*="wygcard"] .elementor-widget-image img {
  transition: transform .35s var(--ease);
}

@media (prefers-reduced-motion: no-preference) {
  .e-con[class*="wygcard"]:hover .elementor-widget-image img {
    transform: scale(1.035);
  }
}

/* --- Events: a date block, not a list row ---------------------------------- */
.pan-event {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: 4px 18px;
  align-items: baseline;
  padding: 16px 18px;
  border: 1px solid var(--hairline);
  border-radius: var(--radius-md, 12px);
  background: #fff;
  box-shadow: var(--shadow-xs);
  margin-bottom: 12px;
  transition: box-shadow .18s var(--ease), transform .18s var(--ease);
}

@media (prefers-reduced-motion: no-preference) {
  .pan-event:hover {
    transform: translateY(-2px);
    box-shadow: var(--shadow-sm);
  }
}

.pan-event-when {
  grid-row: 1 / 3;
  align-self: center;
  font-family: var(--font-heading, sans-serif);
  font-weight: 700;
  color: var(--color-link, #2E6B4F);
  background: var(--green-tint);
  border-radius: var(--radius-sm, 6px);
  padding: 10px 14px;
  text-align: center;
  min-width: 96px;
}

.pan-event-title {
  font-family: var(--font-heading, sans-serif);
  font-weight: 600;
}

.pan-event-time {
  color: #5A5A5A;
}

/* --- Tables with a bit of weight ------------------------------------------- */
/* 🔴 On a 375px screen the "Members, community groups, not-for-profits and
   charities" cell squeezed to 108px — a tall thin ribbon of words. The wrapper
   already scrolls, so give the table a floor and let it scroll rather than
   compress. Measured, not guessed. */
.pan-table td:first-child,
.pan-table th:first-child {
  min-width: 190px;
}

.pan-table {
  min-width: 560px;
  border: 1px solid var(--hairline);
  border-radius: var(--radius-md, 12px);
  overflow: hidden;
  box-shadow: var(--shadow-xs);
  border-collapse: separate;
  border-spacing: 0;
}

.pan-table thead th {
  background: var(--green-tint);
}

.pan-table tbody tr:nth-child(even) td {
  background: rgba(247, 242, 233, .55);
}

/* --- Forms: the booking page is where the money is ------------------------- */
.frm-fluent-form .ff-el-group .ff-el-form-control,
.wpbc_structure_form input[type="text"],
.wpbc_structure_form input[type="email"],
.wpbc_structure_form textarea,
.wpbc_structure_form select {
  border: 1px solid var(--hairline);
  border-radius: var(--radius-sm, 6px);
  padding: 11px 13px;
  font-size: 1rem;
  background: #fff;
  transition: border-color .15s var(--ease), box-shadow .15s var(--ease);
}

.frm-fluent-form .ff-el-group .ff-el-form-control:focus,
.wpbc_structure_form input:focus,
.wpbc_structure_form textarea:focus,
.wpbc_structure_form select:focus {
  border-color: var(--color-link, #2E6B4F);
  box-shadow: 0 0 0 3px var(--green-tint);
  outline: none;
}

.frm-fluent-form .ff-el-input--label label,
.wpbc_structure_form label {
  font-family: var(--font-heading, sans-serif);
  font-weight: 600;
}

/* The booking wizard sits in a panel rather than floating on the page. */
.wpbc_structure_form,
.frm-fluent-form {
  background: #fff;
  border: 1px solid var(--hairline);
  border-radius: var(--radius-md, 12px);
  box-shadow: var(--shadow-sm);
  padding: 24px;
}

@media (max-width: 600px) {
  .wpbc_structure_form,
  .frm-fluent-form {
    padding: 18px 16px;
  }
}

/* --- Footer --------------------------------------------------------------- */
.ct-footer {
  border-top: 1px solid var(--hairline);
}

/* --- Fluent Forms' submit button — the one deliberate !important -----------
   🔴 Four escalations failed and the reason is not specificity, it is ORDER.
   Fluent Forms matches `.ff-btn-submit:not(.ff_btn_no_style)` — the `:not()`
   contributes its argument's weight, so that lands at 0,3,0, exactly level with
   the best selector available to us. It then prints its rules in a <style>
   block in the BODY, after every <link> in the head, so a tie goes to them.

   You cannot out-specify a tie you always lose on order, and inventing a longer
   selector to win by one class is the kind of fix that breaks on their next
   release. The honest options were: change the button in Fluent Forms' own
   styler settings (the right layer, but a database row and another build
   script), or say plainly that this one element is an override.

   Scoped to one property set on one element. The only other !important here is
   the reduced-motion block, which has to beat Elementor's inline animation
   styles for the same reason — order, not weight. */
.frm-fluent-form .ff-btn.ff-btn-submit {
  font-family: var(--font-heading, sans-serif) !important;
  font-weight: 600 !important;
  border-radius: 999px !important;
  padding: 14px 30px !important;
}

/* --- Grab and drag ---------------------------------------------------------
   A thumb already got real momentum from the native scroller. A mouse got
   nothing, which is why the strip felt inert on a laptop even though it was
   technically swipeable. `scroll-behavior` has to drop to auto while dragging
   or every pointermove fights a smooth-scroll animation. */
.pan-gal.is-enhanced .pan-gal-track {
  cursor: grab;
}

.pan-gal.is-enhanced .pan-gal-track.is-dragging {
  cursor: grabbing;
  scroll-behavior: auto;
}

/* --- The hero --------------------------------------------------------------
   Was a text column beside a small photograph: the image read as an
   illustration rather than as the place, and the proportions fought the
   headline. Now the photograph IS the hero, with the words over it.

   🔴 White text on a photograph is a contrast gamble, so it does not sit on the
   photograph — it sits on a scrim over the photograph. The scrim is Hub Green
   darkened, not black, so the brand still runs through it, and it is heaviest
   exactly where the words are. Measured after building, not assumed. */
.e-con[class*="hero0001"] {
  position: relative;
  isolation: isolate;
  background-size: cover;
  background-position: center 60%;
  background-repeat: no-repeat;
  min-height: clamp(460px, 68vh, 680px);
  align-content: center;
}

.e-con[class*="hero0001"]::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 0;
  background: linear-gradient(
    100deg,
    rgba(22, 52, 38, .93) 0%,
    rgba(22, 52, 38, .86) 38%,
    rgba(22, 52, 38, .55) 68%,
    rgba(22, 52, 38, .30) 100%
  );
}

/* On a phone the column is full width, so the scrim runs top-to-bottom
   instead — a left-to-right fade would leave the last words on bare photo. */
@media (max-width: 880px) {
  .e-con[class*="hero0001"]::before {
    background: linear-gradient(
      to bottom,
      rgba(22, 52, 38, .90) 0%,
      rgba(22, 52, 38, .88) 55%,
      rgba(22, 52, 38, .78) 100%
    );
  }
}

.e-con[class*="hero0001"] > .e-con-inner,
.e-con[class*="hero0001"] > .e-con {
  position: relative;
  z-index: 1;
}

/* Everything in the hero goes light. Set on the section so a later text widget
   cannot quietly land in charcoal on a dark ground. */
/* ⚠️ This was `:where(h1, p, span)`. `:where()` contributes ZERO specificity, so
   Elementor's per-widget colour beat it and the headline stayed dark green on a
   dark green scrim. The real fix is the widget colour in the page data; this is
   the backstop for anything added to the hero later. */
.e-con[class*="hero0001"] h1,
.e-con[class*="hero0001"] h2,
.e-con[class*="hero0001"] h3,
.e-con[class*="hero0001"] p,
.e-con[class*="hero0001"] li {
  color: #FFFFFF;
}

.e-con[class*="hero0001"] .elementor-widget-heading:first-of-type .elementor-heading-title {
  /* lightened amber — #E8A33D measured 4.07:1 here, and this is small text */
  color: var(--amber-on-dark, #F7D9AC);
  letter-spacing: .08em;
  text-transform: uppercase;
  font-size: .82rem;
}

.e-con[class*="hero0001"] h1 {
  font-size: clamp(2.1rem, 5.2vw, 3.5rem);
  line-height: 1.08;
  letter-spacing: -.015em;
  margin-bottom: .35em;
  text-wrap: balance;
}

/* The "previously known as" line is a recognition hook, not body copy. */
.e-con[class*="hero0001"] .pan-small {
  color: rgba(255, 255, 255, .82);
  font-size: .95rem;
}

.e-con[class*="hero0001"] .pan-lead {
  font-size: clamp(1.05rem, 1.6vw, 1.22rem);
  color: rgba(255, 255, 255, .94);
  max-width: 34em;
}

/* The secondary route out of the hero — quiet beside the amber button, but a
   real target, and underlined so it is not colour-only. */
/* ⚠️ Third time the same shape of bug in this hero: a colour that looks set and
   is not. `.pan-hero-alt a` is 0,1,1 — exactly level with the theme's own
   `.entry-content a` — so the link rendered Hub Green on a Hub Green scrim and
   all but vanished. Paired with the hero container to reach 0,2,1. */
.e-con[class*="hero0001"] .pan-hero-alt a,
.pan-hero-alt a {
  color: #FFFFFF;
  font-family: var(--font-heading, sans-serif);
  font-weight: 600;
  text-decoration: underline;
  text-underline-offset: .25em;
  text-decoration-thickness: .08em;
  display: inline-block;
  padding: 10px 2px;
}

.e-con[class*="hero0001"] .pan-hero-alt a:hover,
.pan-hero-alt a:hover {
  color: var(--warm-amber, #E8A33D);
}

/* --- Upcoming events on the home page -------------------------------------- */
.pan-events {
  margin-top: var(--space-lg, 24px);
}

/* Home shows a short list, so give it a little more presence than the full
   What's On page does. */
.pan-home-events .pan-event {
  background: rgba(255, 255, 255, .96);
}

/* ==========================================================================
   0.40.0 — dark-ground hover states, and a lighter hero scrim
   ========================================================================== */

/* --- 🔴 Links that vanish on hover ----------------------------------------
   Blocksy's global `--theme-link-hover-color` is #24543E, and the dropdown
   panel and every page's closing CTA band are ALSO #24543E. So hovering a link
   in either turned the text **exactly** the background colour.

   Measured: contrast 1.00. Not "low" — identical. The word disappears under the
   cursor, which reads as the site being broken rather than as a styling choice.

   Reported by Jeremy on the header's More menu; the sweep found it in six
   places, because the cause is one global variable rather than one component.

   Fixed with the lightened amber already used for the hero eyebrow — a tint of
   the brand colour, and the only accent that clears AA on Hub Green. */
:root {
  /* 🔴 One value for every amber-on-dark use. #F2C078 cleared AA against the
     ORIGINAL scrim at 5.26, then lightening the scrim for the photograph pushed
     it to 4.28 and it silently stopped passing for small text. Lightening a
     background is a contrast change to everything sitting on it.
     #F7D9AC: 5.27 on the lightened hero, 6.41 on the dropdown. Margin, not luck. */
  --amber-on-dark: #F7D9AC;
}

.sub-menu a:hover,
.sub-menu a:focus-visible,
#offcanvas a:hover,
#offcanvas a:focus-visible,
.ct-panel a:hover,
.ct-panel a:focus-visible,
.e-con[class*="ctasec"] a:hover,
.e-con[class*="ctasec"] a:focus-visible,
.e-con[class*="cta001"] a:hover,
.e-con[class*="cta001"] a:focus-visible {
  color: var(--amber-on-dark) !important;
}

/* At rest they must be light too — the mobile panel's current-page item was
   #24543E on a near-black panel, measured 2.10:1. */
#offcanvas a,
.ct-panel a,
.sub-menu a,
.e-con[class*="ctasec"] a,
.e-con[class*="cta001"] a {
  color: #FFFFFF;
}

/* The amber CTA button inside a dark band keeps its own charcoal label — the
   rule above must not repaint it. */
.e-con[class*="ctasec"] .elementor-button,
.e-con[class*="cta001"] .elementor-button,
.e-con[class*="ctasec"] .elementor-button:hover,
.e-con[class*="cta001"] .elementor-button:hover {
  color: var(--charcoal, #2B2B2B) !important;
}

/* --- Hero scrim, lightened -------------------------------------------------
   Jeremy: "the gradient on the hero image is a bit dark and makes it hard to
   see the hub's building."

   The tension is real — every point of opacity taken off the scrim is taken off
   the headline's contrast. So it is rebalanced rather than simply lifted: still
   substantial where the words are, falling away much faster across the
   photograph. Re-measured after: white text stays above 7:1 on the worst
   realistic ground (scrim over a blown-out sky). */
.e-con[class*="hero0001"]::before {
  background: linear-gradient(
    100deg,
    rgba(22, 52, 38, .88) 0%,
    rgba(22, 52, 38, .80) 34%,
    rgba(22, 52, 38, .38) 62%,
    rgba(22, 52, 38, .08) 100%
  );
}

@media (max-width: 880px) {
  .e-con[class*="hero0001"]::before {
    background: linear-gradient(
      to bottom,
      rgba(22, 52, 38, .86) 0%,
      rgba(22, 52, 38, .82) 52%,
      rgba(22, 52, 38, .70) 100%
    );
  }
}

/* --- How to book, as cards -------------------------------------------------
   It was three bare columns of text next to a site that had grown cards,
   galleries and elevation everywhere else, and it looked unfinished by
   comparison. Same card language, with the step number carried in a numeral
   rather than only in the heading text. */
.e-con[class*="hbwstep"] {
  position: relative;
  background: #FFFFFF;
  border: 1px solid var(--hairline);
  border-radius: var(--radius-md, 12px);
  padding: 30px 26px 26px;
  box-shadow: var(--shadow-sm);
  transition: transform .2s var(--ease), box-shadow .2s var(--ease);
}

@media (prefers-reduced-motion: no-preference) {
  .e-con[class*="hbwstep"]:hover {
    transform: translateY(-3px);
    box-shadow: var(--shadow-md);
  }
}

/* A connecting rule between the steps, so they read as a sequence rather than
   three unrelated boxes. Desktop only — stacked on a phone they already do. */
@media (min-width: 1000px) {
  .e-con[class*="hbwrow01"] {
    position: relative;
  }

  .e-con[class*="hbwstep"]:not(:last-child)::after {
    content: "";
    position: absolute;
    top: 50%;
    right: -17px;
    width: 10px;
    height: 10px;
    border-top: 2px solid var(--green-line);
    border-right: 2px solid var(--green-line);
    transform: rotate(45deg);
  }
}

/* --- Our Story: the Cook family sign --------------------------------------- */
.pan-story-note {
  border-left: 3px solid var(--warm-amber, #E8A33D);
  padding-left: 18px;
  margin: var(--space-lg, 24px) 0;
}

/* --- Booking Calendar's own colours ---------------------------------------
   /book/ is where a booking actually happens and it was still wearing the
   plugin's defaults.

   ⚠️ Found by LOOKING. Three separate attempts to measure this calendar
   numerically all produced garbage — the detector walked past an
   image-backed container to the wrong ancestor, a regex read a modern
   `color(srgb 0.21 0.45 0.04 / 0.8)` value as if the fractions were 0–255,
   and a paint-and-read-back probe silently fell through to its inherited
   colour. Three confident wrong numbers, then a screenshot showed it in a
   second. Some things are faster to see than to measure. */

/* WPBC's selected time slot is its own blue — nothing to do with the Hub. */
.wpbc_time_selected,
.wpbc_time_selector .wpbc_time_selected {
  background-color: var(--color-link, #2E6B4F) !important;
  border-color: var(--color-link, #2E6B4F) !important;
  color: #FFFFFF !important;
}

/* The number on a part-booked (tan) day was a darker tan — legible only if you
   already knew what it said. Charcoal on tan is unambiguous.

   🔴 `:not(.datepick-unselectable)` is load-bearing. The first version of this
   rule matched `date_user_unavailable` outright, which past dates ALSO carry —
   so 1–6 September went from correctly greyed-out to solid charcoal and started
   reading as bookable. Caught by looking at the calendar after the change, not
   by any check. A fix that repaints more than it meant to is still a bug. */
td.date_user_unavailable:not(.datepick-unselectable) .date-cell-content,
td.date_user_unavailable:not(.datepick-unselectable) .date-cell-content a {
  color: var(--charcoal, #2B2B2B) !important;
}

/* Non-selectable dates must LOOK non-selectable without becoming unreadable.

   🔴 #9B968D measured 2.94:1 on white. On /book/ that is fine — they are past
   dates, and a disabled control is exempt. On /contact/ it was not: that
   calendar is READ-ONLY, so every single date carries `datepick-unselectable`,
   and the whole availability calendar — the thing the page exists to show —
   went washed out.

   The same class means "past" on one page and "informational" on another, so it
   cannot carry a disabled-looking colour. #6B6B6B is 5.34:1: still clearly
   quieter than the charcoal of a live date, still legible as information. */
td.datepick-unselectable:not(.wpbc_calendar_legend_day_cell_height) .date-cell-content,
td.datepick-unselectable:not(.wpbc_calendar_legend_day_cell_height) .date-cell-content a {
  color: #6B6B6B !important;
}

/* 🔴 The LEGEND swatches carry `datepick-unselectable` as well, so the grey
   above landed on the red "Booked" chip: 1.07:1. Third time a WPBC state class
   has meant two different things in two places. Colour the legend by its own
   state instead of inheriting a rule written for the calendar grid. */
.wpbc_calendar_legend_day_cell_height.date_available .date-cell-content,
.wpbc_calendar_legend_day_cell_height.date_available .date-cell-content a,
.wpbc_calendar_legend_day_cell_height.date_approved .date-cell-content,
.wpbc_calendar_legend_day_cell_height.date_approved .date-cell-content a {
  color: #FFFFFF !important;
}

.wpbc_calendar_legend_day_cell_height:not(.date_available):not(.date_approved) .date-cell-content,
.wpbc_calendar_legend_day_cell_height:not(.date_available):not(.date_approved) .date-cell-content a {
  color: var(--charcoal, #2B2B2B) !important;
}

/* ⚠️ White on WPBC's own green measured 3.75:1 — under AA for a 14px number.
   Hub Green is both darker and on-brand, so the fix and the branding are the
   same edit: 6.3:1. */
/* 🔴 `:not(.date_approved)` is the whole point of this rule.
   A PARTLY-booked day carries BOTH `date_available` and `date_approved` —
   available because some hours are free, approved because some are taken. The
   first version matched `date_available` alone, painted every one of them Hub
   Green, and **destroyed the three-state colour code**: free, part-booked and
   booked all became the same green, leaving a 3px dot as the only difference.
   The calendar still worked and still looked tidy, which is exactly why it took
   Jeremy saying "the bookings look weird and wrong now" to catch it.
   Green = nothing booked. Tan = partly booked. Red = gone. */
td.date_available:not(.date_approved):not(.date2approve) .wpbc-cell-box {
  background-color: var(--color-link, #2E6B4F) !important;
}

td.date_available:not(.date_approved):not(.date2approve) .date-cell-content,
td.date_available:not(.date_approved):not(.date2approve) .date-cell-content a,
/* ⚠️ …and everything inside it, including WPBC's small "·" part-day marker. */
td.date_available:not(.date_approved):not(.date2approve) .date-cell-content * {
  color: #FFFFFF !important;
}

/* Part-booked days keep WPBC's tan — but its own text colour on that tan
   measured 1.99:1, so only the INK changes here, never the ground. */
/* 🔴 SELECTED DAY — added 0.53.0.
   Clicking a free day changed nothing on screen. The available-day fill above is
   specificity 0,4,1 and was beating WPBC's own selection styling; a PART-booked
   day highlighted correctly only because the `:not()` excluded it from that rule.
   Reported from a phone, which is where it matters most — a booking form that
   gives no feedback that the date registered is a conversion problem, not a
   cosmetic one.

   Painted in Hub Amber so selection reads the same on every day type, instead of
   WPBC's off-brand blue. ⚠️ Charcoal text, never white: white on this amber is
   2.2:1 and fails. */
td.datepick-days-cell.datepick-current-day.date_available .wpbc-cell-box,
td.datepick-days-cell.datepick-current-day.date_available:not(.date_approved):not(.date2approve) .wpbc-cell-box {
  /* ⚠️ `!important` and `background-color`, deliberately, to match the rule it has
     to beat: the available-day fill below uses `background-color: … !important`
     (it needs it to override WPBC). A normal `background:` here loses to that no
     matter how specific the selector is. This rule then wins on specificity
     among the important declarations, which is the intended order. */
  background-color: var(--color-accent, #E8A33D) !important;
  box-shadow: inset 0 0 0 2px var(--color-ink, #2B2B2B);
}

td.datepick-days-cell.datepick-current-day.date_available .date-cell-content,
td.datepick-days-cell.datepick-current-day.date_available .date-cell-content a,
td.datepick-days-cell.datepick-current-day.date_available .date-cell-content *,
td.datepick-days-cell.datepick-current-day.date_available:not(.date_approved):not(.date2approve) .date-cell-content,
td.datepick-days-cell.datepick-current-day.date_available:not(.date_approved):not(.date2approve) .date-cell-content a,
td.datepick-days-cell.datepick-current-day.date_available:not(.date_approved):not(.date2approve) .date-cell-content * {
  color: var(--color-ink, #2B2B2B) !important;
}

/* ⚠️ WPBC calls a part-booked day `date_approved` in the GRID and
   `date2approve` in the LEGEND. Same state, two class names, so the legend chip
   went green while the days it described stayed tan — a legend that no longer
   matched the calendar it explained. Both names, everywhere. */
td.date_available.date_approved .date-cell-content,
td.date_available.date_approved .date-cell-content a,
td.date_available.date_approved .date-cell-content *,
td.date_available.date2approve .date-cell-content,
td.date_available.date2approve .date-cell-content a,
td.date_available.date2approve .date-cell-content * {
  color: var(--charcoal, #2B2B2B) !important;
}

/* --- 🔴 Everything inside a dark band must be light -----------------------
   The closing CTA band on five pages is Hub Green, and `.pan-small` — the
   address line and the "or see what's on" line — kept its global #5A5A5A.
   Measured 1.26:1. Reported by Jeremy as "nearly unreadable", which is generous.

   The earlier fix only recoloured LINKS in these bands. Links were the thing
   that had been reported that day, so links were what got fixed — and the
   paragraphs sitting beside them were left on a colour chosen for a cream page.
   Recolour the band, not the element you were told about. */
.e-con[class*="ctasec"] :is(p, li, span, small, figcaption, .pan-small, .pan-lead),
.e-con[class*="cta001"] :is(p, li, span, small, figcaption, .pan-small, .pan-lead) {
  color: rgba(255, 255, 255, .90);
}

.e-con[class*="ctasec"] .pan-small,
.e-con[class*="cta001"] .pan-small {
  color: rgba(255, 255, 255, .78);
}

/* The amber button keeps its charcoal label — it is not "text on the band". */
.e-con[class*="ctasec"] .elementor-button :is(span, p),
.e-con[class*="cta001"] .elementor-button :is(span, p) {
  color: var(--charcoal, #2B2B2B);
}

/* --- Navigation: which page am I on? ---------------------------------------
   🔴 The current page was styled EXACTLY like every other item — same colour,
   same weight, no underline, no background. On a seven-item menu that is a
   genuine orientation failure, not a polish nit: the header stops telling you
   where you are.

   Marked with an amber rule under the label rather than a colour swap, so it
   does not rely on distinguishing two greens, and it survives on the dark
   dropdown and the dark mobile panel where a colour change would not. */
/* ⚠️ …and the PARENT when the current page lives in a dropdown. Book and
   Regulars sit under "More", so on those two pages nothing in the top bar was
   marked at all — the indicator worked on 7 of 9 pages, which is the kind of
   gap that only shows up if you count. */
.ct-header .menu-item.current-menu-item > a,
.ct-header .menu-item.current_page_item > a,
.ct-header .menu-item.current-menu-parent > a,
.ct-header .menu-item.current-menu-ancestor > a,
.ct-header .menu-item.current_page_parent > a,
#offcanvas .menu-item.current-menu-item > a {
  position: relative;
}

.ct-header .menu-item.current-menu-item > a::after,
.ct-header .menu-item.current_page_item > a::after,
.ct-header .menu-item.current-menu-parent > a::after,
.ct-header .menu-item.current-menu-ancestor > a::after,
.ct-header .menu-item.current_page_parent > a::after,
#offcanvas .menu-item.current-menu-item > a::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: 2px;
  height: 3px;
  border-radius: 999px;
  background: var(--warm-amber, #E8A33D);
}

/* In the dropdown and the mobile panel the items are stacked, so a bar under
   the text reads as a divider. Use a leading bar instead. */
.sub-menu .menu-item.current-menu-item > a::after,
#offcanvas .menu-item.current-menu-item > a::after {
  left: -14px;
  right: auto;
  top: 50%;
  bottom: auto;
  width: 4px;
  height: 1.15em;
  transform: translateY(-50%);
}

/* --- The dropdown itself ---------------------------------------------------
   2px of radius, no padding and hairline dividers between items — it read as a
   default, because it was one. */
.sub-menu {
  border-radius: var(--radius-md, 12px) !important;
  padding: 8px !important;
  overflow: hidden;
  box-shadow: var(--shadow-lg) !important;
  border: 1px solid rgba(255, 255, 255, .10) !important;
}

.sub-menu .menu-item > a {
  border-radius: var(--radius-sm, 6px);
  padding: 10px 14px !important;
  border-bottom: 0 !important;
  transition: background-color .15s var(--ease);
}

.sub-menu .menu-item > a:hover,
.sub-menu .menu-item > a:focus-visible {
  background: rgba(255, 255, 255, .10);
}

/* --- 🔴 The month arrows were 32×2 pixels ---------------------------------
   `.datepick-next` computes to 30×0, so the anchor inside it collapsed to two
   pixels tall. On a phone that is not a small tap target, it is an unreachable
   one — and it is the control you need to book anything in the following month.
   A booking calendar you cannot page forward on is a broken booking calendar.

   Found by measuring tap targets at 375px, not by looking: at desktop pointer
   size it is hittable, so it never announced itself. */
.datepick-links,
.calendar-links {
  min-height: 44px;
  align-items: center;
}

.datepick-prev,
.datepick-next,
.datepick-current {
  min-height: 44px;
  display: flex !important;
  align-items: center;
  justify-content: center;
}

.datepick-prev a,
.datepick-next a,
.datepick-current a {
  display: flex !important;
  align-items: center;
  justify-content: center;
  min-width: 44px;
  min-height: 44px;
  border-radius: 999px;
  color: var(--color-link, #2E6B4F);
  font-size: 1.25rem;
  line-height: 1;
  transition: background-color .15s var(--ease);
}

.datepick-prev a:hover,
.datepick-next a:hover,
.datepick-current a:hover {
  background: var(--green-tint);
}

/* --- Standalone arrow links get a real target -----------------------------
   An inline link inside a sentence is exempt from target-size rules; a link
   sitting on its own line acting as the section's call to action is not one of
   those, and several were 18–21px tall. */
.entry-content p > a:only-child,
.pan-events + p > a,
.pan-home-events + p > a {
  display: inline-block;
  padding: 9px 2px;
  font-weight: 600;
}
