/* ==========================================================================
   CSS VARIABLES & ROOT STYLES
   ========================================================================== */

/* The --default-* custom properties are NOT defined in this file. They are emitted
   at runtime into an inline <style> by _includes/_templates/header.php, one per key
   of CSS_DEFAULTS (cms/_includes/_config/css_defaults.php) as --default-<key>.
   Edit them there, and remember the CMS block-settings modal reads the same
   constant, so both sides stay in step.

   A commented-out :root block used to sit here listing stale names
   (--default-backgroundColour, --default-outerGap) that no longer match the
   emitted ones (--default-background, --default-outerGapTop/Bottom). It was the
   source of the --block-background bug fixed further down this file, so it has
   been replaced with this note rather than left to mislead again. */

/* ==========================================================================
   BASE STYLES
   ========================================================================== */

html {
  /* Root font-size on the fluid canvas, so every rem in the project scales with the
     design instead of sitting at a fixed 16px. bulma.css alone has ~2100 rem values;
     this is the only way to bring them along without converting each one.
     NOT circular: --ut resolves from vw only, never from rem. And the heading rules
     below stay in `calc(<design units> * var(--ut))`, which is an absolute length, so
     they are not scaled a second time by this. */
  font-size: calc(var(--type-body) * var(--ut));
  background: none !important;
  min-width: 0 !important;
  /* was 170px, sized to clear the fixed header. Now scales with the design and only
     needs to clear the in-flow header. */
  scroll-padding-top: calc(239 * var(--u));
  --cookie-colour: var(--primary-colour);
}

body {
  background-color: var(--body-background);
}

* {
  font-variant-ligatures: none;
}

main {
  background: var(--body-background);
}

.is-static {
  position: static;
}

/* ==========================================================================
   TYPOGRAPHY
   ========================================================================== */

/* Headings.

   h6 JOINED THIS LIST ON 27 Aug. It had been omitted — the list ran h1 to h5 — so an h6 fell
   through to Bulma and rendered in the BODY font, weight 500, mixed case, no letter-spacing,
   while every other level was ABChanel Couture, weight 400, uppercase. That was invisible for a
   while because `--type-h6` is 30, the same as `--type-body` (DESIGN_TYPE in
   cms/_includes/_config/css_defaults.php), so the SIZE already matched body copy and only the
   treatment was wrong.

   What surfaced it: assets/css/tinymce-content.css redeclares all SIX levels for the editor
   iframe (it has to re-express the canvas-derived sizes as ratios of a pinned 16px base — see the
   note at the top of that file), and its h6 block is a copy of the h1-h5 ones. So the wysiwyg
   showed h6 as a small uppercase display heading and the page rendered the same markup as plain
   body text. The editor was right and this rule was the one missing a level.

   LIVE CONSEQUENCE, knowingly: the three `<h6 class="mb-2">Outside</h6>` labels on /internorm
   change from mixed-case body font to uppercase ABChanel. Their inline `color: #e41e25` still
   wins over --heading-colour. /type-test has one more.

   THE SEO-SAFE SIZE CLASSES ARE HERE TOO, added in the same pass. The rule used to key on the
   TAG alone, so `<p class="is-size-2">` got h2's size and line-height (from `html body
   *.is-size-2` below) but kept the body font and mixed case — while the editor gave it the full
   heading treatment, because tinymce-content.css lists `.is-size-N` alongside `hN`. Same
   divergence as h6, one level up, and the same resolution: the editor was right.

   Those classes exist so an editor can change how big something LOOKS without demoting it in the
   document outline — TinyMCE's "Size" group applies is-size-N to `h1,h2,h3,h4,h5,h6,p` as a
   toggle and leaves the tag alone (cms/assets/js/admin.js, search style_formats). So an
   is-size-N thing IS a heading that has been resized; it should read like one.

   SCOPED TO `.content`, NOT GLOBAL, and that is the load-bearing half. `is-size-N` is ALSO plain
   Bulma sizing used well outside prose — `_article_card.php` gives its summary `is-size-6 mb-5`
   and `_video_card.php` its meta `is-size-6 has-text-grey` — and a card summary in uppercase
   ABChanel would be plainly wrong. Those sit in `.card-content` / `.media-content`, which are
   Bulma component classes and NOT this one, so scoping excludes them. It also matches the editor
   exactly rather than approximately: the TinyMCE body carries class="content"
   (admin.js, `bodyClassParts = ['content']`), so `body.mce-content-body .is-size-N` and
   `.content .is-size-N` describe the same ground.

   1 TO 6 ONLY. `is-size-7` is Bulma's and is not on the type scale or in the editor's dropdown;
   `is-size-4-mobile` and friends are different class names and are untouched.

   NO LIVE CONTENT CHANGES: all 20 is-size-N elements across / and /internorm are heading TAGS
   inside .content, so they already render this way. This only fixes what an editor types next. */
.content h1, h1.title, .content .is-size-1,
.content h2, h2.title, .content .is-size-2,
.content h3, h3.title, .content .is-size-3,
.content h4, h4.title, .content .is-size-4,
.content h5, h5.title, .content .is-size-5,
.content h6, h6.title, .content .is-size-6 {
  color: var(--heading-colour);
  font-family: var(--heading-font), serif;
  font-weight: var(--heading-weight);
  letter-spacing: var(--heading-spacing);
  text-wrap: balance;
  text-transform: uppercase;
}

/* Heading margins, derived from the client's export rather than inherited from Bulma.
   These were Bulma's per-level em values converted to rem (h1 .7rem, h2 .5714rem, and so on).
   With --type-body at 30, that put the h2 gap at 17.1 design units — measured live, and
   measured in the export at 73-93u for the same heading. text-box-trim made the shortfall
   worse before it made it fixable: the box no longer carries half-leading, so the margin IS
   the visual gap now, where before margin + leading shared the job.
   Sampled from homepage-skeleton-nudged.jpg, heading baseline to the cap top of the body copy
   beneath it: the four h2 sections give 73.0 / 78.6 / 88.4 / 92.6u (mean 83.2), the hero h1
   gives 70.2u, and the two small headings give 60.3 / 46.3u (mean 53).
   Body copy is trimmed too now (see .content p / .content li), so margin and visual gap are the
   same measurement and these values ARE the gaps, not values offset from them.
   The figures below are the hand-tuned ones, each raised by 10u when that trim went in: the
   trim removed a measured 9.98u of the body's half-leading from every heading gap, so carrying
   the numbers across unchanged would have quietly tightened everything that had been eyed in.
   Was 60/53/48/43/43/43 against untrimmed copy; now 70/63/58/53/53/53 for the same result.
   Deliberately not snapped to SPACING_SCALE_BLOCK — those steps describe block gaps, and a text
   margin has no reason to sit on them.
   margin-top stays 0. Every heading in the export begins a section, so there is no instance of
   one following body copy to measure a top gap from — that spacing is the block gap, set per
   block in the CMS. If a heading ever does follow copy inside one text element, this is the
   number that will need a real value.
   FIRST PASS: ink-band detection on a JPEG at 1.4032 units per pixel, so read these as +/-3u.
   The exact figures are in the Affinity file. */

/* --heading-trim-comp exists because the trim degrades silently but this COMPENSATION FOR IT
   does not. Every margin below was raised by 10u when text-box-trim went in, to replace the
   body copy's half-leading that the trim removes. In a browser without the trim that leading
   is still there AND the margin is still enlarged, so the gap is paid for twice.
   Measured on /type-test at 1280px with the trim forced off: an h2 box goes 22.28px -> 36.59px
   (31.37u of leading returns), its paragraph 36.61px -> 54.06px (38.26u), the ink-to-ink gap
   between them opens by ~34.8u against a 70u target, and the page grows 454px (+12.8%).
   Support is 83% (Chrome 133+, Edge 132+, Safari 18.2+, Firefox 154+), so this is real traffic.
   Subtracted rather than duplicated on purpose: the numbers below are a FIRST PASS and will be
   replaced from the Affinity file, and a second hard-coded set in the @supports block would
   silently stop matching the moment anyone edits one. Change a number once, both paths follow.
   0 when the trim works (the margin IS the gap); 10 when it does not (restore the pre-trim
   60/53/48/43/43/43, which is what those values were tuned to). */
/* The heading margins, as tokens, because they are needed in TWO stylesheets: here in design
   units, and in assets/css/tinymce-content.css converted to `em` so the wysiwyg editor shows the
   same gap-to-type ratio. Hardcoding them twice is exactly how the editor drifted to roughly half
   the design's gaps in the first place -- its font sizes were re-derived from DESIGN_TYPE and its
   margins were not. Unitless on purpose so both consumers can multiply by whatever they need. */
:root {
  --heading-margin-1: 80;
  --heading-margin-2: 63;
  --heading-margin-3: 58;
  --heading-margin-4: 53;
  --heading-margin-5: 53;
  --heading-margin-6: 53;
}
:root { --heading-trim-comp: 0; }
@supports not (text-box-trim: trim-both) {
  :root { --heading-trim-comp: 10; }
}

.content h1, .title.is-1 {
  margin-bottom: calc((var(--heading-margin-1) - var(--heading-trim-comp)) * var(--u));
}
.content h1, .title.is-1, html body *.is-size-1 {
  line-height: var(--heading-line-height-1);
  font-size: calc(var(--type-h1) * var(--ut));
}

.content h2, .title.is-2 {
  margin-bottom: calc((var(--heading-margin-2) - var(--heading-trim-comp)) * var(--u));
}
.content h2, .title.is-2, html body *.is-size-2 {
  line-height: var(--heading-line-height-2);
  font-size: calc(var(--type-h2) * var(--ut));
}

.content h3, .title.is-3 {
  margin-bottom: calc((var(--heading-margin-3) - var(--heading-trim-comp)) * var(--u));
}
.content h3, .title.is-3, html body *.is-size-3 {
  /*--heading-font: 'AspireSC';*/
  /*--heading-weight: 500;*/
  line-height: var(--heading-line-height-3);
  font-size: calc(var(--type-h3) * var(--ut));
}

.content h4, .title.is-4 {
  margin-bottom: calc((var(--heading-margin-4) - var(--heading-trim-comp)) * var(--u));
}
.content h4, .title.is-4, html body *.is-size-4 {
  /*--heading-font: 'AspireSC';*/
  /*--heading-weight: 500;*/
  line-height: var(--heading-line-height-4);
  font-size: calc(var(--type-h4) * var(--ut));
}

.content h5, .title.is-5 {
  margin-bottom: calc((var(--heading-margin-5) - var(--heading-trim-comp)) * var(--u));
}
/* `.content .is-size-5` is repeated here on purpose. The heading-treatment rule above now carries
   it at (0,2,0), which beats the `html body *.is-size-5` in this selector at (0,1,2) — two
   classes outrank one — so without it an is-size-5 inside .content would take --heading-spacing
   and lose this -0.3px. Listing it gives both rules (0,2,0) for that selector and source order
   decides, which is this one. Nothing live is is-size-5 today; this stops it going wrong later. */
.content h5, .title.is-5, html body *.is-size-5, .content .is-size-5 {
  line-height: var(--heading-line-height-5);
  font-size: calc(var(--type-h5) * var(--ut));
  letter-spacing: -0.3px;
}

.content h6, .title.is-6 {
  margin-bottom: calc((var(--heading-margin-6) - var(--heading-trim-comp)) * var(--u));
}

/* Margins for the SEO-safe size classes (the "Size" group in TinyMCE's style dropdown).
   is-size-N already drives font-size and line-height from the type scale further down, but the
   heading margins above are keyed to the TAG — so an h2 shown at size 4 kept h2's gap and read
   too loose for its size. These key the gap to the size instead.
   `html body *.is-size-N` is (0,1,2) against `.content hN` at (0,1,1), so it wins on
   specificity alone; no !important needed. Values match the heading of the same level. */
html body *.is-size-1 { margin-bottom: calc((var(--heading-margin-1) - var(--heading-trim-comp)) * var(--u)); }
html body *.is-size-2 { margin-bottom: calc((var(--heading-margin-2) - var(--heading-trim-comp)) * var(--u)); }
html body *.is-size-3 { margin-bottom: calc((var(--heading-margin-3) - var(--heading-trim-comp)) * var(--u)); }
html body *.is-size-4 { margin-bottom: calc((var(--heading-margin-4) - var(--heading-trim-comp)) * var(--u)); }
html body *.is-size-5 { margin-bottom: calc((var(--heading-margin-5) - var(--heading-trim-comp)) * var(--u)); }
html body *.is-size-6 { margin-bottom: calc((var(--heading-margin-6) - var(--heading-trim-comp)) * var(--u)); }
.content h6, .title.is-6, html body *.is-size-6 {
  line-height: var(--heading-line-height-6);
  font-size: calc(var(--type-h6) * var(--ut));
}

@media (max-width: 768px) {
  h1 br, h2 br, h3 br, h4 br, h5 br, h6 br,
  .title br {
    display: none;
  }

  h1, h2, h3, h4, h5, h6, .title {
    overflow-wrap: break-word;
  }

  h1 span, h2 span, h3 span, h4 span, h5 span, h6 span,
  .title span {
    display: inline-block;
  }
}

/* Content styles */
.content p,
.content li {
  /* was a flat 16px, which is why the page never looked scaled */
  font-size: calc(var(--type-body) * var(--ut));
  font-weight: 400;
  line-height: 1.8;
  /* Trimmed like the headings, so a margin against body copy IS the gap the design measures.
     Untrimmed, a paragraph carried half-leading plus the difference between its ascent and its
     cap height above the first line. Measured on the live page: 9.98u, which came off the gap
     the moment this was added. Only the block's outer edges change — line spacing inside a
     paragraph is line-height and is untouched. */
  text-box-trim: trim-both;
  text-box-edge: cap alphabetic;
  text-wrap-style: pretty;
}

.content p.is-size-1 { line-height: 1.05; }
.content p.is-size-2 { line-height: 1.2; }
.content p.is-size-3 { line-height: 1.15; }
.content p.is-size-4,
.content p.is-size-5 { line-height: 1.3; }

.content .circle-number {
  display: inline-flex;
  justify-items: center;
  text-align: center;
  gap: 1rem;
  margin: 0 0 2rem 0;
  width: 60px;
  height: 60px;
  background: #ffffff12;
  border-radius: 50%;
  align-items: center;
  justify-content: center;
  color: var(--body-colour);
  font-size: 1.4rem;
  font-weight: 500;
  font-family: var(--heading-font);
}


.content .circle-number--primary {
  background-color: var(--primary-colour);
  color: var(--primary-colour-contrast);
}

/* Remove bottom margin from last elements */
h1:last-child, h2:last-child, h3:last-child,
h4:last-child, h5:last-child, h6:last-child,
p:last-child, li:last-child,
.content > *:last-child {
  margin-bottom: 0;
}

.content p .button:first-child:last-child {
  margin-top: 0.6rem;
}

.gradient-text {
    background: linear-gradient(135deg, #00bcef, #95e426);
    -webkit-background-clip: text;
    -webkit-text-fill-color: transparent;
    background-clip: text;
    color: transparent;
}

/* ==========================================================================
   LINKS & BUTTONS
   ========================================================================== */

a {
  transition: background 0.2s ease-in-out, color 0.2s ease-in-out, border-color 0.2s ease-in-out;
}

.button {
  font-weight: var(--button-font-weight);
  font-size: var(--button-font-size);
  border-radius: var(--button-radius);
  height: var(--button-height);
  padding: 1rem 1.7rem;
  /*clip-path: polygon(0 0, 100% 0, 100% calc(100% - 10px), calc(100% - 10px) 100%, 0 100%);*/
  font-family: var(--button-font);
  text-transform: uppercase;
}
.button:hover {
  /*clip-path: polygon(0 0, 100% 0, 100% calc(100% - 16px), calc(100% - 16px) 100%, 0 100%);*/
}

.button.is-text-button-inline {
  height: auto;
  min-height: 0;
  padding: 0 0 .35rem;
}

.button.is-brand-green {
  background-color: var(--brand-green);
  border-color: var(--brand-green);
  color: #fff;
}
.button.is-brand-green:hover,
.button.is-brand-green:focus {
  background-color: var(--brand-green-dark);
  border-color: var(--brand-green-dark);
  color: #fff;
}
.button.is-brand-green.is-outlined {
  background-color: transparent;
  border-color: var(--brand-green);
  color: var(--brand-green);
}
.button.is-brand-green.is-outlined:hover,
.button.is-brand-green.is-outlined:focus {
  background-color: var(--brand-green);
  border-color: var(--brand-green);
  color: #fff;
}

.button.is-brand-blue {
  background-color: var(--brand-blue);
  border-color: var(--brand-blue);
  color: #fff;
}
.button.is-brand-blue:hover,
.button.is-brand-blue:focus {
  background-color: var(--brand-blue-dark);
  border-color: var(--brand-blue-dark);
  color: #fff;
}
.button.is-brand-blue.is-outlined {
  background-color: transparent;
  border-color: var(--brand-blue);
  color: var(--brand-blue);
}
.button.is-brand-blue.is-outlined:hover,
.button.is-brand-blue.is-outlined:focus {
  background-color: var(--brand-blue);
  border-color: var(--brand-blue);
  color: #fff;
}

.button.is-light,
.button.is-primary.is-light,
.button.is-link.is-light {
  background-color: var(--light-colour);
  border-color: transparent;
  color: var(--light-colour-contrast);
}

.button.is-light.is-hovered,
.button.is-light:hover,
.button.is-primary.is-light.is-hovered,
.button.is-primary.is-light:hover,
.button.is-link.is-light.is-hovered,
.button.is-link.is-light:hover {
  background-color: var(--light-colour-hover);
  border-color: transparent;
  color: var(--light-colour-contrast);
}

.button.is-light.is-focused,
.button.is-light:focus,
.button.is-primary.is-light.is-focused,
.button.is-primary.is-light:focus,
.button.is-link.is-light.is-focused,
.button.is-link.is-light:focus {
  border-color: transparent;
  color: var(--light-colour-contrast);
}

.button.is-light.is-focused:not(:active),
.button.is-light:focus:not(:active),
.button.is-primary.is-light.is-focused:not(:active),
.button.is-primary.is-light:focus:not(:active),
.button.is-link.is-light.is-focused:not(:active),
.button.is-link.is-light:focus:not(:active) {
  box-shadow: 0 0 0 0.125em var(--light-colour-focus-ring);
}

.button.is-light.is-active,
.button.is-light:active,
.button.is-primary.is-light.is-active,
.button.is-primary.is-light:active,
.button.is-link.is-light.is-active,
.button.is-link.is-light:active {
  background-color: var(--light-colour-active);
  border-color: transparent;
  color: var(--light-colour-contrast);
}

.button.is-light[disabled],
fieldset[disabled] .button.is-light,
.button.is-primary.is-light[disabled],
fieldset[disabled] .button.is-primary.is-light,
.button.is-link.is-light[disabled],
fieldset[disabled] .button.is-link.is-light {
  background-color: var(--light-colour);
  border-color: transparent;
  box-shadow: none;
  color: var(--light-colour-contrast);
}

.button.is-light.is-loading::after,
.button.is-primary.is-light.is-loading::after,
.button.is-link.is-light.is-loading::after {
  border-color: transparent transparent var(--light-colour-contrast) var(--light-colour-contrast) !important;
}

.button.is-light.is-outlined,
.button.is-primary.is-light.is-outlined,
.button.is-link.is-light.is-outlined {
  background-color: transparent;
  border-color: var(--light-colour-outline);
  color: var(--light-colour-outline);
}

.button.is-light.is-outlined.is-hovered,
.button.is-light.is-outlined:hover,
.button.is-light.is-outlined.is-focused,
.button.is-light.is-outlined:focus,
.button.is-primary.is-light.is-outlined.is-hovered,
.button.is-primary.is-light.is-outlined:hover,
.button.is-primary.is-light.is-outlined.is-focused,
.button.is-primary.is-light.is-outlined:focus,
.button.is-link.is-light.is-outlined.is-hovered,
.button.is-link.is-light.is-outlined:hover,
.button.is-link.is-light.is-outlined.is-focused,
.button.is-link.is-light.is-outlined:focus {
  background-color: var(--light-colour);
  border-color: var(--light-colour-outline);
  color: var(--light-colour-contrast);
}

.button.is-light.is-outlined.is-loading::after,
.button.is-primary.is-light.is-outlined.is-loading::after,
.button.is-link.is-light.is-outlined.is-loading::after {
  border-color: transparent transparent var(--light-colour-outline) var(--light-colour-outline) !important;
}

.button.is-light.is-outlined.is-loading.is-hovered::after,
.button.is-light.is-outlined.is-loading:hover::after,
.button.is-light.is-outlined.is-loading.is-focused::after,
.button.is-light.is-outlined.is-loading:focus::after,
.button.is-primary.is-light.is-outlined.is-loading.is-hovered::after,
.button.is-primary.is-light.is-outlined.is-loading:hover::after,
.button.is-primary.is-light.is-outlined.is-loading.is-focused::after,
.button.is-primary.is-light.is-outlined.is-loading:focus::after,
.button.is-link.is-light.is-outlined.is-loading.is-hovered::after,
.button.is-link.is-light.is-outlined.is-loading:hover::after,
.button.is-link.is-light.is-outlined.is-loading.is-focused::after,
.button.is-link.is-light.is-outlined.is-loading:focus::after {
  border-color: transparent transparent var(--light-colour-contrast) var(--light-colour-contrast) !important;
}

.button.is-light.is-inverted,
.button.is-primary.is-light.is-inverted,
.button.is-link.is-light.is-inverted {
  background-color: var(--light-colour-contrast);
  color: var(--light-colour);
}

.button.is-light.is-inverted.is-hovered,
.button.is-light.is-inverted:hover,
.button.is-primary.is-light.is-inverted.is-hovered,
.button.is-primary.is-light.is-inverted:hover,
.button.is-link.is-light.is-inverted.is-hovered,
.button.is-link.is-light.is-inverted:hover {
  background-color: var(--light-colour-contrast);
  color: var(--light-colour);
}

.button.is-light.is-inverted[disabled],
fieldset[disabled] .button.is-light.is-inverted,
.button.is-primary.is-light.is-inverted[disabled],
fieldset[disabled] .button.is-primary.is-light.is-inverted,
.button.is-link.is-light.is-inverted[disabled],
fieldset[disabled] .button.is-link.is-light.is-inverted {
  background-color: var(--light-colour-contrast);
  border-color: transparent;
  box-shadow: none;
  color: var(--light-colour);
}

.button.is-light.is-inverted.is-outlined,
.button.is-primary.is-light.is-inverted.is-outlined,
.button.is-link.is-light.is-inverted.is-outlined {
  background-color: transparent;
  border-color: var(--light-colour-contrast);
  color: var(--light-colour-contrast);
}

.button.is-light.is-inverted.is-outlined.is-hovered,
.button.is-light.is-inverted.is-outlined:hover,
.button.is-light.is-inverted.is-outlined.is-focused,
.button.is-light.is-inverted.is-outlined:focus,
.button.is-primary.is-light.is-inverted.is-outlined.is-hovered,
.button.is-primary.is-light.is-inverted.is-outlined:hover,
.button.is-primary.is-light.is-inverted.is-outlined.is-focused,
.button.is-primary.is-light.is-inverted.is-outlined:focus,
.button.is-link.is-light.is-inverted.is-outlined.is-hovered,
.button.is-link.is-light.is-inverted.is-outlined:hover,
.button.is-link.is-light.is-inverted.is-outlined.is-focused,
.button.is-link.is-light.is-inverted.is-outlined:focus {
  background-color: var(--light-colour-contrast);
  border-color: var(--light-colour-contrast);
  color: var(--light-colour);
}

.button.is-light.is-inverted.is-outlined.is-loading::after,
.button.is-primary.is-light.is-inverted.is-outlined.is-loading::after,
.button.is-link.is-light.is-inverted.is-outlined.is-loading::after {
  border-color: transparent transparent var(--light-colour-contrast) var(--light-colour-contrast) !important;
}

.button.is-light.is-inverted.is-outlined.is-loading.is-hovered::after,
.button.is-light.is-inverted.is-outlined.is-loading:hover::after,
.button.is-light.is-inverted.is-outlined.is-loading.is-focused::after,
.button.is-light.is-inverted.is-outlined.is-loading:focus::after,
.button.is-primary.is-light.is-inverted.is-outlined.is-loading.is-hovered::after,
.button.is-primary.is-light.is-inverted.is-outlined.is-loading:hover::after,
.button.is-primary.is-light.is-inverted.is-outlined.is-loading.is-focused::after,
.button.is-primary.is-light.is-inverted.is-outlined.is-loading:focus::after,
.button.is-link.is-light.is-inverted.is-outlined.is-loading.is-hovered::after,
.button.is-link.is-light.is-inverted.is-outlined.is-loading:hover::after,
.button.is-link.is-light.is-inverted.is-outlined.is-loading.is-focused::after,
.button.is-link.is-light.is-inverted.is-outlined.is-loading:focus::after {
  border-color: transparent transparent var(--light-colour) var(--light-colour) !important;
}

.notification.is-light,
.notification.is-primary.is-light,
.notification.is-link.is-light {
  background-color: var(--light-colour);
  color: var(--light-colour-contrast);
}

.tag:not(body).is-light,
.tag:not(body).is-primary.is-light,
.tag:not(body).is-link.is-light {
  background-color: var(--light-colour);
  color: var(--light-colour-contrast);
}

/*.button {
  font-weight: 600;
  font-size: 15px;
  border-radius: var(--button-radius);
  height: var(--button-height);
  padding: 1rem 1.7rem;
  border-radius:
    0px
    20px
    20px
    20px;
  transition: border-radius 0.2s ease, transform 0.2s ease;
}


.navbar-item .button {
  font-size: 15px;
}*/

/* Arrow styling */
.arrow:before {
  display: inline-block;
  font-style: normal;
  font-variant: normal;
  text-rendering: auto;
  -webkit-font-smoothing: antialiased;
  font-family: "Font Awesome 5 Pro";
  content: "\f178";
  font-weight: 300;
  font-size: 1.7rem;
  vertical-align: middle;
  margin: 0 15px 0 0;
  position: relative;
  top: -1px;
  right: 0;
  transition: all 0.5s ease;
  cursor: pointer;
  color: var(--nav-arrow-colour);
}

.arrow:hover:before {
  right: -2px;
}

/* ==========================================================================
   ELEMENTS: SECTOR GRID
   ========================================================================== */

.sector-grid {
  display: grid;
  gap: 1rem;
  grid-template-columns: minmax(0, 1fr);
  align-items: stretch;
  grid-auto-rows: 285px;
}

.project-grid {
  display: flex;
  flex-direction: column;
  gap: 1rem;
}

.project-grid__row {
  display: grid;
  gap: 1rem;
  grid-template-columns: minmax(0, 1fr);
  align-items: stretch;
}

.sector-grid .listing.listing-overlay.sector-card,
.project-grid__row .listing.listing-overlay.project-card {
  position: relative;
  top: 0;
  overflow: visible;
  height: 100%;
  margin-bottom: 0;
  border: 0;
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--body-colour) 12%, transparent);
  background: var(--body-background);
  /* The hover lift is done with `top`, NOT `transform`. A transform composites
     the card at its fractional resting position and drags the overflow clip
     across sub-pixels, leaving a 1px hairline at the bottom edge mid-transition
     (the zooming image's edge row bleeds through). `top` re-rasterises cleanly
     each frame — identical 4px lift, no seam. (overflow:visible + the clip on
     .image-container is left as belt-and-braces; not strictly required now.) */
  transition: top .5s cubic-bezier(.2,.8,.2,1), box-shadow .3s ease;
  text-decoration: none;
}

.sector-grid .listing.listing-overlay.sector-card:hover,
.project-grid__row .listing.listing-overlay.project-card:hover {
  top: -4px;
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--primary-colour) 35%, transparent);
}

.sector-grid .listing.listing-overlay.sector-card--large {
  min-height: 450px;
}

.sector-grid .listing.listing-overlay.sector-card--standard {
  min-height: 250px;
}

.project-grid__row--top .listing.listing-overlay.project-card {
  min-height: 380px;
}

.project-grid__row--bottom .listing.listing-overlay.project-card {
  min-height: 280px;
}

.sector-grid .listing.listing-overlay .image-container,
.project-grid__row .listing.listing-overlay .image-container {
  position: absolute;
  inset: 0;
  overflow: hidden;
  z-index: 0;
  line-height: 0;
}

.sector-grid .listing.listing-overlay .image-container .image,
.sector-grid .listing.listing-overlay .image-container .image img,
.project-grid__row .listing.listing-overlay .image-container .image,
.project-grid__row .listing.listing-overlay .image-container .image img {
  width: 100%;
  height: 100%;
}

.sector-grid .listing.listing-overlay .image-container .image,
.project-grid__row .listing.listing-overlay .image-container .image {
  position: absolute;
  inset: 0;
  margin: 0;
  border-radius: 0;
  line-height: 0;
}

.sector-grid .listing.listing-overlay .image-container img,
.project-grid__row .listing.listing-overlay .image-container img {
  display: block;
  object-fit: cover;
  transform: scale(1);
  transition: transform .8s cubic-bezier(.2,.8,.2,1);
}

.sector-grid .listing.listing-overlay:hover .image-container img,
.project-grid__row .listing.listing-overlay:hover .image-container img {
  transform: scale(1.04);
}

.sector-grid .listing.listing-overlay .image-container:before,
.project-grid__row .listing.listing-overlay .image-container:before {
  position: absolute;
  inset: 0;
  z-index: 1;
  background: linear-gradient(
    180deg,
    color-mix(in srgb, var(--dark-colour) 12%, transparent) 0%,
    color-mix(in srgb, var(--dark-colour) 52%, transparent) 55%,
    color-mix(in srgb, var(--dark-colour) 92%, transparent) 100%
  );
  opacity: .84;
}

.sector-grid .listing.listing-overlay .content,
.project-grid__row .listing.listing-overlay .content {
  bottom: 1.35rem;
  left: 1.35rem;
  right: 1.35rem;
  color: var(--heading-colour);
}

.sector-grid .listing.listing-overlay .content-inner,
.project-grid__row .listing.listing-overlay .content-inner {
  bottom: 0;
  display: flex;
  justify-content: space-between;
  align-items: flex-end;
  gap: .75rem;
  transition: none;
}
.sector-grid .listing.listing-overlay.sector-card--large .content-inner {
  flex-direction: column;
  justify-content: flex-end;
  align-items: normal;
}

.project-grid .listing.listing-overlay.project-card .content-inner {
  min-height: 100%;
}

.sector-grid .listing.listing-overlay .content-wrapper,
.project-grid__row .listing.listing-overlay .content-wrapper {
  max-width: 34rem;
  color: color-mix(in srgb, var(--body-colour) 74%, transparent);
  font-size: .98rem;
  line-height: 1.7;
}

.sector-card__title,
.project-card__title {
  position: relative;
  bottom: -5px;
  text-shadow: 0 1px 18px color-mix(in srgb, var(--dark-colour) 15%, transparent);
}

.sector-card__summary,
.project-card__summary {
  max-width: 34rem;
}

.project-card__eyebrow,
.project-card__location {
  color: color-mix(in srgb, var(--body-colour) 78%, transparent);
  letter-spacing: .14em;
}

.sector-card__footer,
.project-card__footer {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  margin-top: 1.25rem;
}

.sector-card__footer--arrow-only,
.project-card__footer--arrow-only {
  justify-content: flex-end;
}

.sector-card__cta,
.project-card__cta {
  display: inline-flex;
  align-items: center;
  gap: .45rem;
  color: var(--primary-colour);
  font-family: var(--heading-font), sans-serif;
  font-size: .8rem;
  letter-spacing: .18em;
  text-transform: uppercase;
  text-decoration: none;
}

.circle-arrow-button {
  --circle-arrow-button-border: color-mix(in srgb, var(--body-colour) 28%, transparent);
  --circle-arrow-button-bg: color-mix(in srgb, var(--dark-colour) 8%, transparent);
  --circle-arrow-button-color: var(--heading-colour);
  --circle-arrow-button-hover-border: var(--primary-colour);
  --circle-arrow-button-hover-bg: var(--primary-colour);
  --circle-arrow-button-hover-color: var(--primary-colour-contrast);
  display: flex;
  align-items: center;
  justify-content: center;
  width: 2.25rem;
  height: 2.25rem;
  border-radius: 999px;
  border: 1px solid var(--circle-arrow-button-border);
  background: var(--circle-arrow-button-bg);
  color: var(--circle-arrow-button-color);
  flex: 0 0 auto;
  transition: border-color .3s ease, background-color .3s ease, color .3s ease;
}

.circle-arrow-button:hover,
.circle-arrow-button:focus-visible {
  border-color: var(--circle-arrow-button-hover-border);
  background-color: var(--circle-arrow-button-hover-bg);
  color: var(--circle-arrow-button-hover-color);
}

.sector-grid .listing.listing-overlay.sector-card:hover .circle-arrow-button,
.project-grid__row .listing.listing-overlay.project-card:hover .circle-arrow-button {
  --circle-arrow-button-border: var(--primary-colour);
  --circle-arrow-button-bg: var(--primary-colour);
  --circle-arrow-button-color: var(--primary-colour-contrast);
}

.sector-grid .listing.listing-overlay.sector-card:hover .sector-card__cta {
  color: var(--secondary-colour);
}

section .listing.listing-service .listing-service__buttons {
  margin-top: 1.5rem;
}

section .listing.listing-service .listing-service__cta {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: .9rem;
  font-family: var(--heading-font);
  font-size: .8rem;
  letter-spacing: .18em;
  line-height: 1;
  text-decoration: none;
  text-transform: uppercase;
  width: 100%;
  color: #fff;
}

section .listing.listing-service .listing-service__cta:hover,
section .listing.listing-service .listing-service__cta:focus-visible {
  color: var(--listing-service-accent, var(--primary-colour));
}

section .listing.listing-service .listing-service__cta .circle-arrow-button {
  --circle-arrow-button-hover-border: var(--listing-service-accent, var(--primary-colour));
  --circle-arrow-button-hover-bg: var(--listing-service-accent, var(--primary-colour));
  --circle-arrow-button-hover-color: var(--primary-colour-contrast);
}

section .listing.listing-service .listing-service__cta:hover .circle-arrow-button,
section .listing.listing-service .listing-service__cta:focus-visible .circle-arrow-button {
  --circle-arrow-button-border: var(--listing-service-accent, var(--primary-colour));
  --circle-arrow-button-bg: var(--listing-service-accent, var(--primary-colour));
  --circle-arrow-button-color: var(--primary-colour-contrast);
}

@media (min-width: 640px) {
  .sector-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    grid-auto-rows: 315px;
  }

  /* Columns follow the number of cards in the row, so short rows (1–2 cards)
     never leave empty tracks. Top rows hold ≤2 cards and bottom rows ≤3, so a
     full set still renders as the intended 2-up / 3-up layout. */
  .project-grid__row:has(.project-card:nth-child(3)) {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }
  .project-grid__row:has(.project-card:nth-child(2)):not(:has(.project-card:nth-child(3))) {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
  .project-grid__row:not(:has(.project-card:nth-child(2))) {
    grid-template-columns: minmax(0, 1fr);
  }

  .sector-grid .listing.listing-overlay.sector-card--large {
    grid-column: span 2;
    grid-row: span 2;
    min-height: 510px;
  }
}

@media (min-width: 1024px) {
  .sector-grid {
    grid-template-columns: repeat(3, minmax(0, 1fr));
    grid-auto-flow: dense;
    grid-auto-rows: 285px;
  }

  .sector-grid .listing.listing-overlay.sector-card--large {
    grid-column: span 2;
    grid-row: span 2;
  }

  .sector-grid .listing.listing-overlay.sector-card--standard {
    grid-column: span 1;
  }

  .project-grid__row--top .listing.listing-overlay.project-card {
    min-height: 440px;
  }

  .project-grid__row--bottom .listing.listing-overlay.project-card {
    min-height: 300px;
  }
}

/* ==========================================================================
   ELEMENTS: ARROW
   ========================================================================== */

.arrow-element {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  width: 4rem;
  height: 4rem;
  background-color: var(--primary-colour);
  color: var(--primary-colour-contrast);
  border-radius: 50%;
  margin: 0 auto;
}

.arrow-element::before {
  content: 'ÃƒÂ¢Ã¢â‚¬Â Ã¢â‚¬â„¢';
  font-size: 2.4rem;
  line-height: 1;
}

.arrow-element[style*="--element-direction: left"]::before {
  content: 'ÃƒÂ¢Ã¢â‚¬Â Ã‚Â';
}

.arrow-element[style*="--element-direction: up"]::before {
  content: 'ÃƒÂ¢Ã¢â‚¬Â Ã¢â‚¬Ëœ';
}

.arrow-element[style*="--element-direction: down"]::before {
  content: 'ÃƒÂ¢Ã¢â‚¬Â Ã¢â‚¬Å“';
}

/* ==========================================================================
   FORM ELEMENTS
   ========================================================================== */

.input, .textarea, .select select, .is-select {
  background-color: #ffffff;
  border: 2px solid #17171717;
  border-radius: var(--border-radius);
  box-shadow: none;
}

form .fields {
  gap: 1.25rem;
}

form .fields .field {
  position: relative;
  margin-bottom: 0;
}

form .fields .field > label.label {
  color: rgba(245, 241, 236, 0.72);
  font-family: var(--main-font), system-ui, sans-serif;
  font-size: 0.68rem;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  margin-bottom: 0.55rem;
}

form .fields .field .input,
form .fields .field .textarea,
form .fields .field .select select,
form .fields .field .is-select {
  min-height: 50px;
  padding: 0.8rem 0.9rem;
  background: rgba(255, 255, 255, 0.04);
  border: 1px solid rgba(255, 255, 255, 0.12);
  color: var(--body-colour);
  font-size: 0.9rem;
}

form .fields .field .textarea {
  min-height: 112px;
}

form .fields .field .input::placeholder,
form .fields .field .textarea::placeholder {
  color: rgba(245, 241, 236, 0.45);
}

form .fields .field_type_checkbox .control {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 0.5rem;
}

form .fields .field_type_checkbox .control > .is-checkradio[type="checkbox"] + label {
  width: auto;
  margin: 0;
  min-height: 44px;
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.8rem 0.95rem 0.8rem 2.4rem;
  border: 1px solid rgba(255, 255, 255, 0.12);
  background: rgba(255, 255, 255, 0.02);
  color: rgba(245, 241, 236, 0.82);
  font-size: 0.8rem;
  line-height: 1.2;
  cursor: pointer;
  transition: border-color 0.2s ease, background-color 0.2s ease, color 0.2s ease;
}

form .fields .field_type_checkbox .control > .is-checkradio[type="checkbox"] + label:hover {
  border-color: var(--secondary-colour);
  color: var(--body-colour);
}

form .fields .field_type_checkbox .control > .is-checkradio[type="checkbox"] + label::before,
form .fields .field_type_checkbox .control > .is-checkradio[type="checkbox"] + label::after {
  left: 0.7rem;
  top: 50%;
  transform: translateY(-50%);
}

form .fields .field_type_checkbox .control > .is-checkradio[type="checkbox"] + label::before {
  width: 1rem;
  height: 1rem;
  border-radius: 2px;
}

form .fields .field_type_checkbox .control > .is-checkradio[type="checkbox"] + label::after {
  width: 0.35rem;
  height: 0.65rem;
  left: 1.02rem;
}

form .fields .field_type_button {
  margin-top: 0.15rem;
}

form .fields .field_type_button .control {
  margin-top: 0 !important;
  text-align: left !important;
}

form .fields .field_type_button .button {
  width: 100%;
  justify-content: center;
}

form .fields .field_type_button .button::after {
  content: '\2192';
  display: inline-block;
  margin-left: 0.75rem;
  font-size: 1.05em;
  line-height: 1;
}

@media (max-width: 768px) {
  form .fields .field_type_checkbox .control {
    grid-template-columns: 1fr;
  }
}

.input[type="date"] {
  display: block;
  width: 100%;
  min-width: 0;
  -moz-appearance: auto;
  -webkit-appearance: auto;
  appearance: auto;
}

.input[type="date"]::-webkit-calendar-picker-indicator {
  cursor: pointer;
}

.mce-content-body {
  background: transparent !important;
  padding: 1rem !important;
}

.fields {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
}

.fields .field {
  width: 100%;
}

.fields .field.field_type_button,
.fields .field.field_type_text_box {
  width: 100%;
}

.fields .field.field_type_hidden,
.fields .field.is-hidden {
  display: none;
}

.fields.fields-venue-hire {
  gap: 1.5rem 2%;
  align-items: flex-start;
}

.fields.fields-venue-hire .field.field_type_text,
.fields.fields-venue-hire .field.field_type_email,
.fields.fields-venue-hire .field.field_type_number,
.fields.fields-venue-hire .field.field_type_date,
.fields.fields-venue-hire .field.field_type_venue_space,
.fields.fields-venue-hire .field.field_type_venue_event_type {
  width: calc(50% - 1%);
}

.fields.fields-venue-hire .field.field_type_text_box,
.fields.fields-venue-hire .field.field_type_button {
  width: 100%;
}

.fields.fields-columns-2,
.fields.fields-columns-3,
.fields.fields-columns-4 {
  column-gap: 3%;
  row-gap: 1.5rem;
  align-items: flex-start;
}

.fields.fields-columns-2 .field,
.fields.fields-columns-3 .field,
.fields.fields-columns-4 .field {
  margin-bottom: 0;
}

.fields.fields-columns-2 .field:not(.field_type_text_box):not(.field_type_heading):not(.field_type_label):not(.field_type_hidden):not(.field_type_button):not(.field_type_checkbox):not(.field_type_radio):not(.field_type_select) {
  width: calc(50% - 1.5%);
}

.fields.fields-columns-3 .field:not(.field_type_text_box):not(.field_type_heading):not(.field_type_label):not(.field_type_hidden):not(.field_type_button):not(.field_type_checkbox):not(.field_type_radio):not(.field_type_select) {
  width: calc(33.333% - 2%);
}

.fields.fields-columns-4 .field:not(.field_type_text_box):not(.field_type_heading):not(.field_type_label):not(.field_type_hidden):not(.field_type_button):not(.field_type_checkbox):not(.field_type_radio):not(.field_type_select) {
  width: calc(25% - 2.25%);
}

.fields.fields-columns-2 .field.field_type_button,
.fields.fields-columns-3 .field.field_type_button,
.fields.fields-columns-4 .field.field_type_button {
  width: 100%;
}

.fields .field label {
  color: var(--body-colour);
  font-weight: 600;
  font-size: 0.9rem;
  margin-bottom: 0.3rem;
  display: block;
}

.fields .field.required > label:after {
  content: '*';
  display: inline-block;
  margin-left: 2px;
  color: var(--secondary-colour);
}

@media (max-width: 768px) {
  .fields.fields-columns-2 .field,
  .fields.fields-columns-3 .field,
  .fields.fields-columns-4 .field {
    width: 100% !important;
  }
}

/* Horizontal fields */
.fields.fields-horizontal {
  flex-wrap: nowrap;
  gap: 2%;
  align-items: flex-end;
}

.fields.fields-horizontal .field {
  margin-bottom: 0;
}

.fields.fields-horizontal .field.field_type_button .button {
  width: 100%;
}

.field_type_heading + .field_type_label {
  margin-top: -10px;
}

.field_type_label p {
  opacity: .7;
}

.field_type_checkbox .control {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
}
.field_type_checkbox .control > label {
  width: 48%;
}

/* File uploader */
.file.uploader {
  position: relative;
  border: 2px dashed #d4d4d4;
  padding: 20px;
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 132px;
  background: #fff;
  border-radius: var(--border-radius);
}

.file.uploader progress {
  -moz-appearance: none;
  -webkit-appearance: none;
  border: none;
  display: block;
  height: 0.75rem;
  overflow: hidden;
  padding: 0;
  width: 100%;
  margin-bottom: 0;
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  border-radius: 4px 4px 0 0;
}

.file.uploader progress:indeterminate {
  background-image: linear-gradient(to right, #9d221e 30%, #ededed 30%);
}

.file.uploader progress[value="0"] {
  opacity: 0;
}

.file.uploader .file-input {
  height: 100%;
  left: 0;
  opacity: 0;
  outline: none;
  position: absolute;
  top: 0;
  width: 100%;
}

.file.uploader .preview {
  position: absolute;
  top: 0;
  left: 0;
  bottom: 0;
  right: 0;
  z-index: 5;
  margin: 0;
  background-size: cover;
}

.file.uploader .file-label {
  margin: 0;
  position: relative;
  z-index: 10;
}

.file.uploader .file-cta .file-name {
  border-color: #dbdbdb;
  border-style: solid;
  border-width: 1px 1px 1px 0;
  display: block;
  max-width: 16em;
  overflow: hidden;
  text-align: left;
  text-overflow: ellipsis;
}

.file.uploader .file-cta .file-icon {
  align-items: center;
  display: flex;
  height: 1em;
  justify-content: center;
  margin-right: 0.5em;
  width: 1em;
}

/* Country picker */
.country-picker {
  padding: 2px 0 !important;
}

.country-picker .navbar-dropdown {
  border: none !important;
  z-index: 99;
  width: 150px;
  left: inherit;
  padding: 0.2rem 0;
  min-width: 0;
  border-radius: var(--border-radius);
  right: 0;
}

.country-picker .navbar-dropdown .navbar-item {
  padding: 0.35rem 0.6rem !important;
  background: transparent !important;
  text-align: left;
  color: #212528 !important;
  font-size: 0.8rem;
  width: 100%;
  justify-content: flex-start;
}

.country-picker .navbar-dropdown .navbar-item:hover {
  background-color: #f3f4f5 !important;
}

.country-picker > .navbar-link {
  background: #fff !important;
  padding: 0.3rem 1.6rem 0.3rem 0.4rem;
  border-radius: var(--border-radius);
  color: #212528 !important;
  font-size: 0.8rem;
}

.country-picker > .navbar-link:after {
  right: 0.725em;
  border-color: #525e68;
}

.country-picker img.flag {
  height: 18px;
  border-radius: 2px;
  margin-right: 0.4rem;
  display: inline-block;
}

/* Form validation */
#form_2 .notification {
  color: var(--primary-colour-contrast) !important;
  font-weight: 600;
  text-align: center;
}

#form_2 .notification.is-success {
  background-color: var(--dark-colour) !important;
}

/* ==========================================================================
   NAVIGATION
   ========================================================================== */

/* Header */
section.header {
  /* position: fixed removed for now: it took the header out of flow, which is what let it
     paint over anything inside a block's stacking context, and it fights a design whose
     vertical rhythm is measured from the top of the page. Restore by uncommenting. */
  /* position: fixed; */
  position: sticky;
  left: 0;
  right: 0;
  top: 0;
  z-index: 40;
  background-color: transparent;
  backdrop-filter: blur(0);
  transition:
    border 0.25s ease,
    background-color 0.25s ease,
    backdrop-filter 0.25s ease;
  background: var(--header-background);
  /* border-bottom: 1px solid #ffffff33; */
}

/*body.scrolling section.header {
  background-color: #00000017;
  backdrop-filter: blur(4px);
  border-bottom-width: 0;
}*/

/*body#home section.header {
  position: absolute;
  background: transparent;
}*/



section.header .navbar .container {
  /* Removed: display:grid + grid-template-columns:minmax(0,1fr) auto minmax(0,1fr), and
     column-gap:.5rem.
     The grid never ran. The element carries Bulma's is-flex helper, which is
     display:flex !important, so the computed display was always flex and the three-track
     template was dead code — left over from when the header had a navbar-center, removed
     at _includes/_templates/header.php:135.
     column-gap DID apply, because flex honours gap, and it was the nav misalignment:
     .navbar-start is width:100% (below), so it takes the whole container, .navbar-end
     collapses to 0 and the gap shunts it past the right edge, with its links overflowing
     visibly outside. Measured at 1885px: "Enquire" ended 16u (= .5rem = 16 design units)
     beyond the container's right edge, and lands exactly flush once the gap is gone.
     align-items:center went with them — is-align-items-center already sets it !important.
     Layout now comes entirely from the helper classes on the element itself:
     is-flex is-align-items-center is-justify-content-space-between. */
  max-width: 100%;
}

section.header .navbar-start,
section.header .navbar-end {
  min-width: 0;
  display: flex;
  align-items: center;
  width: 100%;
}

section.header .navbar-start {
  justify-content: flex-end;
}

section.header .navbar-brand {
  justify-content: flex-start;
  justify-self: center;
  /* padding: 0 .75rem; */
}

section.header .navbar-end {
  justify-content: flex-end;
  gap: 1rem;
}

section.header .navbar-nav-left,
section.header .navbar-nav-right {
  display: block;
}

section.header .navbar-nav-left > ul {
  justify-content: flex-end;
}

section.header .navbar-nav-right > ul {
  justify-content: flex-start;
}

section.header .navbar-nav > ul {
  gap: .25rem;
}

/* Header nav, per the client's design: uppercase, widely letterspaced, small. */
section.header .navbar-center nav a,
section.header .navbar-end nav a {
  text-transform: uppercase;
  letter-spacing: var(--nav-letter-spacing);
  font-family: var(--nav-font);
  font-size: var(--nav-font-size);
  font-weight: var(--nav-font-weight);
  color: var(--nav-link-colour);
}
section.header .navbar-center nav a,
section.header .navbar-end nav a {
  text-decoration: none;
}
section.header .navbar-end nav a:hover {
  color: var(--nav-link-colour-hover);
}
/* the nav <ul> sits flush right; gap on the fluid unit so it tracks the design */
section.header .navbar-end nav ul {
  gap: calc(106 * var(--u));
  margin: 0;
  align-items: center;
}
section.header .navbar-end nav ul li { margin: 0; list-style: none; }

section.header .navbar-brand .navbar-item img {
  /* The logo SVG is an Affinity export carrying width="100%" height="100%". With
     width:auto/height:auto those percentages resolve against a parent with no definite
     size, so the image computed to 0x0. Giving it a definite height and the ratio from
     the SVG's own viewBox (0 0 889 97) makes it deterministic, and it still scales
     because --logo-max-height is on the fluid unit. */
  height: var(--logo-max-height);
  width: auto;
  aspect-ratio: 889 / 97;
  max-width: var(--logo-max-width);
}
/*
section.header .navbar-item:first-child {
    padding-left: 0;
}

section.header .navbar-item:last-child {
    padding-right: 0;
}*/

section.header .navbar-start > .navbar-item {
    margin-left: var(--nav-mobile-margin);
}

section.header .navbar-start > .navbar-item:first-child {
    padding-left: 0;
    margin-left: 0;
}

section.header nav > ul {
  gap: 2rem;
}

section.header nav > ul > li > a {
  position: relative;
}
/* The nav underline was a ::before pseudo-element, not text-decoration or a border,
   which is why setting text-decoration: none on the <a> had no effect. Kept as a
   hover-only reveal: width 0 at rest, animating in on hover.
   Change width to 100% below to bring the permanent underline back. */
section.header nav > ul > li > a:before {
/*  position: absolute;
  bottom: -6px;
  height: 1px;
  background-color: currentColor;
  content: '';
  width: 0;
  right: 0;
  transition: width .35s cubic-bezier(.2,.8,.2,1);
  pointer-events: none;*/
}
section.header nav > ul > li > a:hover:before { width: 100%; }
/* Removed: `section.header nav > ul > li:hover > a:before { width: 0 }`, which sat here and
   cancelled the reveal above. Identical specificity (0,2,6) and later in source order, and
   :hover propagates from the <a> to its parent <li>, so it matched whenever the reveal did
   and always won — the underline was unreachable in every state. Confirmed against the live
   computed style before deleting: ::before width stayed 0px while the link was hovered. */

section.header nav .navbar-dropdown {
  top: calc(100% + 0.8rem);
  margin-top: 0;
  min-width: min(23rem, calc(100vw - 2rem));
  padding: 0;
  overflow: visible;
  background: rgba(14, 24, 32, 0.98);
  border: 1px solid rgba(255, 255, 255, 0.08);
  border-top: 2px solid var(--primary-colour);
  border-radius: 0;
  box-shadow: 0 18px 45px rgba(0, 0, 0, 0.35);
  backdrop-filter: blur(12px);
}

/* Open/close transition. Bulma's desktop rules toggle the panel with `display: none` -> `block`
   (bulma.css, search "Simple dropdown with width control"), and display cannot animate, so the
   panel snapped in. Here it stays display:block at rest — position:absolute, so it costs no layout
   — and is hidden with visibility + opacity + a 6px lift instead, all of which do animate.
   `visibility` is what keeps a hidden panel out of the tab order and off the pointer, the way
   display:none did; it is delayed on the way OUT so the fade completes before the panel vanishes,
   and instant on the way IN so the fade is visible. The trigger's triangle moves and fades with it —
   its rules sit AFTER the triangle's own block below, where source order lets them override its
   transform. Desktop only: below 1024px the nav is mmenu (main.js), not this panel.
   Specificity: the hidden rule at (0,3,3) beats Bulma's base at (0,1,0); the shown rule at (0,4,3)
   beats Bulma's :hover rule at (0,4,0), which also sets an identity transform and pointer-events. */
@media screen and (min-width: 1024px) {
  section.header nav > ul > li.has-dropdown > .navbar-dropdown {
    display: block;
    visibility: hidden;
    opacity: 0;
    transform: translateY(-6px);
    pointer-events: none;
    transition:
      opacity .22s ease,
      transform .28s cubic-bezier(.2, .8, .2, 1),
      visibility 0s linear .28s;
  }
  section.header nav > ul > li.has-dropdown:hover > .navbar-dropdown,
  section.header nav > ul > li.has-dropdown:focus-within > .navbar-dropdown,
  section.header nav > ul > li.has-dropdown.is-active > .navbar-dropdown {
    visibility: visible;
    opacity: 1;
    transform: translateY(0);
    pointer-events: auto;
    transition:
      opacity .22s ease,
      transform .28s cubic-bezier(.2, .8, .2, 1),
      visibility 0s;
  }
  @media (prefers-reduced-motion: reduce) {
    section.header nav > ul > li.has-dropdown > .navbar-dropdown {
      transition: none;
    }
  }
}

/* Pointer triangle. It lives on the TRIGGER LINK, not on the panel. Bulma right-aligns a
   navbar-end dropdown to its <li> (`left: auto; right: 0`), so the previous `left: 6.6rem`
   measured from the panel's left edge put the triangle ~165px left of the "Products" label
   (1265px viewport: label centre x=896, triangle x=731). Centred on the link it follows
   whatever label a dropdown item has. The link is already `position: relative` (rule above).
   Geometry: the panel starts at 100% + 0.8rem below the <li>; the triangle is 0.6rem tall and
   starts at 100% + 0.2rem, plus 2px so it overlaps the panel's 2px primary border-top with no
   seam. Shown only while the dropdown is open (Bulma opens it on li:hover / li.is-active).
   The `> li > a:before` underline rules above are inert (no content) but their hover
   `width: 100%` would stretch this; this selector out-specifies them, (0,3,6) vs (0,2,6). */
section.header nav > ul > li.has-dropdown > .navbar-link::before {
  content: '';
  position: absolute;
  left: 50%;
  top: calc(100% + 0.2rem);
  width: 37px;
  height: calc(0.6rem + 2px);
  transform: translateX(-50%);
  background: var(--primary-colour);
  clip-path: polygon(50% 0, 0 100%, 100% 100%);
  opacity: 0;
  pointer-events: none;
  z-index: 21;
}
section.header nav > ul > li.has-dropdown:hover > .navbar-link::before,
section.header nav > ul > li.has-dropdown:focus-within > .navbar-link::before,
section.header nav > ul > li.has-dropdown.is-active > .navbar-link::before {
  opacity: 1;
}

/* The triangle travels WITH the panel. The panel (rules above, search "Open/close transition")
   fades in while easing down 6px; a triangle that only faded, fixed in place, read as a separate
   object arriving early. Same 6px, same curve, same durations, so the two move as one piece. This
   block sits after the triangle's base and shown rules ON PURPOSE: it shares their (0,3,6) /
   (0,4,6) specificity and needs source order to override the base `transform: translateX(-50%)`.
   The X centring is repeated in both states because `transform` is one property — dropping it
   would shift the triangle to the link's left edge. */
@media screen and (min-width: 1024px) {
  section.header nav > ul > li.has-dropdown > .navbar-link::before {
    transform: translateX(-50%) translateY(-6px);
    transition:
      opacity .22s ease,
      transform .28s cubic-bezier(.2, .8, .2, 1);
  }
  section.header nav > ul > li.has-dropdown:hover > .navbar-link::before,
  section.header nav > ul > li.has-dropdown:focus-within > .navbar-link::before,
  section.header nav > ul > li.has-dropdown.is-active > .navbar-link::before {
    transform: translateX(-50%) translateY(0);
  }
  @media (prefers-reduced-motion: reduce) {
    section.header nav > ul > li.has-dropdown > .navbar-link::before {
      transition: none;
    }
  }
}

section.header nav .navbar-dropdown::after {
  content: '';
  position: absolute;
  top: -1rem;
  left: 0;
  right: 0;
  height: 1rem;
  background: transparent;
}

section.header nav .navbar-dropdown > li {
  margin: 0;
}

section.header nav .navbar-dropdown > li + li {
  border-top: 1px solid rgba(255, 255, 255, 0.06);
}

section.header nav .navbar-dropdown > li > .navbar-item {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  width: 100%;
  padding: 1rem 1.15rem;
  white-space: normal;
  background: transparent;
  color: #f5f0e8 !important;
  /* Label typography lived on an inner .nav-item__label span while dropdown rows
     could carry a subtitle. That feature was removed 7 Sep 2026 (old-CMS leftover),
     so the anchor is the label and the type styles sit here. */
  font-family: var(--heading-font), serif;
  font-size: 1.1rem;
  font-weight: var(--heading-weight);
  letter-spacing: 0.08em;
  line-height: 1.1;
  text-transform: uppercase;
}

section.header nav .navbar-dropdown > li > .navbar-item:hover,
section.header nav .navbar-dropdown > li > .navbar-item.is-active {
  background: rgba(255, 255, 255, 0.04);
}

section.header nav .navbar-dropdown > li > .navbar-item::after {
  content: '\2192';
  flex: 0 0 auto;
  color: var(--primary-colour);
  font-size: 1.1rem;
  line-height: 1;
}
section.header nav .navbar-dropdown > li > .navbar-item[href*="environment"]::after {
  color: var(--brand-green);
}
section.header nav .navbar-dropdown > li > .navbar-item[href*="design"]::after {
  color: var(--brand-blue);
}

section.header nav > ul > a.navbar-item:first-child,
section.header nav > ul > .navbar-item:first-child > .navbar-link {
  /*padding-left: 0;*/
}
section.header nav > ul > a.navbar-item:last-child,
section.header nav > ul > .navbar-item:last-child > .navbar-link {
  /*padding-right: 0;*/
}

/* Mobile navigation visibility */
.navbar-item.mobile_only,
section.header .navbar-link.mobile_only,
section.header a.navbar-item.mobile_only {
    display: none;
}
/* buildMenu() puts a plain item's class on the <a>, so hiding the link alone leaves its empty <li>
   in the flex row, and every empty slot still takes the nav's 106u gap -- the four mobile-only
   footer links added to the main menu on 5 Oct pushed the visible links 216px left. Hide the
   slot. The phone menu (mmenu) is unaffected: main.js rebuilds it from a copy with classes
   stripped. */
section.header nav li:has(> .mobile_only) {
    display: none;
}

.navlink {
  display: none;
}

/* Mobile menu */
#mmenu > .navbar-item {
  margin-left: 12px;
}

.navbar-burger {
  flex-direction: column;
  justify-content: space-between;
  width: 30px;
  height: 21px;
  background: none !important;
  flex-shrink: 0;
}

.navbar-burger span {
  width: 100%;
  position: static;
}

/* Mobile menu styling */
.mm-menu {
  background-color: var(--dark-colour);
}

.mm-menu .mm-listview > li > a {
  font-size: 1.2rem;
  color: var(--dark-colour-contrast);
  padding: 12px 10px 12px 17px;
}

.mm-menu .mm-btn:after,
.mm-menu .mm-btn:before,
.mm-menu .mm-listview > li .mm-next:after,
.mm-menu .mm-listview,
.mm-navbar {
  border-color: rgb(255 255 255 / 30%);
}

.mm-menu .mm-navbar a,
.mm-menu .mm-navbar > * {
  color: rgb(255 255 255 / 30%);
}

.mm-menu .mm-listview > li > a.mm-next {
  left: 0;
  width: 100%;
}

/* ==========================================================================
   IMAGES & MEDIA
   ========================================================================== */

img.sizer {
  visibility: hidden;
}

/* Image sizing utilities */
.image[class*="fixed-"] {
  width: 100%;
  overflow: hidden;
}

.image[class*="fixed-"] img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* Fixed image heights, in DESIGN UNITS so they scale with the fluid canvas like every other
   length. They were hardcoded px — the one part of the layout that ignored the canvas, so a
   "Fixed Medium" was proportionally much taller at 1200px than at 1900px.
   Converted at the 2000px scaleCap, so each renders the SAME size it always did at the cap and
   shrinks proportionally below it: 40/60/90/150/300/500/900px -> 56/84/126/210/421/702/1263u.
   CONSEQUENCE: existing content DOES change below 2000px. A Fixed Medium is still 300px at the
   cap but 216px in a 1440px window where it used to stay 300px. That is the intent, but it
   visibly shortens existing fixed-height images on smaller screens.
   Mirrored in cms/assets/css/style.css against --builder-u — keep the two in step. */
.image.is-fixed-xtiny {
  height: calc(67 * var(--u));
}

.image.is-fixed-tiny {
  height: calc(84 * var(--u));
}

.image.is-fixed-xsmall {
  height: calc(126 * var(--u));
}

.image.is-fixed-small {
  height: calc(210 * var(--u));
}

.image.is-fixed-medium {
  height: calc(421 * var(--u));
}
.image.is-fixed-large {
  height: calc(702 * var(--u));
}
.image.is-fixed-xlarge {
  height: calc(1263 * var(--u));
}

/* CUSTOM IMAGE RATIO. The element twin of the block settings modal's "Exact ratio", declared as
   $elementImageRatioField in cms/_includes/_config/elements.php and offered on every
   image-bearing element type. Mirrored in cms/assets/css/style.css against the builder card --
   KEEP THE TWO IN STEP.

   TWO KEYS, ONE OF THEM A SENTINEL. Image Height = Custom Ratio stores `is-custom-ratio`, which
   _image() puts on the figure as a class -- a class no rule matches, on purpose -- and emits as
   --element-height. The number arrives separately as --element-height_ratio. So a
   custom ratio has no fixed height and no Bulma `is-16by9`-style padding-top hack to fight, and
   `aspect-ratio` here is the only thing sizing the box. That is why this feature needed no PHP
   and no JS at all, where the BLOCK aspect ratio needs a sentinel swap in all three emitters:
   there the value is a calc operand, here it is a class name that simply matches nothing.

   THE FALLBACK IS `auto`, i.e. the initial value, so Custom Ratio selected with no number typed
   yet leaves the image at its natural height. Anything else would snap it to a shape nobody
   chose, and the field is revealed by a `visible_if` at the moment the sentinel is picked, so
   that gap is a real state an editor passes through.

   width/height/object-fit on the img follow `.image[class*="fixed-"] img` above rather than a
   second idiom. object-fit remains overridable by --element-fit, whose rules carry !important. */
.element[style*="--element-height: is-custom-ratio"] .image {
  aspect-ratio: var(--element-height_ratio, auto);
  height: auto;
  width: 100%;
  overflow: hidden;
}

.element[style*="--element-height: is-custom-ratio"] .image img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.element[style*="--element-fit: is-contain"] .image img {
  object-fit: contain !important;
}
.element[style*="--element-fit: is-cover"] .image img {
  object-fit: cover !important;
}

/* Image effects */
section .zoom {
  transition: transform cubic-bezier(0.22, 0.61, 0.36, 1) 0.9s;
}

section .zoom:hover {
  transform: scale(1.1);
}

/* Video container */
.video-container {
  margin: 0;
  width: 100%;
  height: 0;
  padding-top: 56.25%;
  background-color: #ccc;
  position: relative;
}

.video-container iframe {
  width: 100%;
  height: 100%;
  position: absolute;
  top: 0;
  left: 0;
}

/* ==========================================================================
   SECTION LAYOUTS
   ========================================================================== */

section.section {
  /* Base section styles */
}

section.maintenance {
  width: 100vw;
  height: 100vh;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--dark-colour);
}

/* Background sections */
section.has_background {
  position: relative;
}

section.has_background > .container {
  position: relative;
  z-index: 30;
}

section.has_background .background {
  position: absolute;
  top: 0;
  left: 0;
  bottom: 0;
  right: 0;
  object-fit: cover;
  object-position: center;
  width: 100%;
  height: 100%;
}

/* Shadow effects */
section.shadow_top {
  box-shadow: inset 0 10px 50px 0 rgb(0 0 0 / 4%);
}

section.shadow_bottom {
  box-shadow: inset 0 -10px 50px 0 rgb(0 0 0 / 4%);
}

/* Border effects */
section.border_top {
  border-top: 1px solid hsla(0, 0%, 100%, 0.1);
}

section.border_bottom {
  border-bottom: 1px solid hsla(0, 0%, 100%, 0.1);
}

/* Block sections */
section.block_type_block {
  padding: 0 !important;
  background: none !important;
}

/* Sticky text */
section.sticky_text .columns {
  align-items: flex-start !important;
  justify-content: space-between !important;
}

section.sticky_text .column-content {
  position: sticky;
  top: 0;
  padding-top: 3rem;
}

/* ==========================================================================
   HERO SECTIONS
   ========================================================================== */

section.hero {
  background-size: cover;
  background-position: center;
  position: relative;
}

section.hero .container {
  position: relative;
  z-index: 10;
}

section.hero .hero-body {
  background: linear-gradient(180deg, #2f272f1c 0%, #2f272f00 32%, #2f272f00 100%);
}

#home section.hero {
  background-position: center bottom;
}

#home section.hero .hero-body {
  background: linear-gradient(180deg, #091615c7 0%, #0916159e 32%, #0916153b 100%);
  padding-top: 11rem;
}

section.hero .title.is-1,
section.hero h1 {
  font-size: 60pt;
}

section.hero h2:not(:last-child),
section.hero h1:not(:last-child) {
  /* margin-bottom: 0.1em; */
}

section.hero .button {
  margin-top: 2px;
}

section.hero .button + .button {
  margin-left: 12px;
}

#home section.hero .button {
  margin-top: 8px;
}

#home section.hero p {
  margin-bottom: 1rem !important;
}

#home section.hero p:last-child {
  margin-bottom: 0 !important;
}

/* Hero video */
section.hero .video {
  width: 0;
  height: 0;
}

section.hero .video .vjs-loading-spinner .vjs-control-text {
  display: none;
}

section.hero video {
  position: absolute;
  top: 0;
  left: 0;
  bottom: 0;
  right: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* Scroll indicator */
section.hero .scroll-me {
  position: absolute;
  bottom: 1rem;
  z-index: 10;
  color: var(--body-colour);
  left: 0;
  right: 0;
  text-align: center;
  font-size: 2rem;
  display: none;
}

#home section.hero .scroll-me {
  display: block;
}

/* ==========================================================================
   CONTENT BLOCKS
   ========================================================================== */

/* Images in content */
/* Width scale for images placed inside wysiwyg content. The editor used to leave them at
   whatever pixel width TinyMCE's drag-resize baked in — measured live, a logo pinned at
   789px while the container grew x1.38 between 1440 and 1985, and its size relative to body
   copy swung from 87.7x at 390px down to 34.6x at 2545px. That 789 was never a design value:
   the SVG is an Affinity export with width="100%" and viewBox="0 0 889 97", so it has a ratio
   but no intrinsic size, and TinyMCE had simply measured the CMS editor iframe.
   Four steps, expressed as fractions of the 2440.6-unit container in DESIGN UNITS, not
   percentages. Units matter above the 2000px cap: a percentage "half" inside a full-bleed
   block keeps growing while --u, the container and all type are frozen, which is precisely
   the image-vs-type divergence the fluid canvas exists to prevent. In units it freezes with
   everything else.
   The width sits on a class carried by the img, never on a bare `.content img` selector —
   that would be (0,1,2) and would beat Bulma's `.image img { width: 100% }` (0,1,1),
   collapsing the real .element-image figures. No !important either: the footer logo lives
   inside a .content wrapper and survives on specificity alone.
   Bulma's img { max-width: 100% } still clamps these inside a narrow column, which is the
   wanted behaviour — the step is an intent, not a floor.
   Derived from --container-fluid rather than restating its number, so retuning
   DESIGN_CANVAS['designContainer'] moves these with it. An earlier version hardcoded 2440.6
   and would have silently drifted the moment that token changed. */
.content img.img-w-full       { width: var(--container-fluid);             height: auto; }
.content img.img-w-two-thirds { width: calc(var(--container-fluid) * 2 / 3); height: auto; }
.content img.img-w-half       { width: calc(var(--container-fluid) / 2);     height: auto; }
.content img.img-w-third      { width: calc(var(--container-fluid) / 3);     height: auto; }

/* Exact width, in design units. The four steps above cover the common cases; this is the
   escape hatch for the ones that have to land on a specific number from the Affinity file.
   Because the fluid canvas maps the design's 2806.4-unit canvas onto the viewport, a design
   number IS a CSS number: --img-w:889 renders at exactly the width the client drew, at every
   viewport, and freezes with everything else above the scale cap.
   Set from the editor's "Image width" context toolbar (see admin.js), not by hand.
   Placed AFTER the step classes deliberately — [style*="--img-w"] and .img-w-full are both
   (0,2,1), so this only takes precedence on source order. Measured: with the rule above the
   classes it lost and the explicit number was ignored. Do not move it back up. */
.content img[style*="--img-w"] {
  width: calc(var(--img-w) * var(--u));
  height: auto;
}

section:not(.plain_image) .content img,
section .block_image {
  background-size: cover;
  background-position: center;
  background-repeat: no-repeat;
  border-radius: var(--border-radius);
  overflow: hidden;
}

section .block_image:not(.show_img) img {
  visibility: hidden;
  background-size: cover;
  background-position: center;
  display: block;
}

section .block_image.object-fit:not(.show_img) img {
  visibility: visible;
  object-fit: cover;
  height: 100%;
}

section .gallery_image {
  background-size: cover;
  background-position: center;
  background-repeat: no-repeat;
}

/* Big image layouts */
section.big_image {
  position: relative;
}

section.big_image .container {
  position: static;
}

section.big_image .column-image {
  min-height: 350px;
}

section.big_image .column-image .block_image {
  position: absolute;
  padding: 0;
  top: 0;
  bottom: 0;
}

section.big_image .column-image.is-3 .block_image { width: 25%; }
section.big_image .column-image.is-4 .block_image { width: 33.33333%; }
section.big_image .column-image.is-5 .block_image { width: 41.66667%; }
section.big_image .column-image.is-6 .block_image { width: 50%; }
section.big_image .column-image.is-7 .block_image { width: 58.33333%; }

section.block_type_image_text.big_image .column-image .block_image {
  left: 0;
}

section.block_type_text_image.big_image .column-image .block_image {
  right: 0;
}

/* About blocks */
section.about_block .column-image {
  padding-top: 0;
}

/* Gallery blocks */
section.block_type_gallery .gallery {
  display: flex;
  flex-wrap: wrap;
  gap: 3%;
  align-items: center;
  justify-content: center;
}

section.block_type_gallery .gallery .gallery_image {
  width: 22.7%;
  background-size: contain;
  background-repeat: no-repeat;
  background-position: center;
  margin: 0 0 2rem 0;
  opacity: 1;
}

section.block_type_gallery .gallery .image {
  border-radius: var(--border-radius);
  overflow: hidden;
}

section.block_type_gallery .gallery .image img {
  display: block;
}

/* Thumbnails gallery â€” clickable images */
.gallery-thumbnails .gallery-thumb-link {
    display: block;
    cursor: zoom-in;
}
.gallery-thumbnails .gallery-thumb-link .image {
    border-radius: var(--border-radius);
    overflow: hidden;
    transition: opacity 0.2s;
}
.gallery-thumbnails .gallery-thumb-link:hover .image {
    opacity: 0.85;
}

/* Lightbox */
.gallery-lightbox {
    position: fixed;
    inset: 0;
    z-index: 9999;
    display: flex;
    align-items: center;
    justify-content: center;
}
.gallery-lightbox[hidden] { display: none; }

.gallery-lightbox__backdrop {
    position: absolute;
    inset: 0;
    background: rgba(0, 0, 0, 0.92);
}
.gallery-lightbox__frame {
    position: relative;
    z-index: 1;
    max-width: 90vw;
    max-height: 90vh;
    display: flex;
    align-items: center;
    justify-content: center;
}
.gallery-lightbox__img {
    max-width: 90vw;
    max-height: 90vh;
    object-fit: contain;
    border-radius: 4px;
    display: block;
}
.gallery-lightbox__close,
.gallery-lightbox__prev,
.gallery-lightbox__next {
    position: fixed;
    z-index: 2;
    background: none;
    border: none;
    color: #fff;
    cursor: pointer;
    font-size: 2.5rem;
    line-height: 1;
    padding: 0.5rem;
    opacity: 0.8;
    transition: opacity 0.15s;
}
.gallery-lightbox__close,
.gallery-lightbox__prev,
.gallery-lightbox__next { opacity: 0.8; }
.gallery-lightbox__close:hover,
.gallery-lightbox__prev:hover,
.gallery-lightbox__next:hover { opacity: 1; }
.gallery-lightbox__close {
    top: 1rem;
    right: 1.25rem;
    font-size: 2rem;
}
.gallery-lightbox__prev {
    left: 1rem;
    top: 50%;
    transform: translateY(-50%);
    font-size: 3rem;
}
.gallery-lightbox__next {
    right: 1rem;
    top: 50%;
    transform: translateY(-50%);
    font-size: 3rem;
}

/* Project slider captions */
.project-slide-caption {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 2.6rem;
  text-align: center;
  pointer-events: none;
}
.project-slide-caption span {
  display: inline-block;
  font-size: 0.95rem;
  color: #fff;
  padding: 0.45rem 0.75rem;
  background: rgba(0,0,0,0.35);
  border-radius: var(--border-radius, 10px);
  max-width: calc(100vw - 80px);
}

/* CTA blocks */
section.block_type_cta .columns {
  row-gap: 0.5rem;
}

section.block_type_cta .cta {
  background: #ffffff;
  display: block;
  border-radius: var(--border-radius);
  overflow: hidden;
  height: 100%;
}

section.block_type_cta .cta .block_image {
  border-bottom-left-radius: 0;
  border-bottom-right-radius: 0;
}

/* ==========================================================================
   ARTICLE & BLOG CONTENT
   ========================================================================== */

section.editorial .container {
  max-width: 860px !important;
}

/* Article hero */
section.block_type_article_hero {
  text-align: center;
}

section.block_type_article_hero h1,
section.block_type_article_hero h2,
section.block_type_article_hero p {
  color: var(--primary-colour-contrast);
}

/* Blog hero with search */
section.block_type_blog_hero .search {
  position: relative;
  margin-top: -10px;
}

section.block_type_blog_hero .search .button {
  margin: 0;
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  height: auto;
  border: none;
  background: none;
  padding: 0;
  width: 48px;
}

section.block_type_blog_hero .search input {
  background: none;
  border: none;
  border-bottom: 2px solid #fff;
  border-radius: 0;
  color: var(--body-colour);
}

section.block_type_blog_hero .search input:active,
section.block_type_blog_hero .search input:focus {
  border-color: var(--primary-colour);
}

section.block_type_blog_hero .search input::-webkit-input-placeholder,
section.block_type_blog_hero .search input:-moz-placeholder,
section.block_type_blog_hero input::-moz-placeholder,
section.block_type_blog_hero input:-ms-input-placeholder {
  color: rgba(255, 255, 255, 0.5);
  opacity: 1;
}

/* Article cards */
section .card.article {
  display: flex;
  flex-direction: column;
  height: 100%;
}

section .card.article .card-content {
  flex-grow: 1;
  display: flex;
  flex-direction: column;
}

section .card.article:hover {
  color: inherit;
}

section .card.article .image {
  overflow: hidden;
  border-radius: 0;
}

section .card.article .image img {
  object-fit: cover;
  transition: transform 0.2s ease;
}

section .card.article:hover img {
  transform: scale(1.06);
}

section .card.article .content {
  font-size: 0.9em;
  margin-top: auto;
}

section .card.article .content .arrow {
  color: var(--body-colour);
}

/* Listings */
section .listing.listing-card,
section .listing.listing-card .card {
  height: 100%;
}
section .listing.listing-service,
section .listing.listing-service .card {
  height: 100%;
}
section .listing.listing-service .card {
  background: var(--body-background);
  border: 5px solid var(--listing-service-accent, var(--primary-colour));
  display: flex;
  flex-direction: column;
  overflow: hidden;
}
section .listing.listing-service .listing-service__content {
  flex: 1 1 auto;
}
section .listing.listing-service .listing-service__graphic {
  flex: 0 0 auto;
  color: var(--listing-service-accent, var(--primary-colour));
  line-height: 0;
  isolation: isolate;
}
section .listing.listing-service .listing-service__graphic img,
section .listing.listing-service .listing-service__graphic svg {
  display: block;
  width: 100%;
  height: auto;
}
section .listing.listing-service .image {
  border-bottom-left-radius: 0;
  border-bottom-right-radius: 0;
}
section .listing.listing-service .title,
section .listing.listing-service h1,
section .listing.listing-service h2,
section .listing.listing-service h3,
section .listing.listing-service h4,
section .listing.listing-service h5,
section .listing.listing-service h6 {
  color: var(--listing-service-accent, var(--primary-colour));
}
section .listing.listing-card .image {
  border-bottom-left-radius: 0;
  border-bottom-right-radius: 0;
}
section .listing.listing-icon {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
}
section .listing.listing-icon .listing-icon__media {
  width: 100%;
  /* max-width: 96px; */
  margin-left: auto;
  margin-right: auto;
}
section .listing.listing-icon .listing-icon__media .image {
  display: block;
  width: 100%;
}
section .listing.listing-icon .listing-icon__media img {
  width: 100%;
  height: 100%;
  object-fit: contain;
}
section .listing.listing-icon .content {
  margin-bottom: 0;
  text-wrap: balance;
}
/* Whole-card link (icon.php, a Button Link set). Looks exactly like the static card; the title
   underlines on hover and the card gets a focus ring, so it still reads as interactive. */
section a.listing.listing-icon--link,
section a.listing.listing-icon--link:hover {
  color: inherit;
  text-decoration: none;
}
section a.listing.listing-icon--link .content p {
  color: inherit;
}
section a.listing.listing-icon--link:hover h5 {
  text-decoration: underline;
  text-underline-offset: .2em;
}
section a.listing.listing-icon--link:focus-visible {
  outline: 2px solid currentColor;
  outline-offset: 8px;
}

/* Blog Article Listings */
section .listing.listing-article,
section .listing.listing-article .card {
  height: 100%;
}
section .listing.listing-article .image {
  border-bottom-left-radius: 0;
  border-bottom-right-radius: 0;
}
section .listing.listing-article .image:before {
  position: absolute;
  left: 0;
  height: 110px;
  right: 0;
  bottom: 0;
  content: '';
  background-image: linear-gradient(to top, var(--primary-colour), #ffffff00);
  z-index: 1;
}

section .listing.listing-overlay {
  position: relative;
  border-radius: var(--border-radius);
  overflow: hidden;
}
section .listing.listing-overlay .image-container {
  position: relative;
}
section .listing.listing-overlay .content-inner {
  position: relative;
  /* bottom: -68px; */
  transition: bottom .2s ease;
}
section .listing.listing-overlay:hover .content-inner {
  bottom: 0;
}
section .listing.listing-overlay .image-container:before {
  background: linear-gradient(360deg, black, transparent);
  position: absolute;
  inset: 0;
  top: 60%;
  content: '';
  z-index: 1;
  opacity: 0;
  /* border-radius: 0 50px 50px 50px; */
}
section .listing.listing-overlay .content {
  position: absolute;
  bottom: 2.1rem;
  left: 1.8rem;
  right: 1.5rem;
  z-index: 2;
}
section .listing.listing-overlay .content {
  color: white;
}
section .listing.listing-overlay .content p {
  /* font-weight: 600; */
}

/* ==========================================================================
   SLIDERS & CAROUSELS
   ========================================================================== */

section[class*="slider"] {
  overflow: hidden;
}

section .content-slider {
  /* overflow: hidden; */
}

section .content-slider .container {
  width: 760px;
  max-width: 100% !important;
}

section .content-slider .quote p {
  font-size: 1.2rem;
  font-weight: 300;
  color: var(--primary-colour-contrast);
}

section .content-slider .quote p:first-child:before {
  content: "\201C";
}

section .content-slider .quote p:last-child:after {
  content: "\201D";
}

section .content-slider .name {
  margin-top: 20px;
  color: var(--primary-colour-contrast);
  font-weight: 600;
}

section .content-slider .owl-dots {
  margin-top: 30px;
  margin-bottom: -10px;
}

section .content-slider .owl-theme .owl-stage-outer {
  overflow: visible;
}

section .content-slider .owl-theme .owl-dots .owl-dot span {
  background: var(--primary-colour-contrast);
  opacity: 0.2;
}

section .content-slider .owl-theme .owl-dots .owl-dot.active span,
section .content-slider .owl-theme .owl-dots .owl-dot:hover span {
  opacity: 1;
}

section .content-slider .owl-theme .owl-item {
  opacity: 0.35;
  transition: opacity 0.2s ease;
  text-align: center;
}

section .content-slider .owl-theme .owl-item.active {
  opacity: 1;
}

section .content-slider .testimonial_slide {
  border-radius: 10px;
  overflow: hidden;
}

section .content-slider .testimonial_slide .image {
  background-size: cover;
  background-position: center;
  border-radius: 0;
}

section .content-slider .testimonial_slide .details {
  min-height: 440px;
  background-color: var(--dark-colour);
  padding: 3rem !important;
  display: flex;
  align-items: flex-start;
  flex-direction: column;
  justify-content: center;
  text-align: left;
}

/* ==========================================================================
   TESTIMONIALS
   ========================================================================== */

section.testimonials [class*="ArrowControl__ArrowControlContainer"] {
  box-shadow: none !important;
}

section.testimonials [class*="Carousel__CarouselArrowControlContainer"] > * {
  background: none !important;
  fill: #ebeae4 !important;
}

section.testimonials [class*="Carousel__CarouselArrowControlContainer"]:first-child {
  left: -95px;
}

section.testimonials [class*="Carousel__CarouselArrowControlContainer"]:last-child {
  right: -95px;
}

section.testimonials [class*="ReviewAlignContainer__Container"] {
  min-height: 200px;
  justify-content: center;
}

/* ==========================================================================
   PAGINATION
   ========================================================================== */

.pagination {
  display: flex;
  padding-left: 0;
  margin: 20px 0;
  border-radius: 4px;
  justify-content: center;
}

.pagination > li {
  display: inline;
  margin: 3px 3px;
  border-radius: var(--border-radius);
  overflow: hidden;
}

.pagination > li > a,
.pagination > li > a:visited,
.pagination > li > span {
  position: relative;
  float: left;
  padding: 6px 12px;
  margin-left: -1px;
  line-height: 1.42857143;
  color: var(--body-colour);
  text-decoration: none;
  background-color: var(--light-colour);
  border: none;
  font-weight: 400;
  border-radius: 0;
}

.pagination > li:first-child > a,
.pagination > li:first-child > span {
  margin-left: 0;
}

.pagination > li > a:hover,
.pagination > li > span:hover,
.pagination > li > a:focus,
.pagination > li > span:focus {
  color: var(--light-colour-contrast);
  background-color: var(--light-colour-hover);
}

.pagination > .active > a,
.pagination > .active > a:visited,
.pagination > .active > span,
.pagination > .active > a:hover,
.pagination > .active > span:hover,
.pagination > .active > a:focus,
.pagination > .active > span:focus {
  z-index: 2;
  color: var(--primary-colour-contrast);
  cursor: default;
  background-color: var(--primary-colour);
  border-color: var(--primary-colour);
}

.pagination > .disabled > span,
.pagination > .disabled > span:hover,
.pagination > .disabled > span:focus,
.pagination > .disabled > a,
.pagination > .disabled > a:hover,
.pagination > .disabled > a:focus {
  color: #777;
  cursor: not-allowed;
  background-color: var(--light-colour);
  border-color: transparent;
}

/* Bulma pagination variant */
.pagination-link,
.pagination-next,
.pagination-previous {
  background-color: var(--light-colour);
  border-color: transparent;
  color: var(--light-colour-contrast);
}

.pagination-link:hover,
.pagination-next:hover,
.pagination-previous:hover,
.pagination-link:focus,
.pagination-next:focus,
.pagination-previous:focus {
  background-color: var(--light-colour-hover);
  border-color: transparent;
  color: var(--light-colour-contrast);
}

.pagination-link.is-current {
  background-color: var(--primary-colour);
  border-color: var(--primary-colour);
  color: var(--primary-colour-contrast);
}

.pagination-link[disabled],
.pagination-next[disabled],
.pagination-previous[disabled] {
  background-color: var(--light-colour);
  border-color: transparent;
}

/* Pagination sizes */
.pagination-lg > li > a,
.pagination-lg > li > span {
  padding: 10px 16px;
  font-size: 18px;
}

.pagination-lg > li:first-child > a,
.pagination-lg > li:first-child > span {
  border-top-left-radius: 6px;
  border-bottom-left-radius: 6px;
}

.pagination-lg > li:last-child > a,
.pagination-lg > li:last-child > span {
  border-top-right-radius: 6px;
  border-bottom-right-radius: 6px;
}

.pagination-sm > li > a,
.pagination-sm > li > span {
  padding: 5px 10px;
  font-size: 12px;
}

.pagination-sm > li:first-child > a,
.pagination-sm > li:first-child > span {
  border-top-left-radius: var(--border-radius);
  border-bottom-left-radius: var(--border-radius);
}

.pagination-sm > li:last-child > a,
.pagination-sm > li:last-child > span {
  border-top-right-radius: var(--border-radius);
  border-bottom-right-radius: var(--border-radius);
}

/* ==========================================================================
   LISTS & UTILITIES
   ========================================================================== */

section ul.ticks {
  list-style: none;
  margin-left: 0;
  display: flex;
  flex-wrap: wrap;
}

section ul.ticks li {
  position: relative;
  padding-left: 35px;
  margin-bottom: 16px;
  width: 49%;
  margin-top: 0;
}

section ul.ticks li:before {
  content: '';
  width: 24px;
  height: 24px;
  position: absolute;
  left: 0;
  top: 2px;
  background-color: var(--primary-colour);
  -webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 24 24' stroke='%23000'%3E%3Cpath stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z'%3E%3C/path%3E%3C/svg%3E");
  mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 24 24' stroke='%23000'%3E%3Cpath stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z'%3E%3C/path%3E%3C/svg%3E");
  -webkit-mask-size: contain;
  mask-size: contain;
  -webkit-mask-repeat: no-repeat;
  mask-repeat: no-repeat;
  -webkit-mask-position: center;
  mask-position: center;
}

/* ==========================================================================
   SOCIAL ELEMENTS
   ========================================================================== */

.socials a {
  width: 26px;
  height: 26px;
  border-radius: 50%;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: 1.2rem;
}

section.topbar .socials a {
  color: var(--primary-colour-contrast);
}

#contact-us section.block_type_text_form .socials {
  margin-top: 50px;
}

#contact-us section.block_type_text_form .socials a {
  color: var(--dark-colour-contrast) !important;
  background: var(--body-colour);
  width: 45px;
  height: 45px;
  display: inline-flex;
  border-radius: 50%;
  align-items: center;
  justify-content: center;
  padding: 1px 0 0 1px;
}

/* ==========================================================================
   CONTACT INFORMATION ELEMENT
   ========================================================================== */

.contact-information__columns {
  align-items: stretch;
}

.contact-information__item {
  display: flex;
  align-items: flex-start;
  gap: 1rem;
  height: 100%;
  padding: 1.25rem 1.4rem;
  border: 1px solid var(--grey-border);
  border-radius: var(--border-radius);
  background: var(--card-surface-on-white);
  color: var(--dark-colour);
  text-decoration: none;
  transition: transform 0.2s ease, box-shadow 0.2s ease, border-color 0.2s ease;
}

.contact-information__item--stacked {
  width: 100%;
}

.contact-information__item:hover {
  transform: translateY(-2px);
  /* border-color: var(--card-border-on-white); */
  /* box-shadow: 0 10px 25px rgba(14, 19, 25, 0.08); */
  color: var(--dark-colour);
}

.contact-information__icon {
  flex: 0 0 auto;
  width: 3rem;
  height: 3rem;
  border-radius: 50%;
  /*background: var(--primary-light-colour);*/
  background: #fff;
  color: var(--primary-colour);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: 1rem;
}

.contact-information__body {
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 0.15rem;
}

.contact-information__phone-group {
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
}

.contact-information__phone-entry {
  display: flex;
  flex-direction: column;
  gap: 0.1rem;
}

.contact-information__phone-entry-label {
  font-size: 0.72rem;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--grey-dark);
  opacity: 0.6;
}

.contact-information__phone-link {
  color: inherit;
  text-decoration: none;
  font-size: 1rem;
  font-weight: 600;
  line-height: 1.4;
}

.contact-information__phone-link:hover {
  color: var(--primary-colour);
  text-decoration: underline;
}

.contact-information__label {
  font-size: 0.72rem;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--grey-dark);
  opacity: 0.6;
}

.contact-information__value {
  font-size: 1rem;
  font-weight: 600;
  line-height: 1.5;
  word-break: break-word;
}

/* ==========================================================================
   MAP ELEMENT
   ========================================================================== */

.map-element {
  width: 100%;
}

.map-element__frame {
  position: relative;
  width: 100%;
  aspect-ratio: var(--map-aspect-ratio, 16 / 9);
  min-height: 320px;
  overflow: hidden;
  border-radius: var(--border-radius);
  border: 1px solid var(--grey-border);
  background: var(--grey-light-colour);
  box-shadow: 0 10px 30px rgba(14, 19, 25, 0.06);
}

.map-element__iframe {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  border: 0;
}

/* ==========================================================================
   FOOTER
   ========================================================================== */

section.footer {
  position: relative;
  background: var(--footer-background);
  color: var(--body-colour);

  --grey-border: rgb(0 0 0 / 12%);
}

section.footer .footer-top {
  display: none;
}

section.footer .footer-cols {
  display: grid !important;
  grid-template-columns: var(--footer-menu-grid-columns);
  gap: var(--footer-menu-grid-gap);
  align-items: start;
  justify-content: start;
}

section.footer .footer-cols .footer-col {
  padding-right: 0;
  width: auto;
  min-width: 0;
  max-width: none;
}

section.footer .footer-cols .footer-col.branding {
  display: block !important;
}

section.footer a {
  color: var(--footer-link-color);
}

section.footer a:hover {
  color: var(--footer-link-color-hover);
}

section.footer p {
  color: var(--dark-colour-contrast);
  font-size: 16px;
}

section.footer a.navbar-item,
section.footer .navbar-link {
  color: var(--footer-menu-link-color);
  font-family: var(--footer-menu-link-font);
  font-size: var(--footer-menu-link-font-size);
  margin-bottom: 0rem;
  font-weight: var(--footer-menu-link-font-weight);
  letter-spacing: var(--footer-menu-link-letter-spacing);
  line-height: var(--footer-menu-link-line-height);
}

section.footer .navbar-link:after,
section.footer .navbar-item .navbar-dropdown {
  display: none !important;
}

section.footer .navbar-item:hover {
  color: var(--footer-menu-link-color-hover) !important;
}

section.footer .navbar-link {
  padding-right: 1.5rem;
}

section.footer .footer-col.menu h4 {
  color: var(--footer-menu-heading-color);
  font-family: var(--footer-menu-heading-font);
  font-size: var(--footer-menu-heading-font-size);
  font-weight: var(--footer-menu-heading-font-weight);
  letter-spacing: var(--footer-menu-heading-letter-spacing);
  line-height: var(--footer-menu-heading-line-height);
  text-transform: uppercase;
}

section.footer .footer-col.menu ul {
  display: flex;
  flex-direction: column;
  gap: var(--footer-menu-gap);
}

section.footer .footer-col.menu li {
  margin: 0;
}

section.footer .footer-col.menu a {
  color: var(--footer-menu-link-color);
  font-family: var(--footer-menu-link-font);
  font-size: var(--footer-menu-link-font-size);
  font-weight: var(--footer-menu-link-font-weight);
  letter-spacing: var(--footer-menu-link-letter-spacing);
  line-height: var(--footer-menu-link-line-height);
  text-transform: none;
}

section.footer .footer-col.menu a:hover,
section.footer .footer-col.menu .navbar-item:hover,
section.footer .footer-col.menu .navbar-link:hover {
  color: var(--footer-menu-link-color-hover) !important;
}

section.footer .footer-col.contact h4 {
  color: var(--footer-menu-heading-color);
  font-family: var(--footer-menu-heading-font);
  font-size: var(--footer-menu-heading-font-size);
  font-weight: var(--footer-menu-heading-font-weight);
  letter-spacing: var(--footer-menu-heading-letter-spacing);
  line-height: var(--footer-menu-heading-line-height);
  text-transform: uppercase;
}

section.footer .footer-col.contact p,
section.footer .footer-col.contact a {
  color: var(--footer-menu-link-color);
  font-family: var(--footer-menu-link-font);
  font-size: var(--footer-menu-link-font-size);
  font-weight: var(--footer-menu-link-font-weight);
  letter-spacing: var(--footer-menu-link-letter-spacing);
  line-height: var(--footer-menu-link-line-height);
}

section.footer .footer-col.contact a:hover {
  color: var(--footer-menu-link-color-hover);
}

section.footer .footer-col.contact .socials {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  margin-top: 1.5rem;
  justify-content: flex-start;
}

section.footer .footer-col.contact .socials a {
  width: var(--footer-menu-contact-icon-size);
  height: var(--footer-menu-contact-icon-size);
  border-radius: 0;
  border: none;
  color: var(--footer-menu-link-color);
  transition: color .2s ease;
}

section.footer .footer-col.contact .socials a:hover {
  color: var(--footer-menu-link-color-hover);
}

section.footer .footer-col.contact .socials .icon {
  font-size: 30px;
}

section.footer .footer-top .logo {
  /*height: 100px;*/
}
section.footer .footer-top .logo img {
  width: 120px;
}
section.footer .footer-top .socials {
  display: flex;
  align-items: center;
  gap: 1rem;
}
section.footer .footer-top .socials a {
  width: 50px;
  height: 50px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border: 1px solid var(--grey-border);
  border-radius: 50%;
}

section.footer .footer-cols .footer-col.branding {
  /*margin-right: auto;*/
}
section.footer .footer-cols .footer-col {
  /*flex-shrink: 0;*/
  padding-right: var(--footer-menu-column-gap);
  /*min-width: 210px;*/
  /* max-width: 18%; */
  width: auto;
  /* flex-grow: 1; */
}

section.footer .footer-cols .footer-col:last-child {
  padding-right: 0;
}

section.footer .footer-col.branding {
  display: block !important;
}

section.footer .footer-col.branding h3 {
  font-weight: 400;
}
section.footer .footer-col.branding a.logo {
  display: block;
  /*height: 7rem;*/
}

section.footer .footer-col.branding a.logo img {
  max-height: 100%;
  width: auto;
  border-radius: 0;
}

section.footer .footer-col.branding .footer-branding-text {
  /* margin-top: 0.5rem; */
  color: var(--footer-link-color);
}

section.footer .footer-col.branding .footer-branding-text p {
  color: inherit;
}

section.footer .footer-col.branding .footer-branding-logos {
  gap: 0.85rem 1rem;
}

section.footer .footer-col.branding .footer-branding-logos__item {
  flex: 0 0 auto;
}

section.footer .footer-col.branding .footer-branding-logos .image {
  width: auto;
}

section.footer .footer-col.branding .footer-branding-logos .image img {
  object-fit: contain;
}

section.footer .footer_small_print_mobile {
  display: none;
  margin-top: 2rem;
  text-align: center;
}

section.footer .footer_small_print_mobile p {
  font-size: 12px;
  margin-bottom: 0.2rem;
}

section.footer .footer_small_print_mobile p:last-child {
  margin-bottom: 0;
}

section.footer .footer-col .copyright p {
  font-size: 10pt;
}

section.footer .footer-col.icons .google-reviews {
  height: 4rem;
  margin-bottom: 1.5rem;
}

section.footer .footer-col.icons .google-reviews img {
  max-height: 100%;
}

section.footer .footer-col .socials {
  display: flex;
  justify-content: center;
  gap: 1rem;
}

section.footer .badges {
  display: flex;
  gap: 1rem;
}
section.footer .badges img {
  max-height: 100px;
  border-radius: 0;
}

section.footer .footer-bottom p {
  font-size: 0.9rem;
}

/* ==========================================================================
   MODALS & NOTIFICATIONS
   ========================================================================== */

.msg {
  position: fixed;
  top: 30px;
  right: 30px;
  z-index: 100;
}

section.modal {
  background: transparent !important;
}

section.modal .container {
  width: 100%;
  max-width: none;
  flex: none;
  margin: 0;
  position: static;
}

section.modal h2 {
  font-size: 2.6rem;
}

.notification.is-sentModal {
  padding: 0 !important;
}

.notification.is-sentModal > button {
  display: none;
}

.is-sentModal .modal-content {
  width: 420px;
  max-width: calc(100% - 20px);
}

.is-sentModal .modal-content .box {
  border-radius: var(--border-radius);
}

/* ==========================================================================
   ANNOUNCEMENTS & BANNERS
   ========================================================================== */

.announcer p {
  margin-bottom: 0 !important;
  line-height: 1.3;
  font-size: 14px;
}

.announcer p a {
  color: var(--primary-colour-contrast);
}

.announcer ul li a {
  font-size: 14px;
}

.announcer .socials {
  position: relative;
  bottom: 0px;
}

/* ==========================================================================
   UTILITY CLASSES
   ========================================================================== */

.details .column:last-child {
  text-align: center;
}

.details .column:last-child img {
  margin: 0.6rem;
}

/* Contact form alignment */
#contact-us section.block_type_text_form .columns {
  align-items: flex-start !important;
}

/* Bulma-style border helpers */
.has-border {
  border: 1px solid var(--grey-border) !important;
}

.has-border-top {
  border-top: 1px solid var(--grey-border) !important;
}

.has-border-right {
  border-right: 1px solid var(--grey-border) !important;
}

.has-border-bottom {
  border-bottom: 1px solid var(--grey-border) !important;
}

.has-border-left {
  border-left: 1px solid var(--grey-border) !important;
}

.has-border-x {
  border-left: 1px solid var(--grey-border) !important;
  border-right: 1px solid var(--grey-border) !important;
}

.has-border-y {
  border-top: 1px solid var(--grey-border) !important;
  border-bottom: 1px solid var(--grey-border) !important;
}

section.section.block-item .card {
  --card-border-colour: var(--block-cardBorder, var(--card-border-default));
}

section.section.block-item .card .has-border,
section.section.block-item .card.has-border {
  border-color: var(--card-border-colour) !important;
}

section.section.block-item .card .has-border-top,
section.section.block-item .card.has-border-top {
  border-top-color: var(--card-border-colour) !important;
}

section.section.block-item .card .has-border-right,
section.section.block-item .card.has-border-right {
  border-right-color: var(--card-border-colour) !important;
}

section.section.block-item .card .has-border-bottom,
section.section.block-item .card.has-border-bottom {
  border-bottom-color: var(--card-border-colour) !important;
}

section.section.block-item .card .has-border-left,
section.section.block-item .card.has-border-left {
  border-left-color: var(--card-border-colour) !important;
}

section.section.block-item .card .has-border-x,
section.section.block-item .card.has-border-x {
  border-left-color: var(--card-border-colour) !important;
  border-right-color: var(--card-border-colour) !important;
}

section.section.block-item .card .has-border-y,
section.section.block-item .card.has-border-y {
  border-top-color: var(--card-border-colour) !important;
  border-bottom-color: var(--card-border-colour) !important;
}

.is-radiusless {
  border-radius: 0 !important;
}

.is-radiusless-top {
  border-top-left-radius: 0 !important;
  border-top-right-radius: 0 !important;
}

.is-radiusless-right {
  border-top-right-radius: 0 !important;
  border-bottom-right-radius: 0 !important;
}

.is-radiusless-bottom {
  border-bottom-left-radius: 0 !important;
  border-bottom-right-radius: 0 !important;
}

.is-radiusless-left {
  border-top-left-radius: 0 !important;
  border-bottom-left-radius: 0 !important;
}

.is-radiusless-top-left {
  border-top-left-radius: 0 !important;
}

.is-radiusless-top-right {
  border-top-right-radius: 0 !important;
}

.is-radiusless-bottom-left {
  border-bottom-left-radius: 0 !important;
}

.is-radiusless-bottom-right {
  border-bottom-right-radius: 0 !important;
}

@media screen and (min-width: 1024px) {
  .is-radiusless-desktop {
    border-radius: 0 !important;
  }

  .is-radiusless-top-desktop {
    border-top-left-radius: 0 !important;
    border-top-right-radius: 0 !important;
  }

  .is-radiusless-right-desktop {
    border-top-right-radius: 0 !important;
    border-bottom-right-radius: 0 !important;
  }

  .is-radiusless-bottom-desktop {
    border-bottom-left-radius: 0 !important;
    border-bottom-right-radius: 0 !important;
  }

  .is-radiusless-left-desktop {
    border-top-left-radius: 0 !important;
    border-bottom-left-radius: 0 !important;
  }
}

@media screen and (max-width: 1023px) {
  .is-radiusless-mobile {
    border-radius: 0 !important;
  }

  .is-radiusless-top-mobile {
    border-top-left-radius: 0 !important;
    border-top-right-radius: 0 !important;
  }

  .is-radiusless-right-mobile {
    border-top-right-radius: 0 !important;
    border-bottom-right-radius: 0 !important;
  }

  .is-radiusless-bottom-mobile {
    border-bottom-left-radius: 0 !important;
    border-bottom-right-radius: 0 !important;
  }

  .is-radiusless-left-mobile {
    border-top-left-radius: 0 !important;
    border-bottom-left-radius: 0 !important;
  }
}

/* ==========================================================================
   FAQ
   ========================================================================== */

.accordion-header {
    cursor: pointer;
    transition: background-color 0.3s ease;
    box-shadow: none;
}

.accordion-item {
  background-color: transparent;
  border-radius: 5px;
  overflow: hidden;
}
.card-header.accordion-header {
  /*background-color: #fff;*/
}
.accordion-header:hover .card-header-icon.accordion-toggle {
    /*background-color: rgba(0, 0, 0, 0.05);*/
    color: var(--secondary-colour);
}

.accordion-icon {
    transition: transform 0.3s ease;
}

.accordion-content {
    transition: all 0.3s ease;
    /*margin-top: 3px;*/
    background-color: rgba(255, 255, 255, 0.5);
    padding: 1rem 1.4rem;
}

.accordion-header .card-header-title {
    flex-grow: 1;
    padding: 1rem 1.4rem;
}

.accordion-toggle {
    background: none;
    border: none;
    cursor: pointer;
}

section .listing.listing-faq {
  margin-bottom: .5rem;
}
section .listing.listing-faq:last-child {
  margin-bottom: 0;
}

/* ==========================================================================
   COOKIE CONSENT
   ========================================================================== */

.cc-window.cc-floating,
.cc-window.cc-banner {
  background-color: var(--primary-colour);
  color: var(--primary-colour-contrast);
}

.cc-window.cc-floating .cc-btn,
.cc-window.cc-banner .cc-btn {
  color: var(--primary-colour-contrast);
  border-color: var(--primary-colour-contrast);
}

/* Cookie consent dark palette */
html .termsfeed-com---palette-dark .cc-nb-okagree,
html .termsfeed-com---palette-dark .cc-nb-reject {
  color: var(--dark-colour);
  background-color: var(--primary-colour);
}

html .termsfeed-com---palette-dark .cc-pc-head-lang select:focus {
  box-shadow: 0 0 0 2px var(--primary-colour);
}

html .termsfeed-com---palette-dark .cc-pc-head-close:active,
html .termsfeed-com---palette-dark .cc-pc-head-close:focus {
  border: 2px solid var(--primary-colour);
}

html .termsfeed-com---palette-dark .cc-cp-body-content-entry a:focus,
html .termsfeed-com---palette-dark .cc-cp-foot-byline a:focus {
  box-shadow: 0 0 0 2px var(--primary-colour);
}

html .termsfeed-com---palette-dark .cc-cp-foot-save {
  background: var(--primary-colour);
  color: var(--dark-colour);
}

/* ==========================================================================
   BLOCK SYSTEM (DYNAMIC SECTIONS)
   ========================================================================== */

section.section.block-item {
  --block-containerWidth: var(--default-containerWidth);
  --block-elementsGap: var(--default-elementsGap);
  --block-elementsGapPx: calc(var(--block-elementsGap) * var(--u));
  --block-outerGapTop: var(--default-outerGapTop);
  --block-outerGapTopPx: calc(var(--block-outerGapTop) * var(--u));
  --block-outerGapBottom: var(--default-outerGapBottom);
  --block-outerGapBottomPx: calc(var(--block-outerGapBottom) * var(--u));
  /* Was --default-backgroundColour, which is never defined: header.php emits
     --default-<key> from CSS_DEFAULTS and the key is `background`. The old name
     made this invalid at computed-value time, so every default block rendered
     transparent on the front end while the builder (cms style.css, which reads
     the correct name) showed it filled. Visually neutral to fix here, because
     CSS_DEFAULTS['background'] is the same #1F313C as --body-background. */
  --block-background: var(--default-background);
  /* Image opacity, restored with the background-image field. Stored 0-100 (CSS_DEFAULTS
     ['backgroundOpacity']), so it is multiplied into a percentage here rather than being
     stored as a 0-1 fraction — that keeps the CMS slider readable and matches what
     --default-backgroundOpacity has been emitting all along. */
  --block-backgroundOpacity: var(--default-backgroundOpacity);
  --block-backgroundOpacityPercent: calc(var(--block-backgroundOpacity) * 1%);
  /* --block-height removed: combined with overflow:hidden below it silently clipped
     any block whose content exceeded the set height. The design has no fixed-height
     sections. Removing the `height` declaration too, further down this rule. */
  /* Card theming, pinned. 213 lines of WCAG luminance maths in blocks.php compute these
     four values, and on this site they return 'light' for EVERY block — the designs are
     white/grey/black. Pinned here so that PHP can be deleted without cards flipping to
     dark navy. Also fixes blocks with settings '{}' (no style attribute at all), which
     previously fell through to --card-surface-default (#162631) and rendered dark cards
     on a white page while their neighbours rendered #EAE3DA. */
  --block-cardSurface: var(--card-surface-on-white);
  --block-cardBorder: var(--card-border-on-white);
  --block-cardText: var(--dark-colour);
  --block-cardTextMuted: var(--grey-dark);
  /* Consumed below on .block-columns but never declared, so for a block with no
     saved alignment both declarations were invalid at computed-value time and
     fell back to the initial `normal`. Declared explicitly to keep that result
     deterministic before per-device overrides get layered on top. */
  --block-verticalAlign: normal;
  --block-horizontalAlign: normal;

  position: relative;
  background-color: var(--block-background);
  padding-top: var(--block-outerGapTopPx);
  padding-bottom: var(--block-outerGapBottomPx);
  overflow: hidden;
}

/* Background image. Only two things were ever removed for it: this rule and the CMS field.
   The emitter already wraps the value in url() + prependCDN() (blocks.php:379), the save
   path is generic over [data-setting] (block-builder.js:1978), and the builder preview
   still reads settings['backgroundImage'] (block-builder.js:1930) — none of that needed
   restoring.
   Painted on a ::before rather than reviving the .block-background div, which stays
   deleted: that div existed to host background video, and video is off. Opacity applies to
   this layer alone, so --block-background shows through beneath the image; colour + opacity
   together ARE the scrim. Content clears both via .block-container's z-index: 10.
   The `none` fallback matters — without it a block with no image makes the whole
   declaration invalid at computed-value time. */
section.section.block-item::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 0;
  background-image: var(--block-backgroundImage, none);
  background-size: cover;
  background-position: center;
  background-repeat: no-repeat;
  opacity: var(--block-backgroundOpacityPercent);
  pointer-events: none;
}
/* Removed: two rules selecting `.blok-item` on `--blok-height`, an old typo'd
   prefix. render_block() emits class="section block-item" with --block-* vars, so
   these never matched anything. The intended 500px floor on 50vh/100vh blocks has
   therefore never applied — if it is still wanted, add it deliberately alongside
   the svh/dvh work rather than by correcting the spelling here, since that would
   silently change the height of every viewport-sized block. */



/* Bulma's .container is `width: var(--container-width); max-width: calc(100% - 40px)`.
   The max-width is what kept the header and footer pinned to a fixed width while
   everything else scaled. custom.css loads after bulma.css, so this wins on source order. */
.container {
  width: var(--container-fluid);
  max-width: none;
  margin-inline: auto;
}

section.section.block-item .block-container {
  /* Fluid canvas: a fixed proportion of the viewport, deliberately no max-width.
     A max-width would cap the container while type kept scaling, which is exactly
     what made images and text drift apart. */
  width: var(--container-fluid);
  max-width: none;
  margin-inline: auto;
  position: relative;
  z-index: 10;
  height: 100%;
}
/* ==========================================================================
   CONTAINER-WIDTH BLOCKS

   Under the fluid canvas the container is always a fixed PROPORTION of the window, so
   containerWidth stopped being a width long ago — it says WHERE THE SECTION'S EDGES ARE.
   Three values, and the thing that differs is what runs to the window edge:

     ""      section full width, CONTENT in the container   (default, no rule needed)
     100%    section full width, CONTENT edge to edge
     inner   SECTION in the container — its background stops there too

   `100%` is still the string "100%" rather than a word, because rows have stored it since
   before this was a toggle. */
section.section.block-item[style*="--block-containerWidth: 100%"] .block-container {
  width: 100%;
  max-width: none;
}

/* BOXED — A PAGE WITHIN THE PAGE. The only value that moves the SECTION rather than what is
   inside it, so the page background shows down both sides of a coloured or image block.
   Everything the section paints follows for free: background-color is on this element and the
   background image is its ::before at inset: 0.

   THE CONTENT NESTS, IT DOES NOT FILL. The container inside repeats the SAME PROPORTION of the
   boxed section that the page container is of the window, so the block is the whole canvas
   re-run at a smaller size: section 87.5713% of the window, content 87.5713% of that. The first
   cut of this filled the section instead and the result was body copy and headings butting
   straight up against the edge of the background image — which is the one thing a boxed block
   exists to avoid, since the box has a visible edge where a full-width section has none.

   Written from the tokens rather than as 87.5713% because the exactness matters below: the
   gutter it leaves and --bleed have to agree to the unit, and they only do if both come out of
   the same designContainer / designCanvas / designMargin identity (which HANDOFF records as
   load-bearing: designContainer + 2 x designMargin MUST equal designCanvas). Both resolve to
   152.72u here — (1 - 2457.6/2806.4) / 2 * 2457.6 and 2457.6/2806.4 * 174.4.

   --bleed IS RE-SCALED, NOT ZEROED, and it is deliberately one token rather than a list of
   overrides. Every bleed rule on the site is calc(±1 * var(--bleed)) — per-element bleed, the
   stack's media-only variant, the carousel's bleed mode, the carousel arrow offsets — so
   redefining the token at the section retargets all of them at once and any rule added later
   inherits it. Inside a boxed block "bleed to the edge" means the BOX's edge, not the window's:
   the section stops at the container, so the distance to run out to is the inner gutter, which
   is exactly the value above. Left at the page's own --bleed an element would land outside the
   section and be cut off by the overflow: hidden; zeroed, it would stop at the inner container
   and never reach the edge of the image at all. */
section.section.block-item[style*="--block-containerWidth: inner"] {
  width: var(--container-fluid);
  margin-inline: auto;
  --bleed: calc(var(--default-designContainer) / var(--default-designCanvas)
                * var(--default-designMargin) * var(--u));
}
section.section.block-item[style*="--block-containerWidth: inner"] .block-container {
  width: calc(var(--default-designContainer) / var(--default-designCanvas) * 100%);
  max-width: none;
}


/* Fixed-ratio blocks. This is what replaces the removed block `height` setting, which
   combined with the overflow:hidden above to silently clip any content taller than the set
   height. min-height is what makes the difference: it can only ever grow a box, so the used
   height is the ratio height OR the content height, whichever is larger. A ratio can shape a
   block but can never cut it off.
   Deliberately NOT `aspect-ratio`. That was tried first and measured failing: aspect-ratio
   sets the box height outright, so a block whose content was taller than the ratio SHRANK to
   the ratio and the overflow:hidden above clipped it — reintroducing the exact bug that got
   the old `height` setting removed. `min-height: fit-content` did not rescue it (Chrome
   resolves it to auto in the block axis). Verified live at 1280px: a 570px-tall block keeps
   588px under this rule, and clipped only under the aspect-ratio version.
   The divisor is parenthesised because the stored value is a ratio string: substituting
   "21 / 9" yields calc(100vw / (21 / 9)), which is a valid numeric division.
   Tracks 100vw rather than the capped min(100vw, scaleCap) used by --u: above the 2000px
   freeze the section still spans the window, so the shape should follow the real width or it
   would stop being the ratio it claims to be.
   Scoped by attribute rather than applied to every block: "Auto" stores an empty string and
   the emitter skips empty values, so no var is emitted and this never matches.
   Vertical Alignment is re-plumbed here rather than reused. .block-columns already applies
   align-items: var(--block-verticalAlign), but it never sees the extra space: it and
   .block-container are height:100%, and a percentage height against a parent whose SPECIFIED
   height is auto (the section's height comes from min-height) resolves to auto, so both
   collapse to content height and there is nothing to align within. Making the section itself
   a column flex box and handing --block-verticalAlign to justify-content puts the alignment
   on the axis that actually has the slack. Measured on a 542px block with 127px of content:
   normal -> 0px, center -> 208px, flex-end -> 415px from the block top. */
/* A BOXED block measures its ratio across the CONTAINER, not the window — it is only that wide,
   so 100vw would make a 16:9 box 14% too tall and the shape would not be the one chosen. Listed
   before the generic rule so the generic one wins by source order for every other block; this
   pair is (0,2,2) against (0,2,1), so it wins where it applies without needing to come last. */
section.section.block-item[style*="--block-containerWidth: inner"][style*="--block-aspectRatio"] {
  min-height: calc(var(--container-fluid) / (var(--block-aspectRatio)));
}
section.section.block-item[style*="--block-aspectRatio"] {
  min-height: calc(100vw / (var(--block-aspectRatio)));
  display: flex;
  flex-direction: column;
  justify-content: var(--block-verticalAlign);
}

/* TOP AND BOTTOM (space-between) on a ratio block. The rule above hands the alignment to
   justify-content on the section, which has ONE flex child -- .block-container -- so for
   space-between there is nothing to distribute and the content sat at the top (block 101 on
   /showcase/light-and-space, 9 Sep). Hand the slack down instead: grow the container and the row to
   the section's height with flex (NOT percentage height -- that is the trap recorded above), then
   let align-content spread the row's wrapped LINES, first row to the top, last to the bottom.
   align-items already receives space-between from .block-columns and rejects it, so items inside a
   line still stretch to equal height. Elements side by side are one line and do not move; that is
   the setting's documented limit, not a bug. */
section.section.block-item[style*="--block-aspectRatio"][style*="--block-verticalAlign: space-between"] > .block-container {
  flex: 1 1 auto;
  display: flex;
  flex-direction: column;
}
section.section.block-item[style*="--block-aspectRatio"][style*="--block-verticalAlign: space-between"] > .block-container > .block-columns {
  flex: 1 1 auto;
  height: auto;
  align-content: space-between;
}


/* ==========================================================================
   COMBINATION ("STACK") ELEMENTS: the internal gap between the stacked parts

   Four element types stack two or three parts inside ONE column, because the block grid cannot put
   content under a specific column -- see _includes/_functions/elements/_stack.php for why, and for
   the standing call to do row spanning on `.block-columns` instead.

   ONE CLASS, NOT A COMMA LIST. Every member carries `.element-stack` (element_stack_wrap() puts it
   there) alongside its own type class, so this rule and the two overrides further down cover the
   whole family and cannot drift between types. It used to be a comma-separated selector that grew
   by one line per element type, in three separate places.

   The internal gap is TWO half-gaps, deliberately. --block-elementsGapPx is the half-gap (63u by
   default) and two stacked sibling elements would show one bottom plus one top, so 2x is exactly
   what the same content would measure if it were two separate elements. That means splitting or
   combining an element never shifts the layout, and the block's own Element Gap setting still
   drives it, so an editor tuning the gap tunes this too.
   margin-top on the SECOND child rather than a `gap` on the wrapper: `gap` would also apply if
   only one part is populated, and element_stack_wrap() drops an empty part entirely.
   ========================================================================== */
section.section.block-item .element-stack > * + * {
  /*margin-top: calc(2 * var(--block-elementsGapPx));*/
  margin-top: calc(1.5 * var(--block-elementsGapPx));
}

/* Image + Icon List keeps its own default, and that is not an exception for its own sake: its
   image-to-list distance is a MEASURED value off the comp (100u -- see STACK ICON ROWS below)
   rather than a block-relative one, and it renders three-across on live product pages today. This
   preserves that exactly while still going through the family's mechanism. Specificity does the
   ordering: this is (0,4,1) so it beats the family default at (0,3,1), and the `--element-gap`
   override below is (0,5,1) so it beats this -- no !important anywhere. It is also why the type
   deliberately carries no Gap field: there is nothing an editor could set it to that the comp
   asked for, and the field would be overriding a measured value rather than a relative one. */
section.section.block-item .element-stack.element-icon-list > * + * {
  margin-top: calc(100 * var(--u));
}

/* Per-element bleed. The distance from the container edge to the viewport edge IS the design's
   side margin, so --bleed (designMargin * --u, vars.css:53) lands an element exactly on the edge.
   Verified live at a 1938px window: --bleed resolves to 119.5px, container 119.5..1803.5, and
   container right + bleed = 1923 = documentElement.clientWidth EXACTLY. Measured on b14 and b12,
   inner edges move 119.5 -> 0 on the left and 1803.5 -> 1923 on the right.

   THE NEGATIVE MARGIN GOES ON THE ELEMENT'S INNER CHILD, NOT ON THE .column.
   This replaces `.element.is-bleed-left/right/both`, which put it on the .column itself. That was
   wrong twice over: (1) a .column is a flex item with a fixed is-N width, so a negative margin
   shrinks its OUTER size rather than widening the box -- in a flex-start row it moves nothing at
   all, and it only appeared to work on b14 because that row computes to space-between, which
   redistributes the freed space; (2) it pushed the column's own border box 43px PAST the viewport
   edge. The inner child is a plain block with width:auto, so a negative margin genuinely grows it
   on that side. Verified justify-content-independent (tested space-between and normal) and the
   column boxes measured unchanged, so siblings never move.

   No gutter on the bleeding edge, by construction: the inner overflows past the .column's 63u
   padding, so the content reaches the edge with nothing between. The non-bleeding side keeps its
   gutter normally.

   Frozen at the scale cap, deliberately. --bleed is designMargin * --u and --u freezes above
   scaleCap (2000px), so above that the whole canvas is a fixed 2000px block centred in the window
   and a bleeding element lands on the CANVAS edge, not the physical window edge. That is the
   consistent choice -- container (2457.6u) + 2 x bleed (174.4u) = 2806.4u = the canvas, all
   freezing together. Do NOT "fix" this with a vw-based max(): it would make bleeding elements
   chase the window while every other length stayed put.

   Keyed on --element-bleed, which element_settings_to_css_vars() (_includes/_functions/elements.php:150)
   emits generically from the element's settings JSON, same idiom as
   [style*="--block-containerWidth: 100%"] above. Note the emitter writes "key: value" with the
   space, which is what these selectors match. Inert until the CMS field exists. */
section.section.block-item .element[style*="--element-bleed: left"]  > *:not(.element-stack),
section.section.block-item .element[style*="--element-bleed: both"]  > *:not(.element-stack) {
  margin-left: calc(-1 * var(--bleed));
}
section.section.block-item .element[style*="--element-bleed: right"] > *:not(.element-stack),
section.section.block-item .element[style*="--element-bleed: both"]  > *:not(.element-stack) {
  margin-right: calc(-1 * var(--bleed));
}

/* On a STACK element ONLY THE IMAGE BLEEDS. The design has the right-hand image running to the
   screen edge while its heading and body copy stay inside the container -- text at the screen edge
   would be unreadable, so this is the right default and there is deliberately no option to bleed
   the body. Only the two stack types that own an image offer the field at all (media_text and
   text_media_icons); on the others the var is never emitted, so these rules are inert.
   Hence the `:not(.element-stack)` above: without it the generic rule moves the composite wrapper
   and drags the body out with it, and adding this rule on top then bled the image TWICE
   (measured 2042.5px against a 1923px viewport).
   Measured with `bleed: right` on a half-width column: media 1152.2 -> 1923 = the viewport edge,
   media's left edge unmoved, body 1152.2 -> 1803.5 = the container edge, wrapper unmoved.
   `both` extends the media in both directions and still leaves the body alone. */
section.section.block-item .element[style*="--element-bleed: left"]  .element-stack__media,
section.section.block-item .element[style*="--element-bleed: both"]  .element-stack__media {
  margin-left: calc(-1 * var(--bleed));
}
section.section.block-item .element[style*="--element-bleed: right"] .element-stack__media,
section.section.block-item .element[style*="--element-bleed: both"]  .element-stack__media {
  margin-right: calc(-1 * var(--bleed));
}









section.section.block-item .block-columns {
  align-items: var(--block-verticalAlign);
  align-content: var(--block-verticalAlign);
  justify-content: var(--block-horizontalAlign);
  margin-top: calc(-1 * var(--block-elementsGapPx));
  margin-bottom: calc(-1 * var(--block-elementsGapPx));
  margin-left: calc(-1 * var(--block-elementsGapPx));
  margin-right: calc(-1 * var(--block-elementsGapPx));
  height: 100%;
}

section.section.block-item .block-columns > .column {
  padding: var(--block-elementsGapPx);
}

/* ==========================================================================
   BLOCK CAROUSEL — a block SETTING, not a new section type.
   Everything hangs off one inline custom property, --block-carousel, written
   into the section's style attribute by block_settings_to_css_vars()
   (_includes/_functions/blocks.php:353). Values: absent = off, `on`, `bleed`.

   NO MARKUP CONTRACT, which is the whole reason this is viable as a setting.
   render_block() (blocks.php:85-91) already emits .block-columns (which becomes
   the scrollport) and .column (which become the slides). An earlier review
   rejected a block-level carousel because Splide demands
   .splide > .splide__track > .splide__list > .splide__slide and the emitters
   can only write custom properties, never markup — true, but scroll-snap needs
   no wrappers at all, so the objection does not apply.

   [style*="--block-carousel:"] means "this block is a carousel" for BOTH values.
   One key with three values rather than two keys, deliberately: a separate
   --block-carouselBleed would NOT be matched by that selector, so a single key
   keeps the "is a carousel" test unambiguous.

   LOOP HAS NO CSS AT ALL, and belongs here only as a signpost. The Loop setting
   emits --block-carouselLoop: on, which assets/js/block-carousel.js reads; it
   then places complete copies of the slides either side of the real ones and,
   once the scroll comes to REST outside the real set, moves scrollLeft by
   exactly one set. The destination is pixel-identical content on an equally
   valid snap point, so the join is invisible and `scroll-snap-type: mandatory`
   below has nothing to correct. Looping is purely a question of where
   scrollLeft is, which a stylesheet cannot express — hence no rule here. The
   clones are ordinary .column nodes, so every rule below applies to them
   unchanged, which is exactly why they are indistinguishable.
   The one thing to know when editing below: a clone is `[data-carousel-clone]`.
   Do not write a rule that makes one look different from a real slide.

   Measured on the live front end (#b17, its three is-4 columns cloned to six),
   1440x900 and 390x844, both variants: slide width 437.266px, snap positions
   0/437/875/1312, first card content edge vs container left +0.005px, section
   height unchanged at 270.22px, documentElement.scrollWidth == clientWidth.
   ========================================================================== */
section.section.block-item[style*="--block-carousel:"] .block-columns {
  /* flex-direction/align-* are declared explicitly because responsive.css:260
     sets them for the mobile column stack. This selector is (0,4,1) against its
     (0,3,1), so it wins on specificity even though responsive.css loads later. */
  display: flex;
  flex-direction: row;
  flex-wrap: nowrap;
  /* LOAD-BEARING. Horizontal Alignment feeds justify-content on the base rule
     above, and a centred flex container overflows in BOTH directions while
     scrollLeft can never go negative — which silently makes the leading slides
     unreachable. A carousel must start at flex-start. */
  justify-content: flex-start;
  align-items: stretch;
  align-content: stretch;
  /* Releases height:100% from the base rule. */
  height: auto;
  overflow-x: auto;
  /* Declared, not left to compute: setting overflow-x to a non-visible value
     forces overflow-y to `auto`, and pinning it stops the row also becoming a
     vertical scroller. COST: a hover lift, drop shadow or focus ring that
     escapes a card is clipped vertically. CSS cannot scroll one axis and leave
     the other visible — Splide's .splide__track has the identical constraint. */
  overflow-y: hidden;
  scroll-snap-type: x mandatory;
  /* MANDATORY, not cosmetic: without it the classic scrollbar adds exactly
     15.00px to every carousel block's height (measured 285.22 vs 270.22).
     With it, 0.00px delta and scrolling/snapping still work. */
  scrollbar-width: none;
}
section.section.block-item[style*="--block-carousel:"] .block-columns::-webkit-scrollbar {
  display: none;
}

section.section.block-item[style*="--block-carousel:"] .block-columns > .column {
  /* NO width declaration on purpose. A percentage on a flex item resolves
     against the container's CONTENT box, which the negative margins above make
     (container + 2 x half-gap) in BOTH variants — so Bulma's .column.is-4
     already yields the right pitch, and MEASURED IT RESOLVES AGAINST THE
     SCROLLPORT, NOT THE SCROLL CONTENT: is-4 stayed 437.266px at 3, 4, 6 and 9
     slides. Bulma's is-N therefore already means "how many are visible", and
     adding slides never shrinks the cards.
     order:0 beats responsive.css:269's order:-1000. scroll-snap-align aligns
     BORDER boxes and .column carries padding:var(--block-elementsGapPx), so the
     first card's CONTENT edge lands on the container edge — no scroll-padding
     needed. */
  flex: 0 0 auto;
  order: 0;
  scroll-snap-align: start;
}

/* --------------------------------------------------------------------------
   Fade inactive slides. The Fade setting emits --block-carouselFade as the
   opacity a slide drops to when it is not wholly inside the scrollport;
   assets/js/block-carousel.js measures which those are and marks them.

   GATED ON [data-carousel-fade], which the JS puts on the track only once the
   first set of marks is in place. Two things fall out of that, both wanted:
   the row cannot flash uniformly dim before the first measurement, and if the
   script never runs, nothing is ever dimmed — same bargain as the arrows.

   Opacity on .column, so the whole slide fades together — card surface, image
   and text as one object rather than three that dim at their own rates.
   Deliberately NO will-change: it would promote every slide, clones included,
   to its own compositor layer for the life of the page, and a looping carousel
   can hold five sets of them.
   -------------------------------------------------------------------------- */
section.section.block-item .block-columns[data-carousel-fade] > .column {
  opacity: var(--block-carouselFade, 1);
  transition: opacity .35s ease;
}
section.section.block-item .block-columns[data-carousel-fade] > .column[data-in-view] {
  opacity: 1;
}
/* The marks are binary, so the transition is what turns them into a fade rather than a pop.
   Reduced motion therefore means "no fade animation", not "no dimming" — the emphasis is still
   conveyed, it just arrives instantly. */
@media (prefers-reduced-motion: reduce) {
  section.section.block-item .block-columns[data-carousel-fade] > .column { transition: none; }
}

/* Right-edge bleed. Swapping the base margin-right for -1 * --bleed carries the
   scrollport to the canvas edge (measured row right 1424.98 vs clientWidth 1425).
   THE PADDING IS NOT OPTIONAL — the margin alone inflates the row's content box,
   so is-N resolves larger and the pitch breaks: measured slide width 456.13px
   instead of 437.27px, with the trailing card 56.53px PAST the container edge.
   The padding restores the content box to container + 2 x half-gap so the pitch
   matches the static blocks above and below, and it adds the scroll length that
   brings the last card back onto the container edge at scroll end (maxScroll
   1312 with it, 1256 without).
   Above the 2000px scaleCap this reaches the CANVAS edge, not the window edge,
   consistent with --element-bleed. block-item's overflow:hidden absorbs the
   overhang: documentElement.scrollWidth stayed == clientWidth in every variant,
   so it can never produce a page-level horizontal scrollbar. */
/* Slides Per Page. Overrides each element's own is-N while the carousel is on.
   `100%` on a flex item resolves against the row's CONTENT box, which the negative
   margins above make (container + 2 x half-gap) — the SAME basis Bulma's is-N uses —
   so calc(100% / 3) is byte-identical to is-4, and no token needs restating. That
   also means it holds in the bleed variant, where the compensating padding-right
   keeps the content box the same width.
   (0,4,1) against Bulma's .column.is-N at (0,1,1), so it wins without !important.
   The key is --block-carouselPerPage, which does NOT contain "--block-carousel:",
   so the mode selector above cannot match it by accident — keep it that way. */
section.section.block-item[style*="--block-carouselPerPage"] .block-columns > .column {
  width: calc(100% / var(--block-carouselPerPage));
}

section.section.block-item[style*="--block-carousel: bleed"] .block-columns {
  margin-right: calc(-1 * var(--bleed));
  padding-right: calc(var(--bleed) - var(--block-elementsGapPx));
}

/* NO MOUSE DRAG-TO-SCROLL, deliberately. It was built and removed 20 Aug: pointer-events
   drag with `scroll-snap-type: none` while dragging (so mandatory snap does not fight each
   scrollLeft write), click suppression after a travelled pointer, and dragstart prevented.
   Mechanically correct, but it did not FEEL right — the release-snap reads as a jump rather
   than a glide, and matching the platform's momentum and rubber-banding by hand is a losing
   game. Dragging and swiping are left to touch, where the browser does all of that natively
   and for free.
   Desktop is served by the injected arrows, trackpad/wheel scrolling, and the track's
   tabindex="0" for arrow-key and Home/End scrolling. Note the scrollbar is hidden
   (scrollbar-width: none above), so a mouse-only user depends on the arrows — do not remove
   them without putting something back.
   If this is revisited: the missing piece was scrollTo-ing the nearest slide smoothly on
   release BEFORE restoring snap, rather than letting the browser re-snap instantly. */

/* --------------------------------------------------------------------------
   Carousel arrows. Injected into .block-container by /assets/js/block-carousel.js,
   NOT into the track — an absolutely positioned child of the scrollport would
   scroll away with the slides. .block-container is already position:relative, so
   this adds no new positioning context.
   Declarations are copied from splide.min.css rather than reusing .splide__arrow,
   for two reasons: that vendor sheet is HAND-EDITED ("Updated for Overlaid
   Arrows") and should stay droppable, and its companion rule in this file
   positions arrows at ∓3rem only for a non-full-width container, which would
   fight the placement below.
   -------------------------------------------------------------------------- */
section.section.block-item .block-carousel__arrow {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  display: flex;
  align-items: center;
  justify-content: center;
  /* LOAD-BEARING on a fluid-canvas site: a <button> does not inherit font-size, so
     without this the svg's 1.2em would resolve against Chrome's 13.33px UA default
     and the chevron would be the one thing on the page that never scales. */
  font: inherit;
  width:  calc(76 * var(--u));
  height: calc(76 * var(--u));
  padding: 0;
  border: 0;
  /* border-radius: 50%; */
  background: rgb(255 255 255);
  cursor: pointer;
  z-index: 20;
  /*opacity: .7;*/
  color: var(--body-colour);
  transition: opacity .2s, color .2s linear;
}
/* Needed because the `display: flex` above beats the UA sheet's [hidden]{display:none},
   so without this the JS setting `.hidden = true` (when a resize removes the overflow)
   would have no visible effect at all. */
section.section.block-item .block-carousel__arrow[hidden] { display: none; }
section.section.block-item .block-carousel__arrow:hover {
  /*opacity: .9;*/
  color: var(--primary-colour);
}
section.section.block-item .block-carousel__arrow:focus-visible {
  outline: 2px solid var(--primary-colour);
  outline-offset: .35rem;
}
/* [aria-disabled], not :disabled — the JS uses aria-disabled so the button stays in
   the tab order and keeps being announced instead of vanishing as you scroll. */
section.section.block-item .block-carousel__arrow[aria-disabled="true"] {
  opacity: .7;
  cursor: default;
}
/* fill: currentColor so the chevron follows the button's own `color` (set above), rather
   than being a second place to change when the button's background changes — this started
   as a white chevron on a dark disc and is now a dark chevron on white.
   The hover transition therefore belongs on `color` on the BUTTON, not on `fill` here: a
   fill of currentColor re-resolves as the animated colour, so transitioning both would
   double up. */
section.section.block-item .block-carousel__arrow svg {
  width: 1em;
  height: 1em;
  fill: currentColor;
}
/* One chevron path in the JS, mirrored for prev. */
section.section.block-item .block-carousel__arrow--prev svg { transform: scaleX(-1); }

/* Centred in the side gutter: half the gutter, minus half the arrow. Below the
   scaleCap the gutter IS --bleed; above it the gutter is wider, so the arrow simply
   sits further from the cards, which is the right behaviour. */
/*section.section.block-item .block-carousel__arrow--prev { left:  calc(-1 * (var(--bleed) / 2 + 38 * var(--u))); }*/
/*section.section.block-item .block-carousel__arrow--next { right: calc(-1 * (var(--bleed) / 2 + 38 * var(--u))); }*/
section.section.block-item .block-carousel__arrow--prev { left:  calc(-1 * (var(--bleed) / 2 + 0 * var(--u))); }
section.section.block-item .block-carousel__arrow--next { right: calc(-1 * (var(--bleed) / 2 + 0 * var(--u))); }

/* No gutter to sit in: a bleeding track reaches the canvas edge, and a full-width
   block's container IS the window. Overlay the arrow instead of hanging it outside. */
section.section.block-item[style*="--block-carousel: bleed"] .block-carousel__arrow--next,
section.section.block-item[style*="--block-containerWidth: 100%"] .block-carousel__arrow--next { right: calc(28 * var(--u)); }
section.section.block-item[style*="--block-containerWidth: 100%"] .block-carousel__arrow--prev { left:  calc(28 * var(--u)); }

section.section.block-item .card {
  background-color: var(--block-cardSurface, var(--card-surface-default));
  color: var(--block-cardText, var(--dark-colour));
  /* border-color: var(--card-border-colour); */
}

/* Spacer. The size is a settings key, so element_settings_to_css_vars() already emits it as
   --element-size on the .element wrapper (custom properties inherit, so it reaches here), and the
   values are SPACING_SCALE_BLOCK — the same scale as the Top/Bottom Block Gap. So "Standard"
   means the same distance whether it came from a block gap or a spacer.
   In design units, so a spacer scales with the canvas. Previously render_element_spacer() mapped
   words to Bulma's my-3/my-8/my-11/my-32 — fixed rem, and one of the last things on the site
   ignoring the fluid canvas.
   The 0 fallback covers a spacer saved before this change and the "None" step: the emitter's
   guard is `$value != ''`, so 0 does emit, but the fallback makes the rule safe either way.
   NOTE the old `.half` (50vh) and `.full` (100vh) rules are gone with the class map that produced
   them — no config option ever offered them and no stored spacer used them. If a full-height
   spacer is ever wanted, add it as a scale step, not as a viewport unit: vh does not participate
   in the canvas and would be the only length on the page that ignores the scaleCap. */
section.section.block-item .element-spacer {
  height: calc(var(--element-size, 0) * var(--u));
}

/* Simple spacing for elements with exactly 2 buttons */
.mce-content-body p:has(.button:first-child:nth-last-child(2)),
.element-text.content p:has(.button:first-child:nth-last-child(2)) {
  display: flex;
  /*justify-content: center;*/
  gap: 1rem;
}
.mce-content-body p[style*="text-align: center"]:has(.button:first-child:nth-last-child(2)),
.element-text.content p[style*="text-align: center"]:has(.button:first-child:nth-last-child(2)) {
  justify-content: center;
}

/* Leading trim on wysiwyg headings.
   A text box includes half-leading above and below the glyphs, but the client measures
   cap-height to baseline in Affinity — so every heading was contributing more height than
   the design allows for, and the fluid canvas's whole premise (a CSS number IS a design
   number) stopped holding for type. Measured on #b12's h2 at 1885px: a 49.42px box around
   31.37px of ink, i.e. 18.05px — 36.5% of the box — was dead space. Trimming gives 30.09px,
   a saving of 28.8 design units, and the box then corresponds to what the mockup measures.

   Replaces `margin-bottom: -0.6rem` on h1/h2/h3:last-child, which was the earlier attempt at
   this. That only clawed back the BOTTOM half-leading, only for h1-h3, and only when the
   heading was the last child — the space above it was never addressed, and any heading
   followed by a paragraph got nothing. Both must not coexist or the bottom is corrected twice.

   Degrades silently: a browser without text-box-trim ignores both declarations and renders
   exactly as the site does today -- but the +10u compensating for it does NOT degrade on its
   own, which is what --heading-trim-comp (line ~106) exists to handle.

   SCOPE: `.content hN`, deliberately matching the margin selector rather than being narrower.
   This was `.element-text.content hN` until 20 Aug, which made the two halves disagree: the
   heading MARGINS (line ~112, and they override Bulma's own .content hN margins at
   bulma.css:2078) apply to every `.content` heading site-wide, while the trim reached only
   wysiwyg text elements. Anywhere else, a heading kept its half-leading AND took the enlarged
   margin, so the gap was paid for twice -- and `.content p` has always been trimmed everywhere,
   so the paragraph below it was already trimmed while the heading above it was not.
   Live cases this fixes: `elements/base.php:36` emits `.element-html content` (margins, no
   trim), `footer.php:25` emits `.footer-col.branding content` whose <p>s are already trimmed
   while `custom.css`'s `.branding h3` rule was not, plus sections.php, products.php,
   call_to_action.php and slides_slideshow.php, all of which emit a bare `.content`.

   The invariant to keep: TRIM SCOPE MUST EQUAL MARGIN SCOPE. If you narrow one, narrow both.

   Not extended to `.title.is-N` (the other half of the margin selector) on purpose: in every
   real instance -- listing/card.php:18, listing/faq.php, listing/usp.php -- it carries a Bulma
   `mb-*` utility, which is !important and already beats the design margin, so that spacing is
   hand-pinned and must not be silently retightened. Where those headings sit inside a
   `.content` they are covered by the rule below anyway.

   Safe against the replaced-content trap that `text-box-edge: cap alphabetic` sets for a box
   with no text metrics (it collapsed `footer a.logo` 25.28px -> 9.58px when tested): grepped,
   and no heading in the project wraps an <img>/<svg>/<picture>. Keep it that way, or exempt it.

   Untestable collateral, accepted: the inherited listing/card boilerplate
   (listing/simple.php, testimonial.php, icon.php, usp.php, faq.php) puts an `mb-0` heading
   inside a `.content`, so those headings now trim and tighten by about half their leading.
   None of it renders -- `/` and `/type-test` are the only routable pages -- and it is fork
   boilerplate from another site, not Scene Windows design work. Re-check when a page uses it. */
.content h1,
.content h2,
.content h3,
.content h4,
.content h5,
.content h6 {
  text-box-trim: trim-both;
  text-box-edge: cap alphabetic;
}

/* EXEMPTION -- trim only the END of a box that contains an ATOMIC INLINE.
   'text-box-edge: cap alphabetic' resolves the first/last line box against the ROOT INLINE BOX's
   font metrics. ANY inline content taller than that cap-to-baseline band overflows; a replaced
   element is one family, not the condition. The box collapses to the strut while the content
   keeps its height -- and `section.block-item` is `overflow: hidden`, so the overflow above is
   CROPPED rather than merely overlapping. That crop is the visible symptom.

   `trim-end`, NOT `none`. The START trim is the half that collapses the box, so drop it; the END
   trim to the alphabetic baseline keeps the box bottom ON the baseline, which is what stops dead
   descender space appearing under an image AND keeps the heading margins honest (they were tuned
   on the premise that the margin IS the whole visual gap). This REPLACES an earlier pairing of
   `text-box-trim: none` with a separate `vertical-align: bottom` rule guarded by `:only-child`;
   `:only-child` counts ELEMENTS and is blind to text nodes, so `<p>SCENE <img> SCENE</p>` matched
   it and the image was bottom-aligned below the text it should sit on. Measured at 1280px,
   image bottom relative to the text bottom: `none`+vertical-align **+7.03px** (wrong),
   `trim-end` **-3.00px** (correct, matching untrimmed). For an image-only block the two are
   identical (box 47px around a 47px image, 0 above, 0 below), and for `<h1><a><img></a></h1>`
   trim-end fixes what the old rule's `>` combinator could not reach.
   `text-box-edge: auto alphabetic` is INVALID (CSS.supports false -- `auto` is not a <text-edge>
   over-value). It must be `text alphabetic`. Verified: `trim-end` and `text alphabetic` both
   supported; `text-box-trim` is the load-bearing half, so never 'simplify' this to the edge alone.

   `:has(:is(...))`, not `:has(...)`: :has() takes a NON-forgiving list, so ONE unparseable future
   addition drops the WHOLE rule and the collapse returns with no error anywhere. Verified:
   `p.matches(':has(img, ::bogus)')` throws SyntaxError; `:has(:is(img, ::bogus))` parses and
   matches identically, nested `p > a > img` included.

   PLAIN `li`, and do NOT try to guard it. Because :has() matches DESCENDANTS, an outer <li> of
   plain text IS exempted when media sits in a NESTED list inside it -- accepted, and mild under
   trim-end (only the top edge loosens; the bottom stays on the baseline, so the margin still
   holds). The two obvious guards are both WORSE, measured in Chrome 151: with either
   `li:not(:has(li))` or a separate `li:has(> :is(...))` arm, an <li> that fails to match ends up
   at `text-box-trim: none; text-box-edge: auto` -- the INITIAL values -- instead of falling back
   to the base `.content li` trim. Verified reproducible: sibling plain <li>s and plain <p>s in the
   same list fall back correctly to trim-both, but an <li> containing any element child does not,
   and removing the guarded rule restores trim-both to it. So the guard silently un-trims the very
   items it was meant to protect. Do not reintroduce it without re-testing this exact case.

   The list is a WHITELIST against an open-ended failure mode, so expect new instances. It cannot
   ever be complete: `<h2>Windows <span style="font-size:3em">Style</span></h2>` overflows by a
   measured 99.77px and is PURE TEXT -- no :has() list can catch the general case. The class
   selectors cover the project's own inline-flex components, both of which are live CMS output:
   `.button` (custom.css:249 proves buttons are expected inside `.content` paragraphs; measured
   7.78px overflowing ABOVE, i.e. cropped) and `.circle-number` (custom.css:216, inline-flex 60px).
   Note trim-end still leaves an inline-flex button ~12.83px BELOW the baseline -- accepted,
   because below merely overlaps whereas above is cropped.

   This shipped broken for a few hours on 20 Aug and is the reason this rule exists. The
   homepage hero (elements.id=21, block 11) is an image-only heading:
       <h1 style="text-align: center;"><img class="img-w-full" src="...logo-white-no....svg"></h1>
   Measured live at 1440px with the trim applying to it: the <h1> box was 33.27px around an
   87.67px image, which overflowed 54.41px ABOVE its own box and was cropped by the section.
   With this exemption the box becomes 98.58px, the image sits inside it, overflow 0.
   The same trap was measured on `footer a.logo` (25.28px -> 9.58px) -- that one is a container,
   not a heading, which is why the trim is kept off containers entirely.

   Why an exemption rather than narrowing the trim back to `.element-text.content hN`: the
   heading MARGINS reach every `.content` heading (they override Bulma's at bulma.css:2078), so a
   heading that is not trimmed above a paragraph that IS pays for the gap twice. Scope must
   match; see the block above. So the trim stays wide and the metric-less cases opt out.

   SPECIFICITY: `:is()` and `:has()` each contribute their most specific argument, giving
   (0,1,2) against `.content hN` and `.content p` at (0,1,1) -- this wins on specificity alone,
   not merely on source order. `none`/`auto` are the spec's initial values, i.e. a true reset.

   `:has()` is safe to depend on here: it is supported more widely than text-box-trim itself
   (:has() Chrome 105+/Safari 15.4+/Firefox 121+ vs trim Chrome 133+/Safari 18.2+/Firefox 154+),
   so no browser can apply the trim but miss the exemption. Verify that pairing still holds
   before removing this note.

   Includes p and li, not just headings: `.content p`/`.content li` have been trimmed since
   before the heading rule widened, and an image in a paragraph collapses identically. Checked
   the DB when this was written -- `elements` had exactly ONE row containing an <img> at all
   (id 21, the heading above), and no text+image paragraph anywhere -- so there is currently no
   mixed content for this to over-reach on. If a heading or paragraph later mixes text WITH a
   small inline icon, this hands back that block's leading (~28u on an h2), which is a real
   visual loosening; at that point narrow this to `:has(> img:only-child)` and friends. */
.content :is(h1, h2, h3, h4, h5, h6, p, li):has(:is(
    img, svg, picture, video, iframe, object, embed, canvas, audio,
    input, textarea, select, button, progress, meter,
    .button, .circle-number, [class*="is-size-"], [style*="font-size"]
  )) {
  text-box-trim: trim-end;
  text-box-edge: text alphabetic;
}

.element-image .image {
  /*clip-path: polygon(0 0, 100% 0, 100% calc(100% - 40px), calc(100% - 40px) 100%, 0 100%);*/
  /* border-radius: 0 50px 50px 50px; */
}

.element[style*="--element-box_style"]:not([style*="--element-box_style: none"]) .boxed {
  padding: 2rem;
  border-radius: var(--border-radius);
  height: 100%;
}
.element[style*="--element-box_style: white"] .boxed {
  background-color: rgb(255, 255, 255);
}
.element[style*="--element-box_style: grey-light"] .boxed {
  background-color: rgb(255 255 255 / 82%);
}
.element[style*="--element-box_style: body-background"] .boxed {
  background-color: var(--body-background);
  color: var(--body-colour);
}
.element[style*="--element-box_style: primary"] .boxed {
  background-color: var(--primary-colour);
}
.element[style*="--element-box_style: primary-light"] .boxed {
  background-color: var(--primary-light-colour);
}

.element-media_video .element-stack__video .responsive-video,
.element-video .responsive-video {
  position: relative;
  width: 100%;
  border-radius: var(--border-radius);
  overflow: hidden;
  background-color: #000;
}
.element-media_video .element-stack__video .responsive-video::before,
.element-video .responsive-video::before {
  content: "";
  display: block;
  padding-top: var(--aspect-ratio, 56.25%);
}
.element-media_video .element-stack__video .responsive-video iframe,
.element-video .responsive-video iframe {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  border: 0;
}
.element-video .video-caption {
  margin-top: 0.75rem;
  font-size: 0.95rem;
  text-align: center;
  color: currentColor;
  opacity: 0.8;
}

/* MEDIA + VIDEO (Combinations) reuses this box for its video part: the wrapper column is
   .element-media_video and the part sits in .element-stack__video, so the three rules above and
   below carry both selectors. Gap and alignment are the stack family's rules; bleed moves the
   IMAGE only (.element-stack__media), which the video wrapper deliberately is not. */

/* ==========================================================================
   VIDEO COVER — the cover-and-play rendering of both video elements
   (_includes/_functions/elements/video.php video_render_box()). The box is the same
   .responsive-video (ratio via --aspect-ratio padding); the cover link fills it, the thumbnail
   covers the box, and assets/img/play.svg — a white glyph, so no disc behind it — sits centred at
   140u, the site's circle-control scale. Hover darkens the cover a touch so the glyph reads as the
   control. After the click the iframe fills the same box (rule above), so nothing reflows.
   ========================================================================== */
.responsive-video.video-cover {
  background-color: var(--dark-colour);
  line-height: 0;
}
.video-cover__poster {
  position: absolute;
  inset: 0;
  display: block;
  color: inherit;
}
.video-cover__poster .image,
.video-cover__thumb {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  margin: 0;
  border-radius: 0;
  line-height: 0;
}
.video-cover__poster .image img,
.video-cover__thumb {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  transform: scale(1);
  transition: transform .8s cubic-bezier(.2,.8,.2,1);
}
.video-cover__poster::after {
  content: "";
  position: absolute;
  inset: 0;
  background: rgb(0 0 0 / .12);
  transition: background .3s ease;
}
.video-cover__poster:hover::after,
.video-cover__poster:focus-visible::after {
  background: rgb(0 0 0 / .3);
}
.video-cover__poster:hover .image img,
.video-cover__poster:hover .video-cover__thumb {
  transform: scale(1.03);
}
.video-cover__play {
  position: absolute;
  top: 50%;
  left: 50%;
  z-index: 1;
  width: calc(140 * var(--u));
  height: calc(140 * var(--u));
  transform: translate(-50%, -50%);
  filter: drop-shadow(0 4px 18px rgb(0 0 0 / .35));
  transition: transform .3s ease;
}
.video-cover__play img {
  display: block;
  width: 100%;
  height: 100%;
}
.video-cover__poster:hover .video-cover__play,
.video-cover__poster:focus-visible .video-cover__play {
  transform: translate(-50%, -50%) scale(1.06);
}
.video-cover__poster:focus-visible {
  outline: calc(3 * var(--u)) solid #fff;
  outline-offset: calc(-8 * var(--u));
}

/* ==========================================================================
   IMAGE ZOOM — the `zoom` setting on every picture-bearing element
   (element_media_zoom() in _includes/_functions/elements/base.php). The wrapper IS the link — the
   whole image opens the viewer — around the untouched figure, with the zoom.svg glyph in the
   bottom-right corner as the affordance: NO disc, NO background, NO shadow (Dan, 9-10 Sep).

   THE GLYPH COLOURS ITSELF FROM THE PICTURE BEHIND IT. The span is masked to the glyph's shape
   (`mask: url(zoom.svg)` — the SVG is a white glyph on transparent, so its alpha is the mask) and
   paints nothing of its own; what shows through the mask is the BACKDROP, run through
   blur → grayscale → brightness → contrast → invert:
     blur(6px)        averages the texture under the glyph, so grass or gravel gives one colour
                      rather than a speckle of both;
     grayscale(1)     luminance only;
     brightness(2.6)  moves the black/white pivot from 50% luminance down to ~19%: black has far
                      more contrast than white against anything but deep shadow (WCAG's +0.05
                      floor), so the glyph should only turn white on genuinely dark backdrops;
     contrast(60)     snaps everything to black or white;
     invert(1)        …and takes the opposite of the backdrop.
   Result: black on sky, grass, render-white and 50% grey; white on dark timber; and across a
   light/dark boundary it changes per pixel. Prototyped in headless Chrome on eight backdrops
   before shipping (scratchpad zoomtest). Two earlier attempts were dropped: mix-blend-mode:
   difference (a mid-tone inverts to another mid-tone — green grass gave a purple glyph) and a
   dark drop-shadow halo (works, but looks like a halo).
   THAT FILTER IS NOW THE FALLBACK. On a dark navy photograph it produced a soft, faintly tinted
   glyph (Dan's screenshot, 10 Sep) -- near the pivot the per-pixel result is neither black nor
   white. The script in base.php therefore samples the picture under the glyph once (canvas, CORS
   image) and sets .is-on-dark or .is-on-light on the link; those rules below switch the filter off
   and paint a SOLID white or black glyph through the same mask -- crisp, one colour per image. The
   filter still paints the glyph until the picture has loaded, and wherever sampling is impossible.
   @supports falls back to the white glyph with a dark halo where backdrop-filter is missing; where
   mask is missing too, nothing paints and the whole image is still the control.
   ========================================================================== */
section.section.block-item a.media-zoom {
  position: relative;
  display: block;
  color: inherit;
  cursor: zoom-in;
}
section.section.block-item a.media-zoom:focus-visible {
  outline: calc(3 * var(--u)) solid var(--primary-colour);
  outline-offset: calc(6 * var(--u));
}
section.section.block-item a.media-zoom:hover .media-zoom__button {
  transform: scale(1.1);
}
.media-zoom__button {
  position: absolute;
  right: calc(40 * var(--u));
  bottom: calc(40 * var(--u));
  z-index: 2;
  display: block;
  width: calc(64 * var(--u));
  height: calc(64 * var(--u));
  -webkit-mask: url(/assets/img/zoom.svg) center / contain no-repeat;
  mask: url(/assets/img/zoom.svg) center / contain no-repeat;
  /* A (near-)transparent fill: backdrop-filter needs the element to paint, but its own colour must
     not tint the result. */
  background: rgb(0 0 0 / .001);
  -webkit-backdrop-filter: blur(6px) grayscale(1) brightness(2.6) contrast(60) invert(1);
  backdrop-filter: blur(6px) grayscale(1) brightness(2.6) contrast(60) invert(1);
  transition: transform .3s ease;
}
/* Decided by the script: solid glyph, filter off. */
section.section.block-item a.media-zoom.is-on-dark .media-zoom__button,
section.section.block-item a.media-zoom.is-on-light .media-zoom__button {
  -webkit-backdrop-filter: none;
  backdrop-filter: none;
}
section.section.block-item a.media-zoom.is-on-dark .media-zoom__button {
  background: #fff;
}
section.section.block-item a.media-zoom.is-on-light .media-zoom__button {
  background: #000;
}
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  .media-zoom__button {
    background: #fff;
    filter: drop-shadow(0 0 1px rgb(0 0 0 / .9)) drop-shadow(0 2px 10px rgb(0 0 0 / .45));
  }
}
/* The single-image viewer has no prev/next; hide the arrows if the shared markup ever grows them. */
.media-zoom-lightbox .gallery-lightbox__prev,
.media-zoom-lightbox .gallery-lightbox__next {
  display: none;
}


.element-video-detail .video-detail__player {
  box-shadow: 0 18px 38px rgb(0 0 0 / 22%);
}

/* ==========================================================================
   SPLIDE OVERWRITTEN STYLES
   ========================================================================== */

     .splide__arrow:hover:not(:disabled) svg {
      fill: var(--primary-colour);
     }

     section:not([style*="--block-containerWidth: 100%"]) .splide__arrow--prev {
      left: -3rem;
     }
     section:not([style*="--block-containerWidth: 100%"]) .splide__arrow--next {
      right: -3rem;
     }

     .element-slides_slideshow .slides-slideshow {
      /*border-radius: var(--border-radius);*/
      /*overflow: hidden;*/
      background-color: #0f1117;
     }
     .element-slides_slideshow .slides-slideshow__slide {
      min-height: clamp(340px, 52vw, 680px);
      display: flex;
      align-items: center;
      background-image:
        /*linear-gradient(90deg, rgb(0 0 0 / 65%) 0%, rgb(0 0 0 / 35%) 45%, rgb(0 0 0 / 20%) 100%),*/
        linear-gradient(90deg, rgb(0 0 0 / 50%) 0%, rgb(0 0 0 / 50%) 100%),
        var(--slide-image);
      background-size: cover;
      background-repeat: no-repeat;
      background-position: center;
      color: #fff;
     }
     .element-slides_slideshow .slides-slideshow__content-wrap {
      width: 100%;
      padding: clamp(2rem, 6vw, 5rem) clamp(1.25rem, 5vw, 4rem);
     }
     .element-slides_slideshow .slides-slideshow__content {
      max-width: 52rem;
      opacity: 0;
      transform: translateY(16px);
      transition: opacity 0.55s ease, transform 0.75s cubic-bezier(0.22, 1, 0.36, 1);
     }
     .element-slides_slideshow .slides-slideshow__content > * {
      opacity: 0;
      transform: translateY(10px);
      transition: opacity 0.5s ease, transform 0.65s cubic-bezier(0.22, 1, 0.36, 1);
     }
     .element-slides_slideshow .slides-slideshow .splide__slide.is-active .slides-slideshow__content {
      opacity: 1;
      transform: translateY(0);
      transition-delay: 0.18s;
     }
     .element-slides_slideshow .slides-slideshow .splide__slide.is-active .slides-slideshow__content > * {
      opacity: 1;
      transform: translateY(0);
     }
     .element-slides_slideshow .slides-slideshow .splide__slide.is-active .slides-slideshow__content > *:nth-child(1) {
      transition-delay: 0.24s;
     }
     .element-slides_slideshow .slides-slideshow .splide__slide.is-active .slides-slideshow__content > *:nth-child(2) {
      transition-delay: 0.32s;
     }
     .element-slides_slideshow .slides-slideshow .splide__slide.is-active .slides-slideshow__content > *:nth-child(3) {
      transition-delay: 0.4s;
     }
     .element-slides_slideshow .slides-slideshow .splide__slide.is-active .slides-slideshow__content > *:nth-child(4) {
      transition-delay: 0.48s;
     }
     .element-slides_slideshow .slides-slideshow .splide__slide.is-active .slides-slideshow__content > *:nth-child(5),
     .element-slides_slideshow .slides-slideshow .splide__slide.is-active .slides-slideshow__content > *:nth-child(6) {
      transition-delay: 0.56s;
     }
     .element-slides_slideshow .slides-slideshow__slide--align-left .slides-slideshow__content {
      margin-right: auto;
      text-align: left;
     }
     .element-slides_slideshow .slides-slideshow__slide--align-center .slides-slideshow__content {
      margin-left: auto;
      margin-right: auto;
      text-align: center;
     }
     .element-slides_slideshow .slides-slideshow__slide--align-right .slides-slideshow__content {
      margin-left: auto;
      margin-right: 0;
      text-align: right;
     }
     .element-slides_slideshow .slides-slideshow__content,
     .element-slides_slideshow .slides-slideshow__content h1,
     .element-slides_slideshow .slides-slideshow__content h2,
     .element-slides_slideshow .slides-slideshow__content h3,
     .element-slides_slideshow .slides-slideshow__content h4,
     .element-slides_slideshow .slides-slideshow__content h5,
     .element-slides_slideshow .slides-slideshow__content h6,
     .element-slides_slideshow .slides-slideshow__content p,
     .element-slides_slideshow .slides-slideshow__content li {
      color: inherit;
     }
     .element-slides_slideshow .slides-slideshow .splide__arrow {
      opacity: 0.9;
     }
     .element-slides_slideshow .slides-slideshow .splide__pagination {
      bottom: 5.25rem;
     }

     @media (prefers-reduced-motion: reduce) {
      .element-slides_slideshow .slides-slideshow__content,
      .element-slides_slideshow .slides-slideshow__content > * {
        opacity: 1;
        transform: none;
        transition: none;
      }
     }

     @media (max-width: 768px) {
      .element-slides_slideshow .slides-slideshow__slide {
        min-height: 420px;
        background-image:
          linear-gradient(180deg, rgb(0 0 0 / 65%) 0%, rgb(0 0 0 / 45%) 48%, rgb(0 0 0 / 30%) 100%),
          var(--slide-mobile-image, var(--slide-image));
      }
      .element-slides_slideshow .slides-slideshow__content-wrap {
        padding: 2rem 1.25rem 2.75rem;
      }
     }

/* ==========================================================================
   BACKGROUND VIDEO
   ========================================================================== */

    section.section.block-item .block-background > div[id*="vjs_video"] {
      position: static;
    }
    /*
     * Video.js generates its own div with the `video-js` class.
     * The `vjs-fill` class we added already makes it width/height 100%,
     * but we ensure the object-fit property is set.
     */
    section.section.block-item .block-background .video-js {
      background: transparent;
    }
    section.section.block-item .block-background .video-js,
    section.section.block-item .block-background video {
      opacity: 0;
      transition: opacity 0.6s ease;
      will-change: opacity;
      height: 100% !important;
    }
    section.section.block-item .block-background.is-video-ready .video-js,
    section.section.block-item .block-background.is-video-ready video {
      opacity: 1;
    }
    section.section.block-item .block-background .video-js .vjs-tech {
        object-fit: cover;
    }
    section.section.block-item .block-background .vjs-poster {
        display: none !important;
    }

    /* Hide any error messages or spinners that might briefly appear */
    section.section.block-item .block-background .vjs-error-display,
    section.section.block-item .block-background .vjs-loading-spinner {
        display: none !important;
    }

/* ==========================================================================
   ELEMENT STYLES
   ========================================================================== */

    /* ==========================================================================
       LOGO SCROLLER
       ========================================================================== */

    /* Container for the logo scroller */
    .gallery-logo-scroller {
        /*padding: 2rem 0;*/
        /* Helps prevent logos from being clipped on the edges on some browsers */
        overflow: hidden;
    }
    /* Style for each logo's container (the slide) */
    .gallery-logo-scroller .splide__slide {
        display: flex;
        align-items: center;
        justify-content: center;
        /* The width is now determined by the image inside, not a grid column */
        width: auto;
    }
    .gallery-logo-scroller .splide__slide .image {
      display: inline-block;
      width: auto;
      border-radius: 0;
    }
    /* Style for the logo images themselves - THIS IS THE MOST IMPORTANT PART */
    .gallery-logo-scroller .splide__slide img {
        /* Set a consistent height for all logos */
        height: 130px;
        opacity: 0.7;

        /* Let the width adjust automatically to maintain the aspect ratio */
        width: auto;

        /* Ensure the image doesn't grow beyond its container (safety measure) */
        max-width: none;

        /* For the "subtle" effect */
        /*opacity: 0.64;*/
        /*filter: grayscale(100%);*/
        /*transition: opacity 0.3s ease, filter 0.3s ease;*/
    }
    .gallery-logo-scroller .splide__slide .image[class*="fixed-"] img {
        height: 100%;
        width: auto;
        max-width: 240px;
    }
    /* Hover effect remains the same */
    .gallery-logo-scroller .splide__slide:hover img {
        opacity: 1;
        /*filter: grayscale(0%);*/
    }

    .partner-logo-carousel .partner-logo-carousel__item {
        display: flex;
        align-items: center;
        justify-content: center;
        text-decoration: none;
    }

    .partner-logo-carousel .partner-logo-carousel__item:focus-visible {
        outline: 2px solid var(--primary-colour);
        outline-offset: 0.35rem;
    }


    /* ==========================================================================
       PRODUCT LISTING
       ========================================================================== */

      section .listing.listing-product,
      section .listing.listing-product .card {
        height: 100%;
      }
      section .listing.listing-product .card {
        background-color: var(--primary-light-colour);
        display: flex;
        flex-direction: column;
      }
      section .listing.listing-product .image-wrapper {
        position: relative;
      }
      section .listing.listing-product .image-wrapper .image {
        border-bottom-left-radius: 0;
        border-bottom-right-radius: 0;
      }
      section .listing.listing-product .image-wrapper .tag {
        position: absolute;
        bottom: 1.5rem;
        right: 1.5rem;
      }
      section .listing.listing-product .card-content {
        /* height: 100%; */
        display: flex;
        flex-direction: column;
        justify-content: space-between;
        flex-grow: 1;
        padding: 1.8rem 1.9rem 1.8rem 1.9rem;
      }
      section .listing.listing-product .card-content .buttons {
        margin-top: auto;
      }
      section .listing.listing-product .card-content p {
        font-size: 12pt;
      }


    /* ==========================================================================
       USP LISTING
       ========================================================================== */

      section .listing.listing-usp,
      section .listing.listing-usp .card,
      section .listing.listing-usp .card-content {
        height: 100%;
      }
      section .listing.listing-usp .card {
        background-color: var(--primary-light-colour);
      }
      section .listing.listing-usp .image {
        height: 60px;
        width: 60px;
        object-fit: contain;
        object-position: bottom left;
      }
      section .listing.listing-usp:not(.listing-usp-dark) .image {
        background: var(--gradient-main);
        mask-image: var(--listing-image);
        mask-size: contain;
        mask-repeat: no-repeat;
        mask-position: center;
        -webkit-mask-image: var(--listing-image);
        -webkit-mask-size: contain;
        -webkit-mask-repeat: no-repeat;
        -webkit-mask-position: center;
      }
      section .listing.listing-usp:not(.listing-usp-dark) .image img {
        object-position: left;
        opacity: 0;
      }

      section .listing.listing-usp.listing-usp-dark .card {
        background: rgba(255, 255, 255, 0.1);
      }
      section .listing.listing-usp.listing-usp-dark .image {
        object-position: center;
        margin-left: auto;
        margin-right: auto;
      }

/* ==========================================================================
   ARTICLE INTRO
   ========================================================================== */

   .element-article-intro .article-intro__category {
    text-transform: uppercase;
    letter-spacing: 0.04em;
    font-weight: 700;
   }
   .element-article-intro .article-intro__title {
    text-wrap: balance;
   }
   .element-article-intro .article-intro__date {
    font-weight: 500;
   }


/* ==========================================================================
   PROJECT INTRO
   ========================================================================== */

   .element-project-intro .project-intro__sector {
      text-transform: uppercase;
      letter-spacing: 0.06em;
      font-weight: 700;
   }

   .element-project-intro .project-intro__title {
      text-wrap: balance;
   }

   .element-project-intro .project-intro__summary {
      font-size: 1.05rem;
      line-height: 1.65;
      color: var(--bulma-grey-light, #b5b5b5);
   }

/* ==========================================================================
   PROJECT DETAILS
   ========================================================================== */

   .element-project-details .project-details__dl {
      display: flex;
      flex-direction: column;
      gap: 0;
   }

   .element-project-details .project-details__dl-row {
      display: grid;
      grid-template-columns: auto 1fr;
      gap: 0.5rem 1rem;
      padding: 1rem 0;
      border-bottom: 1px solid rgba(255, 255, 255, 0.08);
   }

   .element-project-details .project-details__dl-row:first-child {
      border-top: 1px solid rgba(255, 255, 255, 0.08);
   }

   .element-project-details .project-details__dt {
      font-size: 0.7rem;
      text-transform: uppercase;
      letter-spacing: 0.08em;
      font-weight: 700;
      color: var(--bulma-grey, #7a7a7a);
      white-space: nowrap;
      padding-top: 0.1em;
      min-width: 100px;
   }

   .element-project-details .project-details__dd {
      font-size: 0.875rem;
      color: var(--bulma-white, #fff);
      margin: 0;
      line-height: 1.4;
   }


/* ==========================================================================
   ARTICLE CATEGORIES
   ========================================================================== */

   .element-article-categories {
    /*margin-bottom: 1.25rem;*/
   }
   .element-article-categories .article-categories-nav {
    display: flex;
    flex-wrap: wrap;
    gap: 0.55rem;
    margin: 0;
   }
   .element-article-categories .article-categories-nav .article-categories-nav__link {
    display: inline-flex;
    align-items: center;
    gap: 0.45rem;
    height: 2.25rem;
    padding: 0 0.9rem;
    border-radius: 999px;
    font-size: 0.78rem;
    font-weight: 700;
    line-height: 1;
    letter-spacing: 0.03em;
    text-transform: unset;
    font-family: var(--main-font);
   }
   .element-article-categories .article-categories-nav .article-categories-nav__link.is-light {
    border: 1px solid color-mix(in srgb, var(--primary-colour) 16%, white);
   }
   .element-article-categories .article-categories-nav .article-categories-nav__link.is-selected {
    box-shadow: 0 8px 20px rgb(0 0 0 / 12%);
   }
   .element-article-categories .article-categories-nav .article-categories-nav__count {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 1.35rem;
    height: 1.35rem;
    padding: 0 0.3rem;
    border-radius: 999px;
    font-size: 0.72rem;
    font-weight: 700;
    line-height: 1;
    background: rgb(255 255 255 / 40%);
   }
   .element-article-categories .article-categories-nav .article-categories-nav__link.is-light .article-categories-nav__count {
    background: rgb(0 0 0 / 8%);
   }

/* ==========================================================================
   ARTICLE CARDS
   ========================================================================== */

   .element-article-cards__grid {
    --article-card-line: rgb(245 241 236 / 10%);
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: 1px;
    padding: 1px;
    background: var(--article-card-line);
    border: 1px solid var(--article-card-line);
   }
   .element-article-cards__item {
    min-width: 0;
   }
   @media (min-width: 1024px) {
    .element-article-cards__grid--columns {
      grid-template-columns: repeat(var(--article-card-columns, 3), minmax(0, 1fr));
    }
   }

   .article-card {
    background-color: var(--block-cardSurface, var(--body-background));
    color: var(--block-cardText, var(--body-colour));
    display: flex;
    flex-direction: column;
    height: 100%;
    box-shadow: none;
    border: 0;
   }
   .section.section.block-item .article-card {
    background-color: var(--body-background);
    color: var(--body-colour);
   }
   .section.section.block-item .article-card .article-card__content {
    background-color: var(--body-background);
   }
   .article-card .article-card__image-wrap {
    position: relative;
    display: block;
    padding: 1.5rem 1.5rem 0;
    text-decoration: none;
   }
   .article-card .article-card__image-wrap .tags {
    position: absolute;
    top: 2rem;
    left: 2rem;
    z-index: 10;
   }
   .article-card .article-card__content {
    color: inherit;
    display: flex;
    flex-direction: column;
    flex-grow: 1;
    padding: 1.5rem;
   }
   .article-card .article-card__title-link.has-text-body,
   .article-card .article-card__title-link {
    color: var(--block-cardText, var(--body-colour)) !important;
    font-family: var(--heading-font);
   }
   .article-card .article-card__meta,
   .article-card .article-card__summary {
    color: var(--block-cardTextMuted, rgb(245 241 236 / 70%)) !important;
   }
   .article-card .article-card__title-link:hover,
   .article-card .article-card__title-link:focus {
    color: var(--link-colour-hover) !important;
   }
   .article-card .image {
    border-bottom-left-radius: 0;
    border-bottom-right-radius: 0;
   }
   .article-card .article-card__summary {
    line-height: 1.7;
   }
   .article-card .article-card__button {
    margin-top: auto;
   }
   .element-article-cards .element-article-cards__pagination {
    margin-top: 1.25rem;
   }


/* ==========================================================================
   WEBSITE SPECIFIC STYLES
   ========================================================================== */


section.section.block-item.has-video-thumbnail .block-background:after {
  display: none;
}


/*  :root{--wor-background:#fff;--wor-text-color:#000;--wor-shadow:rgb(0 0 0 / 6%) 0px 2px 8px;--wor-stars-background:#eee;--wor-stars-filled:#ffc107}.wor-dark-mode{--wor-background:#222;--wor-text-color:#f1f1f1;--wor-shadow:rgb(255 255 255 / 6%) 0px 2px 8px;--wor-stars-background:#555}.wor-widget:not(:last-child){margin-bottom:2rem}.wor-widget .fademein{transition:opacity .2s}.wor-widget .wor-stars{position:relative;display:inline-flex}.wor-widget .wor-stars .wor-stars-rating{display:flex;gap:.2rem;align-items:center;justify-content:flex-start}.wor-widget .wor-stars .wor-stars-rating svg{height:20px;color:var(--wor-stars-background);width:auto;flex-shrink:0}.wor-widget .wor-stars .wor-stars-rating.wor-stars-rating-front{position:absolute;top:0;left:0;bottom:0;white-space:nowrap;overflow:hidden}.wor-widget .wor-stars .wor-stars-rating.wor-stars-rating-front svg{color:var(--wor-stars-filled)}.wor-widget.wor-widget-carousel .wor-review{padding:1.4rem;background-color:var(--wor-background);box-shadow:var(--wor-shadow);margin-top:5px;margin-bottom:5px;border-radius:6px}.wor-widget.wor-widget-carousel .wor-review .wor-review-author{display:flex;margin-bottom:.6rem;align-items:center}.wor-widget.wor-widget-carousel .wor-review .wor-review-author .wor-review-details{overflow:hidden}.wor-widget.wor-widget-carousel .wor-review .wor-review-author .wor-review-author-name{font-size:1rem;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;margin-bottom:.2rem;color:var(--wor-text-color);line-height:1.2;margin-top:0}.wor-widget.wor-widget-carousel .wor-review .wor-review-author .wor-review-author-date{font-size:.9rem;opacity:.7;color:var(--wor-text-color);line-height:1;margin-top:0}.wor-widget.wor-widget-carousel .wor-review .wor-review-author img.wor-profile-photo{width:42px;margin-right:11px;flex-shrink:0}.wor-widget.wor-widget-carousel .wor-review .wor-stars{margin-bottom:.7rem}.wor-widget.wor-widget-carousel .wor-review .wor-review-comment{margin-bottom:.7rem;color:var(--wor-text-color)}.wor-widget.wor-widget-carousel .wor-review .wor-review-comment .wor-read-less,.wor-widget.wor-widget-carousel .wor-review .wor-review-comment .wor-read-more{cursor:pointer;opacity:.75;margin-left:3px}.wor-widget.wor-widget-carousel .wor-review .wor-review-source svg{height:27px;display:block}.wor-widget.wor-widget-carousel .splide{margin-left:-5px;margin-right:-5px}.wor-widget.wor-widget-carousel .splide__arrow{opacity:.4}.wor-widget.wor-widget-badge .wor-review-badge{padding:.9rem 1.4rem .6rem;background-color:var(--wor-background);box-shadow:var(--wor-shadow);border-radius:6px;width:200px;display:inline-block}.wor-widget.wor-widget-badge .wor-rating-source{text-align:center;margin-bottom:.2rem}.wor-widget.wor-widget-badge .wor-rating-source svg{height:24px;display:inline-block}.wor-widget.wor-widget-badge .wor-rating{display:flex;align-items:center;justify-content:center;gap:.7rem;margin-bottom:.4rem}.wor-widget.wor-widget-badge .wor-rating .wor-stars{position:relative;top:-2px}.wor-widget.wor-widget-badge .wor-rating .wor-stars .wor-stars-rating svg{height:22px}.wor-widget.wor-widget-badge .wor-rating .wor-rating-number{font-size:1.5rem;font-weight:600;line-height:1;padding-top:3px;color:var(--wor-text-color)}.wor-widget.wor-widget-badge .wor-reviews-count{text-align:center;font-size:.9rem;opacity:.7;line-height:1;white-space:nowrap;color:var(--wor-text-color)}.wor-widget.wor-widget-badge.wor-widget-inline .wor-review-badge{display:inline-flex;justify-content:center;width:auto;gap:1rem;align-items:center;padding:.9rem 1.4rem}.wor-widget.wor-widget-badge.wor-widget-inline .wor-review-badge .wor-rating-source{position:relative;bottom:-1px}.wor-widget.wor-widget-badge.wor-widget-inline .wor-review-badge .wor-rating,.wor-widget.wor-widget-badge.wor-widget-inline .wor-review-badge .wor-rating-source{margin-bottom:0;line-height:1}.wor-widget.wor-widget-badge.wor-widget-inline .wor-rating .wor-rating-number{padding-top:0}.wor-dark-mode .wor-rating-source svg,.wor-dark-mode .wor-review-source svg,.wor-dark-mode img.wor-profile-photo{filter:brightness(1.1)}@media (max-width:420px){.wor-widget.wor-widget-badge.wor-widget-inline .wor-review-badge .wor-reviews-count{display:none}}

  .wor-widget.wor-widget-carousel .wor-review {
    border-radius: 0 50px 50px 50px;
  }
  .wor-review .wor-profile-photo {
    width: 42px;
    height: 42px;
    border-radius: 999px;
    object-fit: cover;
  }

  .wor-widget .wor-stars .wor-stars-rating img {
    height: 20px;
    width: auto;
    flex-shrink: 0;
    display: inline-block;
  }

  .wor-widget.wor-widget-carousel .wor-review-source img {
    height: 27px;
    width: auto;
    display: block;
  }

  .wor-widget.wor-widget-carousel .splide__pagination {
    position: static;
    margin: 1rem 0 0;
    justify-content: center;
    padding: 0;
  }

  .wor-widget.wor-widget-carousel .splide__pagination li {
    margin: 0 0.25rem;
  }*/


section.section.block-item[style*="cropped-pattern-mono-linear-white"] .block-background {
  background-size: 500px auto;
  background-position: top right;
  background-repeat: no-repeat;
}


.is-subtitle {
  font-family: var(--heading-font), sans-serif;
  font-size: 1.2rem;
  font-weight: var(--heading-weight);
  letter-spacing: 0.15em;
  text-transform: uppercase;
}

/* ==========================================================================
   FOOTER — two columns, per the client's design.
   Branding + legal on the left, one menu flush right. All spacing on --u so it
   scales with the rest of the page.
   ========================================================================== */
section.footer {
  background-color: var(--footer-background);
  color: var(--body-colour);
}
section.footer .footer-inner {
  padding-top: calc(166 * var(--u));
  padding-bottom: calc(166 * var(--u));
}
section.footer .footer-cols {
  display: grid;
  grid-template-columns: var(--footer-menu-grid-columns);
  gap: var(--footer-menu-grid-gap);
  align-items: start;
}
section.footer .footer-col.branding .logo {
  display: block;
  /*margin-bottom: calc(83 * var(--u));*/
}
section.footer .footer-col.branding .logo img {
  height: calc(36 * var(--u));
  width: auto;
  aspect-ratio: 889 / 97;
}

/* Uniform rhythm down the branding column, one step for every child. Measured before this
   rule at 1280px, the gaps ran 37.41px / 0 / 0 with an 18.93px top margin on the links list —
   the logo was picking up 83 design units (the block-gap step) while the legal lines had no
   margin at all and Bulma's .content added a top margin to the <ul>. Zeroing margin-top and
   setting one bottom value gives a single gap everywhere.
   1rem, i.e. Bulma's mb-4 step. Under the fluid canvas 1rem IS the fluid body size, so this
   scales with the design rather than pinning the footer to a fixed px gap.
   Needs .footer-cols in the selector: at (0,3,1) the logo's 83-unit margin still won, and
   this lands at (0,4,1). Nothing here is !important — an inline margin overrode it cleanly
   when tested, so specificity was the only thing in the way.
   Two levels, because the stack is not flat: SETTINGS['footer_text'] renders as a
   <div class="footer-legal"> wrapping its own <p>s, so those sat tight against each other
   (measured 0px) while every other gap was 1rem. Targeting that wrapper's children with * and
   not p keeps it working if the CMS field is edited to emit something else. The links <ul> is
   .footer-legal-LINKS, so its <li>s are deliberately not caught by either selector. */
section.footer .footer-cols .footer-col.branding > *,
section.footer .footer-cols .footer-col.branding > .footer-legal > * {
  margin-top: 0;
  margin-bottom: 1.2rem;
}
section.footer .footer-cols .footer-col.branding > *:last-child,
section.footer .footer-cols .footer-col.branding > .footer-legal > *:last-child {
  margin-bottom: 0;
}
section.footer .footer-legal,
section.footer .footer-legal p {
  font-size: calc(20 * var(--u));
  line-height: 1.2;
  color: var(--footer-link-color);
  margin: 0;
  font-weight: 500;
}
section.footer .footer-legal-links {
  list-style: none;
  margin: calc(42 * var(--u)) 0 0;
  padding: 0;
}
section.footer .footer-legal-links a {
  font-size: calc(20 * var(--u));
  font-weight: 700;
  color: var(--body-colour);
  text-decoration: none;
  font-family: var(--main-font);
  font-weight: 700;
  text-transform: initial;
}
/* the right-hand menu: one row, uppercase, matching the header treatment */
section.footer .footer-col.menu ul {
  display: flex;
  /* explicitly row: custom.css:3543 sets flex-direction: column for the old stacked
     four-column footer, and without resetting it here that rule still applied. */
  flex-direction: row;
  gap: calc(96 * var(--u));
  list-style: none;
  margin: 0;
  padding: 0;
}
section.footer .footer-col.menu a {
  font-family: var(--footer-menu-link-font);
  font-size: var(--footer-menu-link-font-size);
  font-weight: var(--footer-menu-link-font-weight);
  letter-spacing: var(--footer-menu-link-letter-spacing);
  color: var(--footer-menu-link-color);
  text-transform: uppercase;
  text-decoration: none;
  white-space: nowrap;
}
section.footer .footer-col.menu a:hover { color: var(--footer-menu-link-color-hover); }

@media screen and (max-width: 768px) {
  section.footer .footer-cols { grid-template-columns: 1fr; }
  section.footer .footer-col.menu ul { flex-wrap: wrap; }
}


/* ==========================================================================
   ROW BREAK — an element whose only job is to end the current row.

   .block-columns is `.columns.is-multiline` (blocks.php:87), a WRAPPING flex row, so this needs
   no markup contract and no new DOM: a full-width flex item cannot share a line with anything,
   so it takes a line of its own and everything after it starts a fresh one. The renderer
   (_includes/_functions/elements/row_break.php) returns an EMPTY STRING unless a rule is wanted
   — every part of the break itself is here.

   `flex: none` + `width`, NOT `flex: 0 0 100%`. That shorthand looks equivalent and is a trap:
   responsive.css:260 turns .block-columns into `flex-direction: column` below 769px, and
   flex-basis is measured along the MAIN axis — so `0 0 100%` would mean HEIGHT 100% there, with
   `flex-shrink: 0` to stop it shrinking back. `flex: none` leaves the basis `auto`, which falls
   back to `width` in a row and to natural height in a column. It is also exactly what Bulma's
   own .column.is-N uses, so it is the same idiom rather than a competing one.
   ========================================================================== */
section.section.block-item .block-columns > .column.element-row_break {
  flex: none;
  width: 100%;
  max-width: 100%;
  /* The base `> .column` rule pads every column by one gap on all four sides. On an element with
     no content that is two gaps of invisible dead space, which would make an "invisible" break
     the single most space-consuming element on the page. */
  padding-top: 0;
  padding-bottom: 0;
}

/* With a rule the gap padding is wanted BACK — it is what gives the rule breathing room, from
   the same token as every other gap in the block rather than a number invented here. Keyed off
   the presence of --element-rule, which the emitter omits entirely for an empty value, so this
   needs no sentinel. Horizontal padding is left alone in both cases: .block-columns carries
   negative margins of one gap and .column pads by one gap, so a full-width column's CONTENT
   edge is exactly the container edge — the rule lines up with the grid for free. */
section.section.block-item .block-columns > .column.element-row_break[style*="--element-rule"] {
  padding-top: var(--block-elementsGapPx);
  padding-bottom: var(--block-elementsGapPx);
}

.element-row-break__rule {
  /* Full reset of bulma.css:284 — height: 2px, background-color: #2e2a2b, margin: 1.5rem 0. */
  display: block;
  margin: 0;
  border: none;
  background-color: var(--grey-border);
  /* max() because a hairline expressed in design units goes sub-pixel and disappears: 2u is
     1.03px at 1440 but 0.62px at 870. The 1px floor keeps it drawn at every width; above
     ~1950px the design unit overtakes it and the rule scales with the canvas like everything
     else. Same reasoning as --type-floor, and unlike that one this really does need px. */
  height: max(1px, calc(2 * var(--u)));
}

section.section.block-item .block-columns > .column.element-row_break[style*="--element-rule: heavy"] .element-row-break__rule {
  height: max(2px, calc(6 * var(--u)));
}

/* A row break inside a carousel block is meaningless and actively harmful. The carousel rules
   above set flex-wrap: nowrap and make .block-columns a scroll-snap scrollport — there are no
   rows left to break, and the element would instead occupy a snap position as a blank slide
   (full-width, so it would eat the whole viewport at one scroll stop). */
section.section.block-item[style*="--block-carousel:"] .block-columns > .column.element-row_break {
  display: none;
}


/* ==========================================================================
   STACK ICON ROWS (the icons part of icon_list and text_media_icons)

   An icon/text list stacked with an image and/or a rich-text body inside one .column — the shape
   the product pages use three-across. Everything is in design units so it scales on the fluid
   canvas like the rest of the site.

   SHARED, not per element type: element_stack_icons() emits the same markup for every stack type
   that carries icon rows, so these rules are keyed on `.element-stack__*` and a new type that
   wants rows needs no CSS at all. The image-to-list distance is NOT here — that is the family's
   internal gap (search COMBINATION ("STACK") ELEMENTS above), where icon_list's measured 100u is
   preserved as its own default.

   THE NUMBERS BELOW ARE MEASURED OFF THE COMP, not from Affinity. Taken from a 1400px-wide
   export, where one design unit is 1400 / 2806.4 = 0.4989px:
     icon square   ~36px -> 72u
     icon -> text  ~26px -> 52u
     row -> row    ~26px -> 52u  (80px pitch minus a two-line text block)
     image -> list ~50px -> 100u
   Treated the same way as the h3-h6 type sizes: round estimates, correct to a few units, to be
   replaced with the real values off the Affinity file. Nothing else depends on them.
   ========================================================================== */
.element-stack__items {
  /* Bulma's .content styles ul/li heavily (list-style, margin-left, nested margins) and this is
     a layout list, not prose. Reset rather than override piecemeal — the element does not carry
     `.content`, but a parent might. */
  list-style: none;
  margin: 0;
  padding: 0;

  /* TWO COLUMNS WHEN THERE IS ROOM, ONE WHEN THERE IS NOT — AND NO BREAKPOINT TO MAINTAIN.
     The trigger has to be the width of THIS element, not the viewport: the same list renders as
     one of three columns on a product page and full-bleed in a wide slide, so a media query would
     be measuring the wrong box. A container query would read the right box but needs
     `container-type` on an ancestor, which brings inline-size containment down onto
     .element-stack — the element that per-element bleed moves with negative margins. Not worth
     the risk for a two-column list. `columns` needs neither: the browser fits as many
     column-widths as the ELEMENT can hold, and column-count caps it.
     MULTICOL RATHER THAN GRID, and this is the whole reason: grid rows are ROWS. A row containing
     a three-line item is three lines tall for BOTH columns, so the column holding the shorter item
     gets a ragged slab of whitespace under it and the two columns stop sharing a rhythm. Multicol
     columns are independent, so every gap down every column is exactly the measured 52u whatever
     the items do. The trade is that the icons no longer line up ACROSS the columns and reading
     order becomes column-major (1,2,3 | 4,5) rather than row-major — the print convention, and it
     still matches DOM order, so it reads as it is announced.
     ONE NUMBER CONTROLS THE SWITCH: 2 columns need 2 * --stack-icons-min-column + the gutter =
     1183u of available width. Against the real column widths a full-width element gets ~2331u and
     goes to two, an is-6 ~1103u stays at one, an is-4 ~693u stays at one. The floor is 560u
     rather than the ~520u that would land is-6 right on the crossover — a row spends 82u on the
     tile plus a 52u gap before the text starts, so a 520u row leaves the label about 25
     characters, and is-6 flipping on a rounding error is the worst outcome. Retune HERE. */
  --stack-icons-min-column: calc(560 * var(--u));
  --stack-icons-column-gap: calc(63 * var(--u));
  columns: var(--stack-icons-min-column) 2;
  column-gap: var(--stack-icons-column-gap);
}


.element-stack__item {
  /* One source of truth for the tile size — .element-stack__icon reads it for both dimensions. */
  --stack-icon-size: calc(82 * var(--u));
  display: flex;
  /* CENTRED, against the whole text block. The earlier note here argued for flex-start on the
     grounds that the first line "is the line it reads with", and that holds while a row is one or
     two lines — but two columns halve the text measure, three- and four-line rows became normal,
     and an icon pinned to the first line of a four-line block reads as top-heavy rather than as
     labelling it. Centring also makes this exact rather than approximate: it needs no half-leading
     correction, because it centres the text's BOX and a line box is symmetric about its own ink.
     A tall block now grows equally above and below the tile. */
  align-items: center;
  gap: calc(52 * var(--u));
  /* ROW RHYTHM LIVES HERE, NOT AS A GAP ON THE LIST, because multicol has no row gap to set.
     margin-BOTTOM specifically, never margin-top: at a column break a top margin would push the
     first item of column two down and the two columns would start at different heights, whereas
     a trailing bottom margin simply falls at the foot of the column where nothing follows it. */
  margin: 0 0 calc(52 * var(--u));
  /* Never split a row's icon from its text across the column boundary. */
  break-inside: avoid;
}

.element-stack__item:last-child {
  margin-bottom: 0;
}

.element-stack__icon {
  /* flex: none so a wide SVG cannot stretch the icon column and knock the text out of alignment
     across the three columns. Explicit width AND height so the row does not reflow as the SVG
     loads — these are the only images on the page with a known intrinsic size. */
  flex: none;
  width: var(--stack-icon-size);
  height: var(--stack-icon-size);
  display: block;
  /* THE TILE IS DRAWN HERE, NOT IN THE ARTWORK. Every file in assets/icons is a WHITE glyph on
     transparent — the source export's stray reds were normalised to white on the owner's call —
     so without this the icons are invisible on a light page. It also means the tile colour is a
     setting rather than baked into every file in the set.
     KNOCKOUT DETAIL IS A HOLE, NOT A COLOUR, throughout the set — the "10" in
     10-year-guarantee, the "RC2" in security-rc2, colour-fan's and ral-colour-fan's blade edges,
     padlock's keyhole ring, glass-sightlines' reflection lines. The tile reads through them, so
     they follow this setting like everything else. `currentColor` is NOT an option and never was:
     the icons are <img src>, not inline SVG, so no CSS reaches inside them.
     TWO MECHANISMS, both holes, and grep will mislead you about the second. The icons added later
     punch with `fill-rule: evenodd`. The ones exported earlier wrap the glyph in a luminance
     <mask id="ko-…"> and draw the detail BLACK inside that mask, where black means transparent —
     so `stroke:black` in colour-fan, padlock and glass-sightlines is a hole, not paint. Check
     whether a black is inside a <mask> before concluding the set is inconsistent; it is not.
     --element-icon_colour comes from the Icon Tile Colour field (a fixed palette: a pale value
     would make white glyphs unreadable and white would erase them). Absent, it falls through to
     the token below, so the default red lives in one place. */
  background-color: var(--element-icon_colour, var(--icon-tile-colour));
  border-radius: calc(8 * var(--u));
  /* Inset on an <img> works because the background paints the padding box while the image is
     drawn in the content box, so this is the tile's internal margin. box-sizing keeps the 82u
     square the OUTER size, which is what has to stay consistent down the column.
     THIS IS THE ONLY PLACE THE GLYPH INSET IS SET, and it is 13u rather than 5u because every
     file in assets/icons now has a viewBox CROPPED TO ITS INK -- no built-in margin of its own.
     That was a real fix, not a tidy-up: the files as exported each carried their own arbitrary
     margin, so the glyphs rendered at wildly different optical sizes in an identical tile
     (colour-fan filled 95% of its canvas, window-frame 57%). With the margin here instead, all
     21 land the same size and the set finally reads as one. 82 - 2*13 = a 56u glyph, which is
     what the old set averaged, so nothing changed size on the page by much.
     A non-square viewBox keeps its aspect ratio for free: width/height stay square, so the
     default preserveAspectRatio (xMidYMid meet) fits the ink inside the square and centres it.
     Crop a new icon to its ink before dropping it in -- assets/icons is globbed, so nothing
     validates this for you. */
  padding: calc(13 * var(--u));
  box-sizing: border-box;
}

/* A row whose icon is missing gets no tile — a bare coloured square would read as a deliberate
   blank icon rather than an absent one. Overrides the background above; it still holds the icon
   column open so the text edges stay aligned. */
.element-stack__icon--empty {
  background-color: transparent;
}

.element-stack__text {
  /* min-width: 0 so a long unbroken word can wrap instead of forcing the row wider than the
     column. A flex item defaults to min-width: auto, which is its min-content size. */
  min-width: 0;
  font-weight: 500;
}


/* ==========================================================================
   LEVEL BODY COPY ACROSS THE COLUMNS OF A ROW

   Opt-in per block via the "Level Body Copy Across Columns" setting, emitted as
   --block-levelHeadings by block_settings_to_css_vars() (_includes/_functions/blocks.php:397,
   which writes every settings key generically — this needed no PHP).

   THE PROBLEM IS THAT TEXT AND IMAGES ARE MEASURED DIFFERENTLY, not that anything is misaligned.
   Measured on /hormann #b53 at a 1600px viewport: three is-4 media_text columns, bodies opening
   with a heading, text in the first and an SVG logo in the other two. `.content p` carries
   `text-box-trim: trim-both`, so a TEXT heading's box is its cap height — 21u — while the same
   property computes to `trim-end` on a paragraph whose content is an inline image, leaving those
   at the image's own height, 48.5u and 48.1u. Every column's media bottom, body top and heading
   top were already identical; it was purely that 27u of box height, inherited by everything
   below, which put the paragraph tops 27.4u apart.

   WHY NOT SUBGRID, which is the textbook answer for levelling a band across columns: it needs the
   ROW to be a grid, and .block-columns is a Bulma flex row where .column.is-4 is literally
   `flex: none; width: 33.33333%`. Converting it would invalidate every is-N width, is-multiline
   wrapping, row_break, the carousel scrollport and the bleed margins. Flex cannot do it either —
   it only distributes spare space WITHIN an item, never across siblings — so a reserved band is
   the only declarative option left, and it is also what the comp actually describes: a fixed
   distance from the block top to the body copy, not "wherever the tallest logo happens to land".

   `1lh` — one line of the heading's OWN type — rather than a number, so it tracks the type scale
   and needs no knowledge of the logos. It clears the measured 48.5u with 5.5u to spare.
   TOP-ALIGNED INSIDE THE BAND, deliberately: the heading tops were already level across the row
   and the design reads that way, so the only thing this moves is the shorter column's paragraph,
   downward, to meet the others. Bottom-aligning instead would equalise each heading-to-paragraph
   gap but drop the text heading ~33u below the logos, which is a different design.
   A heading logo taller than one line will overflow the band and break the level again. Size the
   logo down rather than raising the band: a logo taller than the type it sits with is a design
   decision either way, and the two logos here are already matched to each other. */
section.section.block-item[style*="--block-levelHeadings: on"] .element-stack__body > :first-child {
  min-height: 1lh;
}

/* ==========================================================================
   STACK ELEMENT VERTICAL ALIGNMENT

   Distributes the element's own parts (media, body, icon rows) down the column, for when a taller
   element elsewhere in the row has stretched this column. `space-between` is the case it was added
   for: body copy at the top, logo pinned to the bottom so it lines up with the base of a big image
   beside it.

   ENTIRELY GATED on the presence of --element-verticalAlign, which the emitter omits for the empty
   option. So the default stays plain block flow and no existing stack element renders differently.
   That matters: there is a media_text on the homepage.

   THE HEIGHT IS THE WHOLE PROBLEM, and the handoff records this trap twice already -- a percentage
   height against an auto-height parent resolves to auto, so the element gets no spare room and
   justify-content has nothing to distribute. .element-stack's parent is the .column, which only
   has a definite height when the row stretches it. .block-columns takes align-items from
   --block-verticalAlign, and `normal` (the stored default) behaves as stretch for flex items -- but
   a block set to Align Top / Middle / Bottom does NOT stretch its columns, and this would then
   silently do nothing.

   Hence align-self: stretch on the wrapper. It makes the element setting self-sufficient rather than
   dependent on how the block happens to be aligned. It overrides the block's align-items for THIS
   column only, and only when a vertical alignment is actually asked for -- which is the point: an
   element cannot distribute its content down a column it has not been given.
   ========================================================================== */
section.section.block-item .element[style*="--element-verticalAlign"] {
  align-self: stretch;
}

/* The whole family shares this -- same stacked parts, same need to distribute down a column a
   taller sibling has stretched. `align-self: stretch` above is already element-type-agnostic (it
   keys on the generic .element wrapper) and this keys on `.element-stack`, so a new stack type
   needs no CSS here either. Types that do not offer the field never emit the var, so they are
   unaffected. */
section.section.block-item .element[style*="--element-verticalAlign"] .element-stack {
  display: flex;
  flex-direction: column;
  height: 100%;
  /* justify-content, not align-items: flex-direction is column, so the vertical axis is the MAIN
     one. The stored values are raw CSS (flex-start / center / flex-end / space-between), matching
     how the block's Vertical Alignment feeds align-items directly. */
  justify-content: var(--element-verticalAlign);
}

/* The internal gap rule (`.element-stack > * + *`) still applies and is still wanted -- it is the
   MINIMUM separation. space-between only distributes what is left over, so the parts cannot end up
   closer than that gap even in a short row. */


/* Image horizontal alignment. Value-matched selectors rather than
   `object-position: var(--element-image_align) center`, matching the --element-fit rules above
   (~:1812) that this sits alongside: same idiom, and a junk stored value produces no rule instead
   of an invalid object-position. Scoped to the generic `.element` wrapper, again like fit, so adding
   the field to another element type later needs no CSS.

   Only bites when the figure has a definite height (a ratio or fixed Image Height) -- otherwise the
   artwork already fills the box and there is nothing to move. Paired with Contain it slides the
   letterboxed artwork; paired with Cover it shifts the crop origin. */
section.section.block-item .element[style*="--element-image_align: left"] .image img {
  object-position: left center;
}
section.section.block-item .element[style*="--element-image_align: right"] .image img {
  object-position: right center;
}


/* Gap Between the Stacked Parts — overrides the built-in internal gap above
   (`.element-stack > * + *`, which is 1.5 x --block-elementsGapPx and so follows whatever the
   block's Gap Between Elements is set to), and icon_list's measured 100u default with it.

   Gated on the presence of --element-gap, which the emitter omits for the empty option, so the
   default stays block-relative and no existing stack element changes.

   Stored as a raw number and multiplied by --u here, exactly as the spacer element consumes
   --element-size. At (0,5,1) it beats both base rules -- the family default (0,3,1) and
   icon_list's measured default (0,4,1) -- so no !important.

   Kept on `margin-top` of every child after the first rather than switching to `gap` on the
   wrapper, for the reason the base rule already records: `gap` would also apply when only one part
   is populated, and element_stack_wrap() drops an empty part entirely. It stays correct under any
   stacking order too, since `> * + *` does not care which child is which. */
section.section.block-item .element[style*="--element-gap"] .element-stack > * + * {
  margin-top: calc(var(--element-gap) * var(--u));
}

/* ==========================================================================
   LINKED STACK CARDS — the `link` field on the combination ("stack") elements

   When a stack carries a link, element_stack_wrap() (_stack.php) emits the wrapper as an <a> with
   the `element-stack--link` modifier instead of a <div>. Built for the three "Quotation / Showroom
   / Contact Scene" cards (Enquiry.pdf page 1): the comp has no buttons, the cards ARE the controls.

   THE HOVER IS A `top` LIFT, NOT A TRANSFORM, for the reason recorded on the sector/project cards
   (search ELEMENTS: SECTOR GRID): a transform composites the card at a fractional resting position
   and drags the overflow clip across sub-pixels, leaving a hairline at the image edge mid-transition;
   `top` re-rasterises cleanly. Same 4px, so the two card families move identically.

   SPECIFICITY IS DELIBERATE. `section.section.block-item a.element-stack` is (0,2,2), which beats
   Bulma's `a`/`a:hover` colour rules but LOSES to the vertical-alignment rule
   `section.section.block-item .element[style*="--element-verticalAlign"] .element-stack` at (0,3,1)
   — so a linked stack that is also vertically aligned still becomes the flex column that setting
   needs, and `display: block` here only supplies the default an <a> lacks.
   ========================================================================== */
section.section.block-item a.element-stack {
  display: block;
  color: inherit;
  text-decoration: none;
  position: relative;
  top: 0;
  transition: top .5s cubic-bezier(.2,.8,.2,1);
}
section.section.block-item a.element-stack:hover,
section.section.block-item a.element-stack:focus-visible {
  top: -4px;
  color: inherit;
}
section.section.block-item a.element-stack:focus-visible {
  outline: calc(3 * var(--u)) solid var(--primary-colour);
  outline-offset: calc(8 * var(--u));
}
/* Body copy keeps its own colours inside the anchor: Bulma paints link descendants only through
   `a` itself (inherited above), but pin the paragraph colour so a future `a p` rule cannot tint it. */
section.section.block-item a.element-stack .content p {
  color: var(--body-colour);
}

/* ==========================================================================
   ENQUIRY FLOW — the multi-step "Make an enquiry" element (Enquiry.pdf 2-5)

   One element renders the whole flow (see _includes/_functions/elements/enquiry.php): the option
   steps, the progress rail and the personal-details form, inside one <form class="enquiry">.

   NUMBERS ARE MEASURED OFF THE 1400px COMP, where 1u = 1400 / 2806.4 = 0.4989px, and expressed in
   design units (var(--u)) so they scale on the fluid canvas like the rest of the site. Same status
   as the icon_list and h3-h6 figures: correct to a few units, replace from the Affinity file when
   it lands. Layout proportions from the comp: cards area ~1816u wide, rail from ~1993u, container
   2457.6u — so steps take ~72% and the rail ~22% with a ~6% gutter. Option cards are a 2-column
   grid (820u columns, 86u gutter); the landing page's three cards are ordinary media_text elements,
   not this.

   PROGRESSIVE ENHANCEMENT. Without JS every step is visible and the form still posts; the inline
   script in the renderer adds `.enquiry--js` synchronously so these hide-inactive rules apply
   before first paint. Everything keyed on `.enquiry--js` is therefore JS-only chrome.
   ========================================================================== */

.enquiry {
  --enq-rail-width: 22%;
  --enq-rail-gap: 6%;
  --enq-card-gap: calc(86 * var(--u));
  --enq-line: color-mix(in srgb, var(--body-colour) 16%, transparent);
  --enq-muted: var(--grey-dark);
  display: grid;
  grid-template-columns: minmax(0, 1fr) var(--enq-rail-width);
  column-gap: var(--enq-rail-gap);
  align-items: start;
}

/* Rail sits second in the DOM (after the steps) so reading and tab order go content-first, and is
   pulled into the right-hand column visually. Sticky so it stays beside a tall step.

   TWO THINGS HAD TO BE TRUE FOR THE STICKY TO WORK, and neither was at first:
   1. No ancestor may be a scroll container. `section.section.block-item` carries `overflow: hidden`
      (search --block-background above), and overflow:hidden establishes a scrollport even though
      nothing can scroll it — so the rail was sticking to the block, which never moves. The rule
      below switches only the block that holds an enquiry to `overflow: clip`: identical visual
      clipping, but clip does not create a scroll container, so the rail sticks to the window.
      Scoped with :has() rather than changed globally on purpose — every live block relies on that
      hidden and none of them was audited for the BFC/scrollport difference. A browser without
      :has() (or clip) simply gets a non-sticky rail; nothing else changes. IF A SECOND STICKY
      THING EVER LANDS IN A BLOCK, make the global switch to `overflow: clip` instead and drop this.
   2. `top` must clear the site header, which is itself `position: sticky; top: 0` (section.header).
      Measured live at 1440px: 98px = 191u, all of it fluid, so it holds at every width. 191 + 39
      (the body-copy paragraph margin, so the gap sits on the site's rhythm) = 230u. There is no
      header-height token to read; if the header padding changes, this is the number to retune. */
section.section.block-item:has(.element-enquiry) {
  overflow: clip;
}
.enquiry__rail {
  grid-column: 2;
  grid-row: 1;
  position: sticky;
  top: calc(230 * var(--u));
  align-self: start;
}
.enquiry__steps {
  grid-column: 1;
  grid-row: 1;
  min-width: 0;
}

/* ---- Steps ---------------------------------------------------------------- */
.enquiry__step { border: 0; padding: 0; margin: 0; min-width: 0; }
/* Only the active step shows once JS is on. Without JS, all steps stack in order. */
.enquiry--js .enquiry__step { display: none; }
.enquiry--js .enquiry__step.is-active { display: block; }

.enquiry__head { margin-bottom: calc(70 * var(--u)); }
.enquiry__title { margin-bottom: calc(24 * var(--u)); }
.enquiry__title:focus { outline: none; }
.enquiry__intro { color: var(--body-colour); max-width: 46ch; }

/* ---- Option cards (4-up grid; was 2-up until 2 Oct 2026) ------------------- */
.enquiry__grid {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: var(--enq-card-gap);
}
.enquiry__option { min-width: 0; }

.enquiry__card {
  display: grid;
  grid-template-rows: auto auto 1fr;
  cursor: pointer;
  height: 100%;
  /* Containing block for the visually-hidden input below, so it sits inside the card rather than
     resolving against the nearest positioned ancestor (.container). Keyboard focus then scrolls to
     the card the visitor is on. Mouse clicks do not move focus at all — see enquiry.js, "Card
     clicks: select WITHOUT moving focus", for the scroll-to-top bug that made that necessary. */
  position: relative;
}
/* When the JS scrolls a new step into view it aligns the form's top edge to the window; the site
   header is sticky and ~191u tall, so without this the step heading lands underneath it. Same
   figure as the rail's `top` above, for the same reason. */
.enquiry { scroll-margin-top: calc(230 * var(--u)); }

/* The real input drives state but is not shown; the card is the control. Not display:none — it
   must stay focusable, so the keyboard can reach it and :focus-visible can ring the card. */
.enquiry__input {
  position: absolute;
  width: 1px; height: 1px;
  margin: -1px; padding: 0; border: 0;
  clip: rect(0 0 0 0); clip-path: inset(50%);
  overflow: hidden; white-space: nowrap;
}

.enquiry__media {
  position: relative;
  aspect-ratio: 4 / 5;
  overflow: hidden;
  background: var(--grey-light);
  margin-bottom: calc(40 * var(--u));
}
.enquiry__media .image,
.enquiry__media .image img {
  width: 100%; height: 100%;
  margin: 0; border-radius: 0;
}
.enquiry__media .image img { object-fit: cover; display: block; }
.enquiry__media--empty { display: block; }

/* The selectable outline. Drawn as an inset ring (no layout shift when it thickens on select),
   the same technique the sector/project cards use. */
.enquiry__media::after {
  content: "";
  position: absolute; inset: 0;
  box-shadow: inset 0 0 0 calc(3 * var(--u)) transparent;
  transition: box-shadow .2s ease;
  pointer-events: none;
}
.enquiry__card:hover .enquiry__media::after {
  box-shadow: inset 0 0 0 calc(3 * var(--u)) color-mix(in srgb, var(--primary-colour) 30%, transparent);
}
.enquiry__input:checked ~ .enquiry__media::after {
  box-shadow: inset 0 0 0 calc(6 * var(--u)) var(--primary-colour);
}
/* Keyboard focus ring on the whole card. */
.enquiry__input:focus-visible ~ .enquiry__media {
  outline: calc(3 * var(--u)) solid var(--primary-colour);
  outline-offset: calc(4 * var(--u));
}

/* Selected tick, top-right of the image: a solid brand square (background-color) with a white
   checkmark drawn on top (background-image). Two layers in one pseudo-element, so no extra markup.
   Hidden until the input is checked. */
.enquiry__media::before {
  content: "";
  position: absolute;
  top: calc(24 * var(--u)); right: calc(24 * var(--u));
  width: calc(56 * var(--u)); height: calc(56 * var(--u));
  background-color: var(--primary-colour);
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23fff' stroke-width='3' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M5 12l4 4 10-10'/%3E%3C/svg%3E");
  background-size: 62% 62%;
  background-position: center;
  background-repeat: no-repeat;
  opacity: 0;
  transform: scale(.6);
  transition: opacity .18s ease, transform .18s ease;
  z-index: 1;
}
.enquiry__input:checked ~ .enquiry__media::before { opacity: 1; transform: scale(1); }

.enquiry__card-title {
  font-family: var(--heading-font), serif;
  font-weight: var(--heading-weight);
  letter-spacing: var(--heading-spacing);
  text-transform: uppercase;
  font-size: calc(var(--type-h6) * var(--ut));
  line-height: 1.2;
  margin-bottom: calc(16 * var(--u));
}
.enquiry__card-text {
  color: var(--body-colour);
  font-size: calc(var(--type-body) * var(--ut));
  line-height: 1.6;
  max-width: 34ch;
}

/* ---- Uploads (shown under a selected upload-enabled card) ------------------ */
.enquiry__uploads {
  grid-column: 1 / -1;
  /*margin-top: calc(40 * var(--u));*/
  padding: calc(40 * var(--u));
  background: var(--grey-light);
}
.enquiry__uploads-label {
  font-family: var(--main-font), system-ui, sans-serif;
  font-size: 0.72rem;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--grey-dark);
  margin-bottom: calc(24 * var(--u));
  font-weight: 500;
}
.enquiry__dropzone { position: relative; }
.enquiry__file-input {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  opacity: 0; cursor: pointer;
}
.enquiry__dropzone-inner {
  display: flex; align-items: center; gap: calc(32 * var(--u));
  flex-wrap: wrap;
  padding: calc(32 * var(--u));
  border: calc(2 * var(--u)) dashed var(--enq-line);
  background: var(--body-background);
  transition: border-color .2s ease, background-color .2s ease;
}
.enquiry__dropzone.is-dragover .enquiry__dropzone-inner {
  border-color: var(--primary-colour);
  background: color-mix(in srgb, var(--primary-colour) 4%, var(--body-background));
}
.enquiry__dropzone-hint { color: var(--grey-dark); font-size: 0.85rem; }
.enquiry__choose { pointer-events: none; }

.enquiry__files { list-style: none; margin: calc(24 * var(--u)) 0 0; padding: 0; }
.enquiry__file {
  display: flex; align-items: center; gap: calc(24 * var(--u));
  padding: calc(20 * var(--u)) 0;
  border-bottom: 1px solid var(--enq-line);
}
.enquiry__file:first-child { border-top: 1px solid var(--enq-line); }
.enquiry__file-name { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.enquiry__file-name a { color: inherit; text-decoration: underline; text-decoration-color: var(--enq-line); }
.enquiry__file-name a:hover { text-decoration-color: currentColor; }
.enquiry__file-size { color: var(--grey-dark); font-size: 0.85rem; flex: none; }
.enquiry__file.is-uploading { opacity: .6; }
.enquiry__file-progress {
  flex: none; width: calc(120 * var(--u)); height: calc(4 * var(--u));
  background: var(--enq-line); overflow: hidden;
}
.enquiry__file-progress span { display: block; height: 100%; width: 0; background: var(--primary-colour); transition: width .2s ease; }
.enquiry__file-remove {
  flex: none; border: 0; background: none; cursor: pointer;
  color: var(--grey-dark); text-decoration: underline;
  font-family: inherit; font-size: 0.85rem; padding: 0;
}
.enquiry__file-remove:hover { color: var(--body-colour); }
.enquiry__uploads-error { color: #c00; margin-top: calc(16 * var(--u)); font-size: 0.85rem; }

/* ---- The form step -------------------------------------------------------- */
.enquiry__fields {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: calc(40 * var(--u)) calc(63 * var(--u));
}
/* Address and the long "Additional Information" span both columns, like the comp. */
.enquiry__fields .field_type_text_box { grid-column: 1 / -1; }
.enquiry__fields .field { margin-bottom: 0; }
.enquiry__captcha { margin-top: calc(40 * var(--u)); }

/* Field appearance. The site's general `form .fields .field .input` rules (search FORM ELEMENTS)
   were tuned for a DARK section — light text on a translucent-white border — so on this white page
   they would be near-invisible. Restyle to the comp's underline look: black uppercase labels, a
   single bottom rule, no box. SELECTORS CARRY FOUR CLASSES (.enquiry .enquiry__fields .field .X) so
   they beat the generic rules at (0,3,1): four classes outranks three whatever the element counts,
   no !important needed. Keep the four-class prefix on anything added here. */
.enquiry .enquiry__fields .field > label.label {
  color: var(--body-colour);
  font-family: var(--main-font), system-ui, sans-serif;
  font-size: 0.72rem;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  margin-bottom: calc(20 * var(--u));
}
/* "NAME*" as in the comp. render_form_field_base() puts `required` on the wrapper, so the mark is
   CSS and stays in step with the field's setting in the form editor. */
.enquiry .enquiry__fields .field.required > label.label::after { content: "*"; }
.enquiry .enquiry__fields .field .input,
.enquiry .enquiry__fields .field .textarea,
.enquiry .enquiry__fields .field .select select {
  background: transparent;
  border: 0;
  border-bottom: calc(2 * var(--u)) solid var(--enq-line);
  border-radius: 0;
  color: var(--body-colour);
  padding: calc(16 * var(--u)) 0;
  min-height: 0;
  box-shadow: none;
  font-size: calc(var(--type-body) * var(--ut));
  transition: border-color .2s ease;
}
.enquiry .enquiry__fields .field .textarea { min-height: calc(120 * var(--u)); resize: vertical; }
.enquiry .enquiry__fields .field .input:focus,
.enquiry .enquiry__fields .field .textarea:focus,
.enquiry .enquiry__fields .field .select select:focus {
  border-bottom-color: var(--primary-colour);
  outline: none;
}
.enquiry .enquiry__fields .field .input::placeholder,
.enquiry .enquiry__fields .field .textarea::placeholder { color: var(--grey-dark); }
.enquiry .enquiry__fields .field .input.is-danger,
.enquiry .enquiry__fields .field .textarea.is-danger { border-bottom-color: #c00; }
.enquiry .enquiry__fields .field .help { color: var(--grey-dark); }

/* ---- Step nav ------------------------------------------------------------- */
.enquiry__nav {
  display: flex; align-items: center; justify-content: space-between;
  gap: calc(32 * var(--u));
  margin-top: calc(70 * var(--u));
}
/* Back and Continue are JS-only; without JS the single submit at the end is all that is needed. */
.enquiry:not(.enquiry--js) .enquiry__back,
.enquiry:not(.enquiry--js) .enquiry__next { display: none; }
.enquiry__back {
  border: 0; background: none; cursor: pointer;
  font-family: var(--main-font), system-ui, sans-serif;
  letter-spacing: 0.14em; text-transform: uppercase; font-size: 0.72rem;
  color: var(--grey-dark); padding: 0;
}
.enquiry__back:hover { color: var(--body-colour); }
.enquiry__next, .enquiry__submit { margin-left: auto; }
.enquiry__step-error { color: #c00; margin-top: calc(24 * var(--u)); }

/* ---- Progress rail -------------------------------------------------------- */
.enquiry__rail-list { list-style: none; margin: 0; padding: 0; }
.enquiry__rail-item {
  position: relative;
  padding-left: calc(56 * var(--u));
  padding-bottom: calc(56 * var(--u));
}
.enquiry__rail-item:last-child { padding-bottom: 0; }
/* The bullet. */
.enquiry__rail-item::before {
  content: "";
  position: absolute; left: 0; top: calc(4 * var(--u));
  width: calc(22 * var(--u)); height: calc(22 * var(--u));
  border-radius: 50%;
  background: var(--enq-line);
  transition: background-color .2s ease;
}
/* The connecting line, from this bullet down to the next. */
.enquiry__rail-item:not(:last-child)::after {
  content: "";
  position: absolute;
  left: calc(10 * var(--u)); top: calc(26 * var(--u)); bottom: calc(4 * var(--u));
  width: calc(2 * var(--u));
  background: var(--enq-line);
  transition: background-color .2s ease;
}
/* Done and current steps get a solid black bullet and a solid line above them. */
.enquiry__rail-item.is-done::before,
.enquiry__rail-item.is-current::before { background: var(--primary-colour); }
.enquiry__rail-item.is-done::after { background: var(--primary-colour); }

.enquiry__rail-button {
  border: 0; background: none; padding: 0; text-align: left; cursor: default;
  font-family: var(--heading-font), serif;
  font-weight: var(--heading-weight);
  letter-spacing: var(--heading-spacing);
  text-transform: uppercase;
  font-size: calc(var(--type-h6) * var(--ut));
  line-height: 1.1;
  color: var(--enq-muted);
  transition: color .2s ease;
}
.enquiry__rail-item.is-done .enquiry__rail-button,
.enquiry__rail-item.is-current .enquiry__rail-button { color: var(--body-colour); }
/* A reachable step (done) is clickable to jump back. */
.enquiry__rail-item.is-done .enquiry__rail-button { cursor: pointer; }
.enquiry__rail-item.is-done .enquiry__rail-button:hover { color: var(--grey-dark); }

.enquiry__rail-values { list-style: none; margin: calc(12 * var(--u)) 0 0; padding: 0; }
.enquiry__rail-values li {
  color: var(--grey-dark);
  font-size: calc(var(--type-body) * var(--ut));
  line-height: 1.5;
}

/* ---- Success modal reuse -------------------------------------------------- */
/* The action flashes the same `sentModal` markup the contact form uses, so no extra CSS here. */

/* ---- Mobile (interim; no mobile comp yet — NEXT item in HANDOFF) ----------- */
@media (max-width: 768px) {
  .enquiry {
    grid-template-columns: minmax(0, 1fr);
  }
  /* Rail moves ABOVE the steps and collapses to a horizontal step strip. */
  .enquiry__rail {
    grid-column: 1; grid-row: 1;
    position: static;
    margin-bottom: 2rem;
  }
  .enquiry__steps { grid-column: 1; grid-row: 2; }
  /* PHONE PROGRESS: a segmented bar captioned "STEP 2 OF 4" (5 Oct 2026). It replaced a dotted
     strip that showed only the current step's name, wrapped under its dot and repeated the step
     heading right below it. One segment per step, filled for done and current.
     The caption is CSS generated content, so it needs no markup or JS: every item counts towards
     `enq-total`, done and current also towards `enq-step`, and the list's ::after comes after all
     the items, so it reads both final values. order: -1 lifts it above the bar.
     The step names stay in the DOM, visually hidden, so screen readers still hear each step in the
     "Your progress" list, and enquiry.js marks the current one aria-current="step". The chosen
     values are hidden: the steps themselves show what was picked. */
  .enquiry__rail-list {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
    counter-reset: enq-step enq-total;
  }
  .enquiry__rail-list::after {
    content: "Step " counter(enq-step) " of " counter(enq-total);
    order: -1;
    flex: 0 0 100%;
    margin-bottom: 10px;
    font-family: var(--heading-font), serif;
    font-weight: var(--heading-weight);
    letter-spacing: var(--nav-letter-spacing);
    text-transform: uppercase;
    font-size: 13px;
    line-height: 1.2;
    color: var(--enq-muted);
  }
  .enquiry__rail-item {
    flex: 1 1 0;
    padding: 0;
    counter-increment: enq-total;
  }
  .enquiry__rail-item.is-done,
  .enquiry__rail-item.is-current { counter-increment: enq-step enq-total; }
  .enquiry__rail-item::before {
    position: static;
    display: block;
    transform: none;
    width: 100%;
    height: 4px;
    border-radius: 2px;
  }
  .enquiry__rail-item:not(:last-child)::after { display: none; }
  .enquiry__rail-values { display: none; }
  .enquiry__rail-button {
    position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap;
  }
  /* Two across (was one): stacked, each card was 438px tall and the four options ran to three
     screens. 2 Oct 2026. */
  .enquiry__grid { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 24px 16px; }
  .enquiry__fields { grid-template-columns: minmax(0, 1fr); }
}
/* Narrow phones: two across left ~150px columns, which clipped "Refurbishment" at 360px and
   wrapped the descriptions a few words to a line. Each option becomes a selectable ROW instead:
   square thumbnail left, title and text right. The whole row is still the <label>, so tapping
   anywhere selects, and the selected ring (on .enquiry__media) stays visible on the thumbnail. */
@media (max-width: 479px) {
  .enquiry__grid { grid-template-columns: minmax(0, 1fr); gap: 16px; }
  .enquiry__card {
    grid-template-columns: min(96px, 22vw) minmax(0, 1fr);
    grid-template-rows: auto 1fr;
    column-gap: 16px;
    align-items: start;
  }
  .enquiry__media {
    grid-column: 1;
    grid-row: 1 / span 2;
    aspect-ratio: 1 / 1;
    margin-bottom: 0;
  }
  /* overflow-wrap is the backstop for a single long word in the letterspaced heading face
     ("Refurbishment" is ~175px) on the narrowest screens. */
  .enquiry__card-title { grid-column: 2; grid-row: 1; margin-top: 4px; overflow-wrap: anywhere; }
  .enquiry__card-text { grid-column: 2; grid-row: 2; }
}

/* ==========================================================================
   ELEMENTS: SHOWCASE — project cards and the full-width feature (Showcase.afdesign, 9 Sep 2026)

   Renderer: _includes/_functions/elements/showcase.php; templates in _templates/elements/showcase/.

   NUMBERS ARE READ OFF THE EMBEDDED PREVIEW AND ONE SCREENSHOT, NOT A MEASURED EXPORT. The renders
   available of Showcase.afdesign this session were its 114x512 thumbnail (1px = 24.6u) and a
   763px-wide screenshot of Artboard1 (1px = 3.68u), so the grid is correct to ~25u and the hero to
   ~5u, with type inferred from the site's own scale: card image ~1.1:1 two across on the design's
   126.8u gutter, ~42u to the meta lines, ~166u between card rows; the feature is 16:9 edge to edge;
   the hero is 1.855:1 (the brand heroes' ratio), its caption 184u from the left and 166u up from
   the bottom, name ~52u caps, category ~33u caps. Same status as the h3-h6 estimates: REPLACE FROM
   A 1400px EXPORT when one lands (drop it in assets/design/ like the homepage slices).

   Lengths are design units (--u), type is the type unit (--ut) so it follows --type-floor like the
   rest of the site — no px floors here, on purpose. The per-row count and the image ratio are the
   element's own settings, emitted generically as --element-columns / --element-image_ratio on the
   .element wrapper and read here with the comp values as fallbacks, so the CMS needed no PHP or JS
   for either. The column gap is TWO half-gaps (2 x --block-elementsGapPx = 126u at the standard
   block gap), i.e. the same gutter .block-columns gives sibling elements, so a grid of cards and a
   row of media_text elements sit on one rhythm.

   The whole card is the link (the comp has no button), so the hover is the sector cards' `top`
   lift — see ELEMENTS: SECTOR GRID for why `top` and not a transform. The feature's edge-to-edge
   comes from the element's Bleed setting via the generic per-element bleed rule (search
   --element-bleed); the rule below only re-aligns its caption to the container edge in that case.
   ========================================================================== */

.showcase-grid {
  --showcase-columns: var(--element-columns, 2);
  --showcase-ratio: var(--element-image_ratio, 1.1);
  --showcase-col-gap: calc(2 * var(--block-elementsGapPx));
  --showcase-row-gap: calc(166 * var(--u));
  --showcase-inset: calc(63 * var(--u));
  display: grid;
  grid-template-columns: repeat(var(--showcase-columns), minmax(0, 1fr));
  column-gap: var(--showcase-col-gap);
  row-gap: var(--showcase-row-gap);
  align-items: start;
}

/* Slides layout: each card is its own .column (a block-carousel slide), so the variables the card
   reads from .showcase-grid are set here instead. Portrait by default, as the comp's "See More
   Inspirational Scenes" cards are (~0.86). */
.showcase-slide {
  --showcase-ratio: var(--element-image_ratio, 0.86);
  --showcase-inset: calc(63 * var(--u));
}

.showcase-grid--feature {
  --showcase-ratio: var(--element-image_ratio, 1.7778);
  grid-template-columns: minmax(0, 1fr);
  row-gap: var(--showcase-col-gap);
}

/* `section.section.block-item a.showcase-card` is (0,2,2): beats Bulma's `a` colour rules, same
   weight as the linked stack cards. */
section.section.block-item .showcase-card,
section.section.block-item .showcase-feature {
  display: block;
  position: relative;
  top: 0;
  min-width: 0;
  color: inherit;
  text-decoration: none;
  transition: top .5s cubic-bezier(.2,.8,.2,1);
}

section.section.block-item a.showcase-card:hover,
section.section.block-item a.showcase-card:focus-visible,
section.section.block-item a.showcase-feature:hover,
section.section.block-item a.showcase-feature:focus-visible {
  top: -4px;
  color: inherit;
}

section.section.block-item a.showcase-card:focus-visible,
section.section.block-item a.showcase-feature:focus-visible {
  outline: calc(3 * var(--u)) solid var(--primary-colour);
  outline-offset: calc(8 * var(--u));
}

/* ---- The image box: sized by ratio, image covers it ---------------------- */
.showcase-card__media,
.showcase-feature__media {
  position: relative;
  overflow: hidden;
  aspect-ratio: var(--showcase-ratio);
  background: var(--grey-light);
  line-height: 0;
}

.showcase-card__media .image,
.showcase-feature__media .image {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  margin: 0;
  border-radius: 0;
  line-height: 0;
}

.showcase-card__media .image img,
.showcase-feature__media .image img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  transform: scale(1);
  transition: transform .8s cubic-bezier(.2,.8,.2,1);
}

.showcase-card:hover .showcase-card__media img,
.showcase-feature:hover .showcase-feature__media img {
  transform: scale(1.04);
}

/* Legibility wash behind the white title. Card: only the lower half. Feature: a longer ramp,
   because its caption carries two lines and the arrow. */
.showcase-card__media::after,
.showcase-feature__media::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 1;
  pointer-events: none;
  background: linear-gradient(180deg, transparent 45%, rgb(0 0 0 / .55) 100%);
}

.showcase-feature__media::after {
  background: linear-gradient(180deg, rgb(0 0 0 / .05) 0%, rgb(0 0 0 / .25) 50%, rgb(0 0 0 / .7) 100%);
}

/* ---- Card caption: title over the image, two lines beneath ---------------- */
.showcase-card__title {
  position: absolute;
  left: var(--showcase-inset);
  right: var(--showcase-inset);
  bottom: calc(55 * var(--u));
  z-index: 2;
  margin: 0;
  color: #fff;
  font-family: var(--heading-font), sans-serif;
  font-weight: var(--heading-weight);
  font-size: calc(38 * var(--ut));
  line-height: 1.2;
  letter-spacing: var(--heading-spacing);
  text-transform: uppercase;
  text-shadow: 0 1px 18px rgb(0 0 0 / .25);
}

.showcase-card__meta {
  margin-top: calc(42 * var(--u));
  line-height: normal;
}

.showcase-card__category {
  margin: 0;
  color: var(--body-colour);
  font-family: var(--heading-font), sans-serif;
  font-weight: var(--heading-weight);
  font-size: calc(22 * var(--ut));
  line-height: 1.4;
  letter-spacing: .14em;
  text-transform: uppercase;
}

.showcase-card__location,
.showcase-card__products {
  margin: calc(12 * var(--u)) 0 0;
  color: var(--grey-dark);
  font-size: calc(24 * var(--ut));
  line-height: 1.5;
}

.showcase-card__placeholder {
  background: var(--grey-light);
}

/* On the two dark block swatches (#222222 / #000000, cms/section-blocks.php) the meta lines flip to
   white, the way the seeded "More Projects" band on a project page uses them. Keyed on the block's
   own --block-background var the same way the bleed rules key on --element-bleed; a light swatch
   leaves the default colours alone. */
section.section.block-item[style*="--block-background: #222222"] .showcase-card__category,
section.section.block-item[style*="--block-background: #000000"] .showcase-card__category {
  color: #fff;
}
section.section.block-item[style*="--block-background: #222222"] .showcase-card__location,
section.section.block-item[style*="--block-background: #000000"] .showcase-card__location,
section.section.block-item[style*="--block-background: #222222"] .showcase-card__products,
section.section.block-item[style*="--block-background: #000000"] .showcase-card__products {
  color: rgb(255 255 255 / .7);
}
/* "Image and story" (showcase_grid style split, the homepage band): the project's name and
   summary inside the media_text stack. White on the dark backgrounds, as the hand-typed copy it
   replaced was. No hover underline on the name and no hover lift on the card (both removed 6 Oct
   at Dan's request); the keyboard focus ring stays. The lift is only switched off here, so the
   other linked media + text cards (the enquiry cards) keep theirs. */
section.section.block-item .element-showcase_grid a.element-stack:hover,
section.section.block-item .element-showcase_grid a.element-stack:focus-visible {
  top: 0;
}
/* Through .element-stack .content so it outranks the linked-card rule that pins paragraph colour
   to --body-colour (search "a.element-stack .content p"). */
section.section.block-item[style*="--block-background: #222222"] .element-stack .content .showcase-split__name,
section.section.block-item[style*="--block-background: #000000"] .element-stack .content .showcase-split__name,
section.section.block-item[style*="--block-background: #222222"] .element-stack .content .showcase-split__summary,
section.section.block-item[style*="--block-background: #000000"] .element-stack .content .showcase-split__summary {
  color: #fff;
}


/* ---- Feature caption ------------------------------------------------------- */
.showcase-feature__content {
  position: absolute;
  left: var(--showcase-inset);
  right: var(--showcase-inset);
  bottom: calc(126 * var(--u));
  z-index: 2;
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: end;
  column-gap: calc(63 * var(--u));
  color: #fff;
  line-height: normal;
}

/* Bled to both edges the image is 100vw, so the caption re-aligns to the container edge. */
section.section.block-item .element[style*="--element-bleed: both"] .showcase-feature__content {
  left: var(--bleed);
  right: var(--bleed);
}

.showcase-feature__title {
  grid-column: 1;
  margin: 0;
  color: #fff;
  font-family: var(--heading-font), sans-serif;
  font-weight: var(--heading-weight);
  font-size: calc(70.6 * var(--ut));
  line-height: 1.1;
  letter-spacing: var(--heading-spacing);
  text-transform: uppercase;
}

.showcase-feature__subline {
  grid-column: 1;
  margin: calc(21 * var(--u)) 0 0;
  color: rgb(255 255 255 / .85);
  font-family: var(--heading-font), sans-serif;
  font-weight: var(--heading-weight);
  font-size: calc(22 * var(--ut));
  line-height: 1.4;
  letter-spacing: .14em;
  text-transform: uppercase;
}

.showcase-feature .circle-arrow-button {
  --circle-arrow-button-border: rgb(255 255 255 / .6);
  --circle-arrow-button-bg: transparent;
  --circle-arrow-button-color: #fff;
  grid-column: 2;
  grid-row: 1 / span 2;
  width: calc(90 * var(--u));
  height: calc(90 * var(--u));
}

/* White fill on hover, not the primary colour: primary is black and this sits on a photograph. */
.showcase-feature:hover .circle-arrow-button,
.showcase-feature:focus-visible .circle-arrow-button {
  --circle-arrow-button-border: #fff;
  --circle-arrow-button-bg: #fff;
  --circle-arrow-button-color: var(--dark-colour);
}

/* ---- Page hero (Artboard1) --------------------------------------------------
   Not a link as a whole (the subtitle is editor copy); the caption is. The lockup is composed —
   the white Scene wordmark (logo-white-noc…svg, viewBox 841x97) at ~100u tall, a 3u rule, the word
   in the heading face sized so its caps match — because the comp's "SCENE | SHOWCASE" is exactly
   that and it saves an export. Lockup ~1667u wide in the comp, centred a little above the middle;
   subtitle body-sized beneath it. */
.showcase-grid--hero {
  --showcase-ratio: var(--element-image_ratio, 1.8553);
  grid-template-columns: minmax(0, 1fr);
}

.showcase-hero {
  position: relative;
  overflow: hidden;
  aspect-ratio: var(--showcase-ratio);
  background: var(--dark-colour);
  color: #fff;
  line-height: 0;
}

.showcase-hero__media {
  position: absolute;
  inset: 0;
  z-index: 0;
}

.showcase-hero__media .image {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  margin: 0;
  border-radius: 0;
  line-height: 0;
}

.showcase-hero__media .image img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* A light overall veil for the white lockup, deepening at the foot for the caption — the brand
   heroes get the same effect from backgroundOpacity 75 over #222222. */
.showcase-hero__media::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 1;
  pointer-events: none;
  background: linear-gradient(180deg, rgb(0 0 0 / .18) 0%, rgb(0 0 0 / .18) 55%, rgb(0 0 0 / .55) 100%);
}

.showcase-hero__inner {
  position: absolute;
  inset: 0;
  z-index: 2;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  padding: 0 var(--bleed) calc(120 * var(--u));
  text-align: center;
  line-height: normal;
}

.showcase-hero__lockup {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: calc(46 * var(--u));
  margin: 0;
  color: #fff;
  line-height: 1;
}

.showcase-hero__logo {
  display: block;
  height: calc(100 * var(--u));
  width: auto;
}

.showcase-hero__rule {
  display: block;
  width: calc(3 * var(--u));
  height: calc(150 * var(--u));
  background: currentColor;
  opacity: .9;
}

.showcase-hero__word {
  display: block;
  font-family: var(--heading-font), sans-serif;
  font-weight: var(--heading-weight);
  font-size: calc(140 * var(--ut));
  line-height: 1;
  letter-spacing: .1em;
  text-transform: uppercase;
  opacity: .92;
}

.showcase-hero__text {
  max-width: calc(1100 * var(--u));
  margin-top: calc(60 * var(--u));
  color: #fff;
}

.showcase-hero__text p,
.showcase-hero__text strong {
  color: #fff;
}

.showcase-hero__caption {
  position: absolute;
  left: var(--showcase-inset);
  right: var(--showcase-inset);
  bottom: calc(166 * var(--u));
  z-index: 3;
  display: block;
  color: #fff;
  text-decoration: none;
  line-height: normal;
}

section.section.block-item .element[style*="--element-bleed: both"] .showcase-hero__caption {
  left: var(--bleed);
  right: var(--bleed);
}

.showcase-hero__name {
  display: block;
  font-family: var(--heading-font), sans-serif;
  font-weight: var(--heading-weight);
  font-size: calc(52 * var(--ut));
  line-height: 1.15;
  letter-spacing: var(--heading-spacing);
  text-transform: uppercase;
}

.showcase-hero__category {
  display: block;
  margin-top: calc(34 * var(--u));
  font-family: var(--heading-font), sans-serif;
  font-weight: var(--heading-weight);
  font-size: calc(30 * var(--ut));
  line-height: 1.3;
  letter-spacing: .14em;
  text-transform: uppercase;
  opacity: .9;
}

a.showcase-hero__caption:hover,
a.showcase-hero__caption:focus-visible {
  color: #fff;
}

a.showcase-hero__caption:hover .showcase-hero__name,
a.showcase-hero__caption:focus-visible .showcase-hero__name {
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: .2em;
}

a.showcase-hero__caption:focus-visible {
  outline: calc(3 * var(--u)) solid #fff;
  outline-offset: calc(8 * var(--u));
}

/* THE MID-PAGE FEATURE (Showcase.pdf, Sarah and Matthew; render_showcase_card() swaps a feature
   that has lockup/text onto hero.php with .showcase-hero--feature). Same photo box and caption as
   the hero, laid out LEFT: the lockup small at top-left (~290u wordmark, 76u down), the
   intro left-aligned at the container edge just below the middle. Measured from a 2012px render of
   the 2795u artboard (1px = 1.389u). Ratio 1.855 like the hero -- the comp's photo is 1.85, not the
   16:9 the bare feature uses. */
.showcase-hero--feature {
  aspect-ratio: var(--element-image_ratio, 1.8553);
}

/* The comp washes the feature photo LIGHT rather than darkening it like the hero: a white veil
   over the upper part (the sky reads near-white), clearing through the middle, then a dark band at
   the foot so the white caption still reads. Estimated by fitting the comp render against the
   source photo, region by region. */
.showcase-hero--feature .showcase-hero__media::after {
  background: linear-gradient(180deg,
    rgb(255 255 255 / .38) 0%,
    rgb(255 255 255 / .2) 45%,
    rgb(0 0 0 / .05) 68%,
    rgb(0 0 0 / .45) 100%);
}

.showcase-hero--feature .showcase-hero__inner {
  align-items: flex-start;
  justify-content: center;
  padding: calc(150 * var(--u)) var(--showcase-inset) 0;
  text-align: left;
}

section.section.block-item .element[style*="--element-bleed: both"] .showcase-hero--feature .showcase-hero__inner {
  padding-left: var(--bleed);
  padding-right: var(--bleed);
}

.showcase-hero--feature .showcase-hero__lockup {
  position: absolute;
  top: calc(76 * var(--u));
  left: var(--showcase-inset);
  gap: calc(18 * var(--u));
}

section.section.block-item .element[style*="--element-bleed: both"] .showcase-hero--feature .showcase-hero__lockup {
  left: var(--bleed);
}

.showcase-hero--feature .showcase-hero__logo { height: calc(34 * var(--u)); }
.showcase-hero--feature .showcase-hero__rule { height: calc(52 * var(--u)); width: calc(2 * var(--u)); }
.showcase-hero--feature .showcase-hero__word { font-size: calc(48 * var(--ut)); }

.showcase-hero--feature .showcase-hero__text {
  max-width: calc(780 * var(--u));
  margin-top: 0;
}

@media (max-width: 768px) {
  .showcase-grid,
  .showcase-grid--feature,
  .showcase-grid--hero {
    grid-template-columns: minmax(0, 1fr);
  }

  /* 16:9 leaves no room for a two-line caption at phone widths; the hero needs the lockup, the
     subtitle AND the caption, so it goes taller still. */
  .showcase-grid--feature {
    --showcase-ratio: var(--element-image_ratio, 1.25);
  }

  .showcase-grid--hero {
    --showcase-ratio: var(--element-image_ratio, 0.9);
  }

  .showcase-feature__content {
    bottom: calc(63 * var(--u));
  }

  .showcase-hero__inner {
    padding-bottom: calc(400 * var(--u));
  }
}

/* ==========================================================================
   IN THE SCENE — the project page's carousel of tagged products
   (_includes/_functions/elements/showcase.php render_element_showcase_products(),
   _templates/elements/showcase/products.php + product.php; Showcase Project 1.afdesign)

   A centred small-caps heading over a Splide track of product cards, in the comp's order: an image
   box (square by default, --element-image_ratio to change it; the product is a cut-out on white so
   it is CONTAINED, not covered — the template passes contain to _image()), the brand row (logo from
   brands.image, or a small-caps name tag until one is uploaded), the product name in bold mixed
   case and a one-line summary. The comp's per-project spec lines (glazing, finishes) are not yet
   modelled — see the template header. Card gap is the same two half-gaps as the showcase grid, passed to Splide as a
   CSS string so it stays in design units. The arrows are the site's restyled .splide__arrow
   (search ELEMENTS: ARROW / splide.min.css), nothing new here. Read off the 512x173 nine-artboard
   thumbnail, so the proportions are approximate — same export caveat as ELEMENTS: SHOWCASE.
   ========================================================================== */

.showcase-products {
  --showcase-products-ratio: var(--element-image_ratio, 1);
  line-height: normal;
}

.showcase-products__heading {
  margin: 0 0 calc(83 * var(--u));
  color: var(--heading-colour);
  font-family: var(--heading-font), sans-serif;
  font-weight: var(--heading-weight);
  font-size: calc(30 * var(--ut));
  line-height: 1.3;
  letter-spacing: .18em;
  text-align: center;
  text-transform: uppercase;
}

.showcase-products__splide {
  visibility: visible;
}

.showcase-products .splide__slide {
  min-width: 0;
}

section.section.block-item .showcase-product {
  display: block;
  position: relative;
  top: 0;
  height: 100%;
  color: inherit;
  text-decoration: none;
  transition: top .5s cubic-bezier(.2,.8,.2,1);
}

section.section.block-item a.showcase-product:hover,
section.section.block-item a.showcase-product:focus-visible {
  top: -4px;
  color: inherit;
}

section.section.block-item a.showcase-product:focus-visible {
  outline: calc(3 * var(--u)) solid var(--primary-colour);
  outline-offset: calc(8 * var(--u));
}

.showcase-product__media {
  position: relative;
  overflow: hidden;
  aspect-ratio: var(--showcase-products-ratio);
  background: var(--grey-light);
  line-height: 0;
}

.showcase-product__media .image {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  margin: 0;
  border-radius: 0;
  line-height: 0;
}

.showcase-product__media .image img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: contain;
  transform: scale(1);
  transition: transform .8s cubic-bezier(.2,.8,.2,1);
}

/* Cut-outs on white in the comp, so the box is white too; the element's Image Fit = Cover
   re-enables cropping for photographic product shots. */
.showcase-product__media {
  background: #fff;
}
section.section.block-item .element[style*="--element-fit: is-cover"] .showcase-product__media .image img {
  object-fit: cover;
}

.showcase-product:hover .showcase-product__media img {
  transform: scale(1.04);
}

/* Brand row under the image, as the comp lays it out. The logo is capped to a small height so
   the four brands' marks (very different aspect ratios) sit on one baseline. */
.showcase-product__brand {
  margin-top: calc(42 * var(--u));
  line-height: 0;
}

.showcase-product__brand-logo {
  display: block;
  height: calc(44 * var(--u));
  width: auto;
  max-width: 60%;
}

.showcase-product__brand-tag {
  display: inline-block;
  padding: calc(8 * var(--u)) calc(20 * var(--u));
  background: var(--dark-colour);
  color: #fff;
  font-family: var(--heading-font), sans-serif;
  font-weight: var(--heading-weight);
  font-size: calc(18 * var(--ut));
  line-height: 1.4;
  letter-spacing: .14em;
  text-transform: uppercase;
}

.showcase-product__title {
  margin: calc(30 * var(--u)) 0 0;
  color: var(--heading-colour);
  font-weight: 700;
  font-size: calc(26 * var(--ut));
  line-height: 1.4;
}

.showcase-product__summary {
  margin: calc(12 * var(--u)) 0 0;
  color: var(--grey-dark);
  font-size: calc(24 * var(--ut));
  line-height: 1.5;
}

/* On the dark swatches the meta flips to white, as the showcase cards do. */
section.section.block-item[style*="--block-background: #222222"] .showcase-products__heading,
section.section.block-item[style*="--block-background: #000000"] .showcase-products__heading,
section.section.block-item[style*="--block-background: #222222"] .showcase-product__title,
section.section.block-item[style*="--block-background: #000000"] .showcase-product__title {
  color: #fff;
}
section.section.block-item[style*="--block-background: #222222"] .showcase-product__summary,
section.section.block-item[style*="--block-background: #000000"] .showcase-product__summary {
  color: rgb(255 255 255 / .7);
}

/* ==========================================================================
   GALLERY MOSAIC — _templates/elements/gallery/mosaic.php (Showcase Project 1.afdesign)

   One tall image beside a grid of smaller tiles: a 3-column grid whose FIRST tile spans two rows,
   with `dense` packing so the remaining tiles fill around it. That single rule holds for 2, 3, 5
   or 9 images without per-count templates. Row height is a fixed design length rather than a
   ratio so the tall tile is exactly two small tiles plus the gap, whatever the images' own shapes.
   Gap is the same two half-gaps as the showcase cards. Reached through the section_item_gallery
   element (and any gallery element that selects it), and the thumbnails lightbox styles already in
   this file (search .gallery-lightbox) do the viewer.
   ========================================================================== */

.gallery-mosaic__grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  grid-auto-rows: calc(560 * var(--u));
  grid-auto-flow: dense;
  gap: calc(2 * var(--block-elementsGapPx));
}

.gallery-mosaic__item {
  display: block;
  position: relative;
  overflow: hidden;
  background: var(--grey-light);
  line-height: 0;
}

.gallery-mosaic__item:first-child {
  grid-row: span 2;
}

.gallery-mosaic__item .image {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  margin: 0;
  border-radius: 0;
  line-height: 0;
}

.gallery-mosaic__item .image img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  transform: scale(1);
  transition: transform .8s cubic-bezier(.2,.8,.2,1);
}

.gallery-mosaic__item:hover .image img,
.gallery-mosaic__item:focus-visible .image img {
  transform: scale(1.04);
}

.gallery-mosaic__item:focus-visible {
  outline: calc(3 * var(--u)) solid var(--primary-colour);
  outline-offset: calc(8 * var(--u));
}

@media (max-width: 768px) {
  .gallery-mosaic__grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    grid-auto-rows: 38vw;
  }
}

/* ==========================================================================
   ELEMENTS: BRAND CAROUSEL — brand cards from the Brands section (1 Oct 2026)

   Renderer: _includes/_functions/elements/brand_carousel.php; card markup in
   _templates/elements/brands/card.php. One .column per brand, so inside a block with the Carousel
   setting on these are ordinary slides of the BLOCK CAROUSEL above — nothing here scrolls, snaps
   or sizes a slide.

   The card is the brand's card_image as a cover, at --element-image_ratio (default 0.716, the
   1500x2094 portrait of the original artwork), with the logo laid over it. The logo box is
   positioned by --element-logo_position (top / center / bottom, matched as a substring of the
   column's style attribute like --element-style) and capped two ways: --element-logo_width % of
   the card's width, and a height cap in container units, so a tall lockup and a wide wordmark read
   at a similar weight. Top/bottom inset 7% matches where the logos sat in the baked artwork.

   Focus ring is INSET: the carousel track is overflow-y: hidden (load-bearing, see BLOCK
   CAROUSEL), so an outline outside the card would be clipped.
   ========================================================================== */

section .brand-card {
  position: relative;
  display: block;
  aspect-ratio: var(--element-image_ratio, 0.716);
  overflow: hidden;
  border-radius: var(--border-radius);
  background: #222222;
  container-type: inline-size;
}

section .brand-card__media,
section .brand-card__media .image {
  position: absolute;
  inset: 0;
  margin: 0;
}

section .brand-card__media .image img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform .6s ease;
}

section .brand-card:hover .brand-card__media .image img,
section .brand-card:focus-visible .brand-card__media .image img {
  transform: scale(1.03);
}

section .brand-card:focus-visible {
  outline: calc(4 * var(--u)) solid var(--primary-colour);
  outline-offset: calc(-4 * var(--u));
}

section .brand-card__logo {
  position: absolute;
  left: 0;
  right: 0;
  top: 7%;
  z-index: 1;
  display: flex;
  justify-content: center;
  pointer-events: none;
}

section .element-brand_carousel[style*="--element-logo_position: center"] .brand-card__logo {
  top: 50%;
  transform: translateY(-50%);
}

section .element-brand_carousel[style*="--element-logo_position: bottom"] .brand-card__logo {
  top: auto;
  bottom: 7%;
}

section .brand-card__logo img {
  display: block;
  width: auto;
  height: auto;
  max-width: calc(var(--element-logo_width, 78) * 1%);
  max-height: 14cqw;
}

/* No logo uploaded yet: the name, as a black lockup like the baked artwork's Hyline badge. */
section .brand-card__name {
  display: inline-block;
  max-width: calc(var(--element-logo_width, 60) * 1%);
  padding: 0.35em 0.9em;
  background: rgba(0, 0, 0, 0.88);
  color: #ffffff;
  font-family: var(--heading-font);
  font-size: calc(44 * var(--ut));
  line-height: 1.1;
  letter-spacing: 0.08em;
  text-align: center;
  text-transform: uppercase;
}

/* ==========================================================================
   EDITOR UNDERLINE — the TinyMCE Underline button (cms/assets/js/admin.js, search UNDERLINE GOES
   ON THE INNERMOST ELEMENT) writes an inline `text-decoration: underline`. That shorthand resets
   style and thickness to solid / auto at inline-style strength, so these need !important to win.
   text-underline-offset is not part of the shorthand, but is kept here with the rest. This file
   is also in the editor's content_css, so the editor shows the same line.
   ========================================================================== */
[style*="text-decoration: underline"],
u {
  text-decoration-thickness: 1px !important;
  text-decoration-style: dotted !important;
  text-underline-offset: 3px;
}

/* ==========================================================================
   ELEMENTS: PRODUCT BROWSER — /products (2 Oct 2026)

   Renderer: _includes/_functions/elements/product_browser.php; markup
   _templates/elements/products/browser.php; behaviour assets/js/product-browser.js.

   A filter column beside a grid of the shared "In the Scene" product cards (the IN THE SCENE rules
   above style the card itself; only the image box ratio and its grey surface are set here). Laid
   out after the reference retailer listing Dan supplied — heading and intro, then grouped checkbox
   filters with counts on the left, a product count over the grid on the right — in this site's
   type: small-caps heading face for the heading and group labels, the body face for options.

   Columns from --element-columns (2/3/4, default 3), image ratio from --element-image_ratio
   (default 1.25). Column gap is the block's two half-gaps, the same gutter as the showcase grid.
   Desktop only for now: no responsive rules until the mobile design exists.
   ========================================================================== */

.product-browser {
  --showcase-products-ratio: var(--element-image_ratio, 1.25);
  display: grid;
  grid-template-columns: calc(480 * var(--u)) minmax(0, 1fr);
  gap: calc(126 * var(--u));
  align-items: start;
  line-height: normal;
}

.product-browser__heading {
  margin: 0 0 calc(42 * var(--u));
  color: var(--heading-colour);
  font-family: var(--heading-font), sans-serif;
  font-weight: var(--heading-weight);
  font-size: calc(52 * var(--ut));
  line-height: 1.15;
  letter-spacing: .12em;
  text-transform: uppercase;
}

.product-browser__intro {
  margin-bottom: calc(63 * var(--u));
  color: var(--grey-dark);
  font-size: calc(24 * var(--ut));
  line-height: 1.6;
}

.product-browser__selected {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  padding-bottom: calc(30 * var(--u));
  border-bottom: 1px solid var(--grey-light);
  font-size: calc(22 * var(--ut));
}
.product-browser__selected[hidden] { display: none; }

.product-browser__clear {
  color: var(--grey-dark);
  text-decoration: underline;
  text-underline-offset: 3px;
}
.product-browser__clear:hover { color: var(--body-colour); }

.product-browser__group {
  margin: 0;
  padding: calc(42 * var(--u)) 0;
  border: 0;
  border-bottom: 1px solid var(--grey-light);
  min-width: 0;
}

.product-browser__legend {
  float: left;   /* a legend ignores the fieldset's padding otherwise; float makes it a normal box */
  width: 100%;
  margin-bottom: calc(24 * var(--u));
  padding: 0;
  color: var(--heading-colour);
  font-family: var(--heading-font), sans-serif;
  font-weight: var(--heading-weight);
  font-size: calc(22 * var(--ut));
  letter-spacing: .18em;
  text-transform: uppercase;
}

.product-browser__option {
  clear: left;
  display: flex;
  align-items: center;
  gap: calc(16 * var(--u));
  padding: calc(8 * var(--u)) 0;
  font-size: calc(24 * var(--ut));
  cursor: pointer;
}

.product-browser__option input {
  appearance: none;
  -webkit-appearance: none;
  flex: 0 0 auto;
  width: calc(26 * var(--u));
  height: calc(26 * var(--u));
  margin: 0;
  border: 1px solid var(--body-colour);
  border-radius: 0;
  background: #fff;
  cursor: pointer;
}
.product-browser__option input:checked {
  background: var(--body-colour);
  box-shadow: inset 0 0 0 calc(5 * var(--u)) #fff;
}
.product-browser__option input:focus-visible {
  outline: 2px solid var(--body-colour);
  outline-offset: 2px;
}

.product-browser__count { color: var(--grey-dark); }

.product-browser__option.is-disabled { cursor: default; opacity: .4; }
.product-browser__option.is-disabled input { cursor: default; }

.product-browser__apply { margin-top: calc(42 * var(--u)); }
.product-browser__apply[hidden] { display: none; }
.product-browser__show { display: none; }   /* phones only, see responsive.css */

.product-browser__total {
  margin: 0 0 calc(42 * var(--u));
  color: var(--grey-dark);
  font-size: calc(22 * var(--ut));
}

.product-browser__grid {
  display: grid;
  grid-template-columns: repeat(var(--element-columns, 3), minmax(0, 1fr));
  column-gap: calc(1 * var(--block-elementsGapPx));
  row-gap: calc(64 * var(--u));
}

.product-browser__item[hidden] { display: none; }

/* The retailer reference sits its products on a light grey box, and with no product images
   uploaded yet the placeholder is that same box. */
.product-browser .showcase-product__media {
  background: var(--grey-light);
}

.product-browser__empty {
  font-size: calc(24 * var(--ut));
  color: var(--grey-dark);
}
.product-browser__empty[hidden] { display: none; }
