/* ==========================================================================
   VMFRP Project page template
   Layout, spacing and background colours only.
   Typography is inherited from Enfold.
   ========================================================================== */

:root {
  /* Brand colours */
  --vmfrp-deep-teal: #006f62;
  --vmfrp-blue: #005e80;
  --vmfrp-light-teal: #a6cfc9;
  --vmfrp-light-blue: oklch(
    0.88 0.046 232
  ); /* light blue analogue of --vmfrp-light-teal; used on completed projects */
  --vmfrp-light-grey: #f0f0f0;
  --vmfrp-white: #ffffff;
  --vmfrp-orange: #e87822; /* used sparingly, accent only (decorative) */
  --vmfrp-burnt-orange: oklch(
    0.55 0.165 52.08
  ); /* darker shade of --vmfrp-orange tuned for legible white-text contrast on the Announcement block. Tweak the L value to dial: lower = more contrast / darker, higher = closer to brand original. Hue + chroma kept identical to brand orange so the family relationship reads. */
  --vmfrp-pale-blue: #b9d3dc; /* borders, soft accents */

  /* Project-status adaptive colours. Use these — not --vmfrp-deep-teal /
     --vmfrp-light-teal — wherever a colour should automatically switch
     between active (teal) and completed (blue) projects. The
     body.project-completed rule resolves them to the blue palette. */
  --vmfrp-project-dark: #006f62;
  --vmfrp-project-light: #a6cfc9;

  /* Typography (inherits from Enfold for layout/family; tokens here
     own the colour palette so the project pages don't drift back into
     Enfold's hardcoded green/blue mix). */
  --vmfrp-text-default: #2c4542; /* Body copy on light surfaces */
  --vmfrp-text-muted: #6b6b6b;
  --vmfrp-text-heading: var(
    --vmfrp-project-dark
  ); /* h1–h6 inside project content; follows project status colour so active = teal, completed = blue. */

  /* Quiet surface + border for framed media units (Map, etc.) */
  --vmfrp-surface-subtle: #fafafa;
  --vmfrp-border-subtle: #e5e5e5;

  /* Layout */
  --vmfrp-content-max: 1180px;
  --vmfrp-content-width: 85%;
  --vmfrp-toc-width: 240px;
  --vmfrp-gap: 2rem;
  --vmfrp-header-offset: 100px; /* Enfold sticky header — clearance for anchor targets and sticky ToC */

  /* Hero — mobile hero fills the full small-viewport height minus
       Enfold's 80px mobile nav, for an editorial takes-over-the-screen
       feel. svh (small viewport height) chosen so iOS chrome collapse
       doesn't jank the layout. */
  --vmfrp-hero-min-height: 60vh;
  --vmfrp-hero-min-height-mobile: calc(100svh - 80px);
  /* Hero text-box background — translucent dark teal so legibility
       holds against any featured image without per-project tuning. */
  --vmfrp-hero-box-bg: oklch(0.15 0.05 176.07 / 0.75);
  /* Atmospheric bottom-up gradient sitting between image and box.
       The box owns text contrast; this just adds mood and ties the
       image to the page edge. Inline override per-project from the
       ACF Hero Settings range field; this :root value is the fallback. */
  --vmfrp-hero-overlay-strength: 25%;

  /* Spacing scale (8px base) */
  --vmfrp-space-1: 0.5rem;
  --vmfrp-space-2: 1rem;
  --vmfrp-space-3: 1.5rem;
  --vmfrp-space-4: 2rem;
  --vmfrp-space-6: 3rem;
  --vmfrp-space-8: 4rem;

  /* Inter-block gap. Used as both the positive margin between
       different-bg blocks AND the negative margin that collapses
       same-bg adjacents into one merged area. Single token = the two
       cases stay symmetrical when tuned. */
  --vmfrp-content-gap: var(--vmfrp-space-4);
}

/* Sticky-context fix: Enfold sets overflow:hidden on #wrap_all and
   overflow:hidden auto on body, both of which become scroll containers
   that descendant position:sticky elements try to track. Body never
   actually scrolls (real scroll is on html), so the ToC never sticks.
   Override both on project pages, using overflow-x:clip on body to
   preserve horizontal-bleed clipping without promoting body to a
   scroll container.
   ========================================================================== */

body.single-project,
body.page-template-template-flex-page {
  overflow-x: clip;
  overflow-y: visible;
}

body.single-project #wrap_all,
body.page-template-template-flex-page #wrap_all {
  overflow: visible;
}

body.project-completed {
  --vmfrp-project-dark: #005e80;
  --vmfrp-project-light: oklch(0.88 0.046 232);
  --vmfrp-hero-box-bg: oklch(0.15 0.05 232 / 0.75);
}

/* Hero — featured image, title, lede. Sits above the page-layout grid.
   ========================================================================== */

.vmfrp-hero {
  position: relative;
  overflow: hidden;
  min-height: var(--vmfrp-hero-min-height);
  display: flex;
  align-items: flex-end;
  color: var(--vmfrp-white);
}

.vmfrp-hero--no-image {
  background: var(--vmfrp-project-dark);
}

.vmfrp-hero__image {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  z-index: 0;
}

/* Bottom-up atmospheric gradient. Sits on top of the image, beneath
   the text box. Five weighted stops give a perceptually smooth
   dark-to-clear transition; flat 2-stop gradients look muddy through
   the mid-tones because alpha interpolation isn't gamma-aware.
   Strength is driven by --vmfrp-hero-overlay-strength, set inline on
   .vmfrp-hero from the ACF range field. */
.vmfrp-hero__overlay {
  position: absolute;
  inset: 0;
  background: linear-gradient(
    to top,
    rgb(0 0 0 / var(--vmfrp-hero-overlay-strength)) 0%,
    rgb(0 0 0 / calc(var(--vmfrp-hero-overlay-strength) * 0.85)) 12%,
    rgb(0 0 0 / calc(var(--vmfrp-hero-overlay-strength) * 0.55)) 32%,
    rgb(0 0 0 / calc(var(--vmfrp-hero-overlay-strength) * 0.25)) 60%,
    rgb(0 0 0 / 0) 100%
  );
  z-index: 1;
}

/* Container handles the centering and content-width constraint —
   keeps the box positioned correctly within the page layout. */
.vmfrp-hero__container {
  position: relative;
  z-index: 2;
  width: var(--vmfrp-content-width);
  max-width: var(--vmfrp-content-max);
  margin-inline: auto;
  padding-block: var(--vmfrp-space-6);
}

/* The box itself: translucent dark-teal panel that owns text
   contrast against any featured image. width:fit-content +
   max-width:100% sizes the panel to its natural content while
   never overflowing the container. */
.vmfrp-hero__inner {
  background-color: var(--vmfrp-hero-box-bg);
  padding-block: var(--vmfrp-space-6);
  padding-inline: var(--vmfrp-space-4);
  width: fit-content;
  max-width: 100%;
}

@media (max-width: 768px) {
  /* Mobile: edge-to-edge box flush with the bottom of the viewport.
       Container drops its width constraint and bottom padding so the
       box can run the full width and sit flush. align-items:flex-end
       on .vmfrp-hero already places the container at the bottom. */
  .vmfrp-hero__container {
    width: 100%;
    max-width: none;
    padding-block-end: 0;
  }

  .vmfrp-hero__inner {
    width: 100%;
    max-width: none;
  }
}

/* Hero typography — minimal class-scoped overrides over Enfold's defaults.
   Font-sizes are inherited (Enfold's H1 and P sizes carry the right
   weight inside the box). We just tighten the title's line-height and
   tracking, constrain reading widths, and add a structural underline
   beneath the title for editorial anchoring. */

.vmfrp-hero__title {
  line-height: 1;
  letter-spacing: -0.01em;
  max-width: 18ch;
  border-block-end: 1px solid var(--vmfrp-white);
  padding-block-end: 18px;
}

.vmfrp-hero__lede {
  margin-block-start: var(--vmfrp-space-2);
  line-height: 1.5;
  max-width: 50ch;

  a {
    color: var(--vmfrp-white);
    text-decoration: underline;
  }
}

@media (max-width: 768px) {
  .vmfrp-hero__lede {
    line-height: 1.4;
  }
}

@media (max-width: 768px) {
  .vmfrp-hero {
    min-height: var(--vmfrp-hero-min-height-mobile);
  }
}

/* Page layout: ToC + content
   ========================================================================== */

.vmfrp-page-layout {
  display: grid;
  grid-template-columns: var(--vmfrp-toc-width) 1fr;
  gap: var(--vmfrp-gap);
  width: var(--vmfrp-content-width);
  max-width: var(--vmfrp-content-max);
  margin-inline: auto;
  padding-block: var(--vmfrp-space-6);
}

.vmfrp-toc {
  position: sticky;
  top: calc(var(--vmfrp-header-offset) + var(--vmfrp-space-4));
  align-self: start;
}

.vmfrp-toc__list {
  list-style: none;
  padding-inline-start: 0;
  margin-inline-start: 0;
  margin-block: 0;
  display: flex;
  flex-direction: column;
}

.vmfrp-toc__link {
  display: block;
  padding-block: var(--vmfrp-space-1);
  padding-inline-start: var(--vmfrp-space-2);
  border-inline-start: 2px solid transparent;
}

/* Suppress :visited differentiation — body text colour for both states.
   Active section is marked by the inline-start border below. */
.vmfrp-toc__link,
.vmfrp-toc__link:visited {
  /* Body paragraph colour rather than `inherit`, so the ToC stays
     consistent regardless of where it's rendered or what Enfold has
     set on the surrounding context. */
  color: var(--vmfrp-text-default);
}

.vmfrp-toc__link[aria-current="true"] {
  border-inline-start-color: var(--vmfrp-project-dark);
  color: var(--vmfrp-project-dark);
  font-weight: 700;
}

/* Hover and focus: bold weight only, no underline, no colour change.
   Distinct from the active state (which also adds the teal colour),
   so the current-section indication still reads clearly while the
   user hovers other links. */
.vmfrp-toc__link:hover,
.vmfrp-toc__link:focus {
  font-weight: 700;
  text-decoration: none;
}

/* Suppress Enfold's mouse-click focus outline (the persistent
   "underline that won't go away" after clicking a link). */
.vmfrp-toc__link:focus {
  outline: none;
}

/* Keyboard focus: keep a visible accessibility ring. */
.vmfrp-toc__link:focus-visible {
  outline: 2px solid var(--vmfrp-project-dark);
  outline-offset: 2px;
}

/* Anchor scroll-target offset so headings don't slip under the sticky header. */
.vmfrp-block[id] {
  scroll-margin-top: var(--vmfrp-header-offset);
}

.vmfrp-blocks {
  min-width: 0; /* allow grid child to shrink below content size */
  display: flex;
  flex-direction: column;
}

@media (max-width: 768px) {
  .vmfrp-page-layout {
    grid-template-columns: 1fr;
    width: 100%;
    padding-inline: var(--vmfrp-space-3);
  }

  .vmfrp-toc {
    display: none;
  }
}

/* Block shell — used by every block partial
   ========================================================================== */

.vmfrp-block {
}

.vmfrp-block__inner {
  padding-block: var(--vmfrp-space-8);
  padding-inline: var(--vmfrp-space-4);
}

/* Inter-block separation: each block past the first gets a positive
   margin equal to --vmfrp-content-gap. That gap shows the page bg
   behind .vmfrp-blocks, so adjacent different-bg sections never
   crash their colours into a hard transition line. */
.vmfrp-block + .vmfrp-block {
  margin-block-start: var(--vmfrp-content-gap);
}

/* Same-bg adjacents merge into one continuous coloured area:
   – Negative margin equal to --vmfrp-content-gap pulls the second
     block up by the same distance the default pushes it down, so
     the two sections overlap rather than abut. The overlap is two
     same-coloured backgrounds, so it's visually invisible.
   – Zero inner padding-block-start removes the second block's top
     content padding so the merged area reads with normal content
     rhythm rather than 8rem of padded bg between content.
   – Image blocks are excluded as the *preceding* block: the image
     extends to the block's bottom edge, so the next block would
     slide under the image/caption rather than under invisible bg. */
.vmfrp-block[data-bg="white"]:not(.vmfrp-block--image)
  + .vmfrp-block[data-bg="white"],
.vmfrp-block[data-bg="light_grey"]:not(.vmfrp-block--image)
  + .vmfrp-block[data-bg="light_grey"],
.vmfrp-block[data-bg="light_teal"]:not(.vmfrp-block--image)
  + .vmfrp-block[data-bg="light_teal"],
.vmfrp-block[data-bg="light_blue"]:not(.vmfrp-block--image)
  + .vmfrp-block[data-bg="light_blue"],
.vmfrp-block[data-bg="project_light"]:not(.vmfrp-block--image)
  + .vmfrp-block[data-bg="project_light"],
.vmfrp-block[data-bg="deep_teal"]:not(.vmfrp-block--image)
  + .vmfrp-block[data-bg="deep_teal"],
.vmfrp-block[data-bg="project_dark"]:not(.vmfrp-block--image)
  + .vmfrp-block[data-bg="project_dark"],
.vmfrp-block[data-bg="burnt_orange"]:not(.vmfrp-block--image)
  + .vmfrp-block[data-bg="burnt_orange"] {
  margin-block-start: calc(var(--vmfrp-content-gap) * -1);
}

.vmfrp-block[data-bg="white"]:not(.vmfrp-block--image)
  + .vmfrp-block[data-bg="white"]
  > .vmfrp-block__inner,
.vmfrp-block[data-bg="light_grey"]:not(.vmfrp-block--image)
  + .vmfrp-block[data-bg="light_grey"]
  > .vmfrp-block__inner,
.vmfrp-block[data-bg="light_teal"]:not(.vmfrp-block--image)
  + .vmfrp-block[data-bg="light_teal"]
  > .vmfrp-block__inner,
.vmfrp-block[data-bg="light_blue"]:not(.vmfrp-block--image)
  + .vmfrp-block[data-bg="light_blue"]
  > .vmfrp-block__inner,
.vmfrp-block[data-bg="project_light"]:not(.vmfrp-block--image)
  + .vmfrp-block[data-bg="project_light"]
  > .vmfrp-block__inner,
.vmfrp-block[data-bg="deep_teal"]:not(.vmfrp-block--image)
  + .vmfrp-block[data-bg="deep_teal"]
  > .vmfrp-block__inner,
.vmfrp-block[data-bg="project_dark"]:not(.vmfrp-block--image)
  + .vmfrp-block[data-bg="project_dark"]
  > .vmfrp-block__inner,
.vmfrp-block[data-bg="burnt_orange"]:not(.vmfrp-block--image)
  + .vmfrp-block[data-bg="burnt_orange"]
  > .vmfrp-block__inner {
  padding-block-start: 0;
}

/* Keep-spacing override. Editor-set per-block flag (vmfrp_keep_spacing
   in ACF) forces full inter-block spacing even when adjacent same-bg
   neighbours would otherwise merge.

   The flag works on either side of the pair: setting it on the upper
   block ("don't let the next one pull up into me") or the lower block
   ("don't pull me up into the previous") both restore the visible gap.
   Either way we adjust the *second* block, since the merge originally
   operated on its margin-top + inner padding-top.

   Specificity: the merge selectors above are (0,4,0)/(0,5,0). These
   overrides land at (0,5,0)/(0,6,0) by adding the data-keep-spacing
   attribute to one side, so they win without source-order discipline. */
.vmfrp-block[data-bg][data-keep-spacing] + .vmfrp-block[data-bg],
.vmfrp-block[data-bg] + .vmfrp-block[data-bg][data-keep-spacing] {
  margin-block-start: var(--vmfrp-content-gap);
}

.vmfrp-block[data-bg][data-keep-spacing]
  + .vmfrp-block[data-bg]
  > .vmfrp-block__inner,
.vmfrp-block[data-bg]
  + .vmfrp-block[data-bg][data-keep-spacing]
  > .vmfrp-block__inner {
  padding-block-start: var(--vmfrp-space-8);
}

/* First block on the page: drop the top inner padding so its heading
   aligns with the ToC's first link on the same vertical plane. The
   page-layout's own padding-block keeps breathing room above.

   Scoped to data-bg="white" only — when the first block has any other
   bg, its heading sits inside a visible coloured box, and zeroing the
   top padding crashes the heading against the box edge. The default
   --vmfrp-space-8 padding is what gives the heading room to breathe
   inside the colour. */
.vmfrp-blocks
  > .vmfrp-block:first-child[data-bg="white"]
  > .vmfrp-block__inner {
  padding-block-start: 0;
}

.vmfrp-block__sub-headline {
  margin-block-start: var(--vmfrp-space-1);
  font-size: 0.875rem;
  /* Inherit colour from the section (set by data-bg) and dim with
     opacity, same pattern as captions and download meta. Self-adapts:
     muted grey on light surfaces, muted white on deep teal. Hard-coding
     --vmfrp-text-muted (a literal grey) made the sub-headline disappear
     against deep_teal because dark grey on dark teal has almost no
     contrast. */
  color: inherit;
  opacity: 0.7;
}

.vmfrp-block__description {
  margin-block-start: var(--vmfrp-space-3);
}

/* WYSIWYG-authored lists inside rich-text descriptions. Enfold's
   global content styles strip list-style and indentation from <ul>
   and <ol>, so editor-pasted bulleted/numbered lists render as
   indented paragraphs without markers. Restore the standard browser
   list rendering here, scoped to the rich-text containers so it
   doesn't leak into the framework's own list components (slider
   dots, ToC, cards grid, etc., all of which deliberately strip
   markers). Specificity (0,2,1) defeats Enfold's typical (0,1,1)
   without resorting to !important. */
.vmfrp-block__description ul,
.vmfrp-card__description ul {
  list-style: disc;
  padding-inline-start: 1.5em;
  margin-block: var(--vmfrp-space-2);
}

.vmfrp-block__description ol,
.vmfrp-card__description ol {
  list-style: decimal;
  padding-inline-start: 1.5em;
  margin-block: var(--vmfrp-space-2);
}

.vmfrp-block__description li,
.vmfrp-card__description li {
  margin-block-start: 0.25em;
  /* Override Enfold's `.entry-content-wrapper li { margin-left: 1em }`
       — the indentation lives on the list's padding-inline-start, so
       the bullet sits in the gutter rather than getting pushed off. */
  margin-inline-start: 0;
}

/* Editor-added links inside rich-text content. Inherit the section's
   text colour and use a persistent underline rather than Enfold's
   colour-shift convention — links need to stand out reliably across
   every data-bg surface (a blue link on deep teal clashes; an
   underlined inherit-colour link reads correctly anywhere). The
   :visited override drops Enfold's purple-visited-link styling in
   favour of flat colour, which is more appropriate for ongoing
   project communication where a returning reader shouldn't see
   "you've already read this" markers on every reference. */
.vmfrp-block__description a,
.vmfrp-block__description a:visited,
.vmfrp-card__description a,
.vmfrp-card__description a:visited,
.vmfrp-faq__answer a,
.vmfrp-faq__answer a:visited,
.vmfrp-announcement__description a,
.vmfrp-announcement__description a:visited {
  color: inherit;
  text-decoration: underline;
}

/* Keyboard focus ring uses currentColor so it inherits the section's
   contrast — visible on light surfaces (dark ring) and dark surfaces
   (light ring) without per-palette overrides. */
.vmfrp-block__description a:focus-visible,
.vmfrp-card__description a:focus-visible,
.vmfrp-faq__answer a:focus-visible,
.vmfrp-announcement__description a:focus-visible {
  outline: 2px solid currentColor;
  outline-offset: 2px;
}

/* Backgrounds (data attribute, not modifier — changes too often).
   Reusable: applies to blocks AND cards.
   ========================================================================== */

/* Every background sets its own text colour so a deep-teal section
   containing a light-teal card (or any other combo) reads correctly
   instead of inheriting whatever the parent decided. */
[data-bg="white"] {
  background: var(--vmfrp-white);
  color: var(--vmfrp-text-default);
}
[data-bg="light_grey"] {
  background: var(--vmfrp-light-grey);
  color: var(--vmfrp-text-default);
}
[data-bg="light_teal"] {
  background: var(--vmfrp-light-teal);
  color: var(--vmfrp-text-default);
}
[data-bg="light_blue"] {
  background: var(--vmfrp-light-blue);
  color: var(--vmfrp-text-default);
}
[data-bg="project_light"] {
  background: var(--vmfrp-project-light);
  color: var(--vmfrp-text-default);
}
[data-bg="deep_teal"] {
  background: var(--vmfrp-deep-teal);
  color: var(--vmfrp-white);
}
[data-bg="project_dark"] {
  background: var(--vmfrp-project-dark);
  color: var(--vmfrp-white);
}
[data-bg="burnt_orange"] {
  background: var(--vmfrp-burnt-orange);
  color: var(--vmfrp-white);
}

/* Heading colour. Scoped to the project-page surface containers so it
   doesn't bleed into the hero (white-on-image) or any future
   non-project usage. Enfold ships its own (incorrect) heading colour
   on the host site; this rule overrides it. Sits at .vmfrp-block
   specificity so it beats Enfold's class-scoped declarations.

   The deep-teal override below uses `[data-bg="deep_teal"]` (without
   `.vmfrp-block` scope) so it catches *any* deep-teal surface — most
   importantly nested ones like a deep-teal Card sitting inside a
   light-teal block, where a teal-on-teal headline would be invisible
   otherwise. `color: inherit` pulls the immediate surface's text
   colour (white on deep teal, dark on light), so the rule self-tunes
   to whatever the closest data-bg ancestor sets. */
.vmfrp-block :is(h1, h2, h3, h4, h5, h6),
.vmfrp-recent :is(h1, h2, h3, h4, h5, h6),
.vmfrp-contact :is(h1, h2, h3, h4, h5, h6) {
  color: var(--vmfrp-project-dark);
}

[data-bg="deep_teal"] :is(h1, h2, h3, h4, h5, h6),
[data-bg="project_dark"] :is(h1, h2, h3, h4, h5, h6),
[data-bg="burnt_orange"] :is(h1, h2, h3, h4, h5, h6) {
  color: inherit;
}

/* Announcement block — compact callout for time-sensitive notices
   ==========================================================================
   Asymmetric composition: icon top-left as the "this is a notice"
   anchor, date top-right as metadata, headline + body left-aligned
   and packed below. Tighter inner padding than other blocks because
   compactness is the urgency signal — fat padding reads as leisurely
   content. Section emits no id, so the ToC skips it. */

.vmfrp-block--announcement > .vmfrp-block__inner {
  /* Override the standard inner padding (--vmfrp-space-8 block,
     --vmfrp-space-4 inline). The announcement is sized to read like
     a notice strip rather than a content section — tight padding all
     round, slightly smaller body type, tighter line-height. */
  padding-block: var(--vmfrp-space-2);
  padding-inline: var(--vmfrp-space-2);
  font-size: 90%;
  line-height: 1.4;
}

/* First-block-on-page announcements pull the next block up by one
   content-gap, so the announcement reads as a header strip introducing
   the page rather than a standalone box with a full gap below. Mid-
   page announcements keep their normal bottom spacing — the strip
   treatment is reserved for top-of-page intros. */
.vmfrp-blocks > .vmfrp-block--announcement:first-child {
  margin-block-end: calc(var(--vmfrp-content-gap) * -1);
}

.vmfrp-announcement__head {
  display: flex;
  align-items: center;
  gap: var(--vmfrp-space-2);
  margin-block-end: var(--vmfrp-space-2);
}

.vmfrp-announcement__icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 32px;
  height: 32px;
  /* flex-shrink: 0 so a long date in the right slot can never squeeze
     the icon out of the row. */
  flex-shrink: 0;
}

.vmfrp-announcement__icon svg {
  display: block;
  width: 100%;
  height: 100%;
  /* stroke=currentColor on the SVG ties the icon's stroke to whatever
     the section's text colour is — white on deep teal / burnt orange,
     dark on light surfaces — so the icon recolours per data-bg
     automatically with no per-palette overrides. */
}

.vmfrp-announcement__date {
  font-size: 0.875rem;
  /* Inherit + opacity dims the date as metadata, mirroring the
     captions / sub-headline / download-meta pattern. Self-tunes to
     the data-bg's text colour. */
  color: inherit;
  opacity: 0.75;
  /* margin-inline-start: auto pushes the date to the right edge
     whether the icon is present or not. With justify-content default
     (start) and this margin, layout works for icon+date, date-only,
     and icon-only without per-case overrides. */
  margin-inline-start: auto;
}

/* h2.vmfrp-announcement__headline (element + class) lifts specificity
   to (0,2,1), one notch above Enfold's class-scoped h2 declarations,
   so the smaller font-size lands without !important. */
h2.vmfrp-announcement__headline {
  /* Reset Enfold's default H2 margin so the head row above and the
     description below sit tight against the headline. The inner's
     own padding gives the outer breathing room. */
  margin: 0;
  /* Smaller than Enfold's default h2 — the announcement is a notice
     strip, not a section heading; the headline reads as a label. */
  font-size: 22px;
}

.vmfrp-announcement__description {
  margin-block-start: var(--vmfrp-space-2);
  /* 80ch is roomy for left-aligned body text — readers can scan
     comfortably without the eye-return problem that affects centred
     text at the same width. Wider than the centred 60ch we'd use
     for a centred composition. */
  max-width: 80ch;
}

/* Image / Slider block — image renders edge-to-edge inside the block's
   background, single image or slider. Direct-descendant selectors keep
   images embedded inside a WYSIWYG description untouched.
   ========================================================================== */

/* Tighten the heading-to-image gap. The image lives outside .__inner,
   so the inner's bottom padding becomes the only thing between the
   heading and the image — at the default --vmfrp-space-8 it reads as
   a disconnected gap. Drop it almost to zero so the heading reads as
   the image's title rather than a separate paragraph above it. */
.vmfrp-block--image .vmfrp-block__inner {
  padding-block-end: var(--vmfrp-space-3);

  &:has(p) {
    padding-block-end: var(--vmfrp-space-6);
  }
}

.vmfrp-block--image .vmfrp-image-link {
  display: block;
  /* Position context for the corner zoom badge. */
  position: relative;
  cursor: pointer;
  /* Button reset — the element is a <button> so it can be a
       lightbox trigger without an href that competes with our click
       handler. Strip every default that would otherwise leak through:
       background, border, padding, font, alignment. */
  appearance: none;
  background: transparent;
  border: 0;
  padding: 0;
  margin: 0;
  width: 100%;
  color: inherit;
  font: inherit;
  text-align: inherit;
  line-height: 0;
}

.vmfrp-block--image .vmfrp-image-link__img {
  display: block;
  width: 100%;
  height: auto;
  /* Disable the browser's native image-drag affordance. Without this,
       click-and-hold-drag on the image becomes a drag-and-drop, which
       suppresses subsequent mousemove events and breaks our drag-to-
       scroll handler — the same gotcha as the recent-projects carousel.
       pointer-events: none is the second half: it routes clicks through
       to the parent <a> instead of the <img>, so the lightbox handler
       fires reliably regardless of where on the image the user clicks. */
  -webkit-user-drag: none;
  pointer-events: none;
}

/* Subtle "click to enlarge" affordance — small magnifying glass chip
   in the top-right corner. Always visible on touch (no hover state to
   reveal it), fades in on hover for pointer users. Lucide search icon
   inlined inside.

   Sits inside the link with pointer-events: none so it doesn't steal
   clicks from the link itself. */
.vmfrp-image-link__zoom {
  position: absolute;
  top: var(--vmfrp-space-1);
  right: var(--vmfrp-space-1);
  width: 32px;
  height: 32px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: rgba(0, 0, 0, 0.55);
  color: var(--vmfrp-white);
  pointer-events: none;
  /* Fully visible by default — touch devices have no hover so the
       affordance must always be on screen. The hover-revealing behaviour
       is layered on inside @media (hover: hover) below. */
  opacity: 0.85;
  transition:
    opacity 200ms ease,
    background 200ms ease;
}

.vmfrp-image-link__zoom svg {
  display: block;
}

@media (hover: hover) {
  .vmfrp-image-link__zoom {
    opacity: 0;
  }
  .vmfrp-image-link:hover .vmfrp-image-link__zoom,
  .vmfrp-image-link:focus-visible .vmfrp-image-link__zoom {
    opacity: 1;
  }
}

/* Caption beneath a single (non-slider) image. Sits inside the section's
   background, lightly indented to match the inner content rhythm so a
   long caption doesn't bleed to the section edge. */
.vmfrp-image-caption {
  width: var(--vmfrp-content-width);
  max-width: var(--vmfrp-content-max);
  margin: var(--vmfrp-space-2) auto 0;
  font-size: 0.875rem;
  /* Inherit colour from the section so captions stay legible across
       all data-bg palettes (dark caption on light bg, light caption on
       deep teal); opacity gives the muted feel without locking a hue. */
  color: inherit;
  opacity: 0.7;
  text-align: center;
}

/* Slider — used when the Image block has 2+ images. CSS scroll-snap
   gives free swipe support on touch and a solid keyboard/mouse story
   via the JS-driven arrows + dots; auto-advance lives in JS too.
   ========================================================================== */

.vmfrp-slider {
  position: relative;
}

.vmfrp-slider__viewport {
  overflow: hidden;
}

.vmfrp-slider__track {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  /* flex-start so each slide takes its natural content height
       (rather than stretching to row max). The viewport's JS-managed
       height clips the row at the active slide's height — short slides
       no longer leave huge whitespace when a tall slide exists in the
       same set. */
  align-items: flex-start;
  overflow-x: auto;
  /* Explicit overflow-y: hidden — overflow-x: auto silently flips
       overflow-y to auto in some browsers, which would let the track
       grow a vertical scrollbar when the row is taller than viewport. */
  overflow-y: hidden;
  scroll-snap-type: x mandatory;
  scrollbar-width: none;
}

.vmfrp-slider__track::-webkit-scrollbar {
  display: none;
}

@media (hover: hover) {
  /* Desktop drag-to-scroll affordance — matches the recent-projects
       carousel. Touch devices skip this; native swipe via scroll-snap
       is the gesture there. */
  .vmfrp-slider__track {
    cursor: grab;
  }
  .vmfrp-slider__track.is-dragging,
  .vmfrp-slider__track.is-dragging .vmfrp-image-link {
    cursor: grabbing;
  }
}

.vmfrp-slider__slide {
  flex: 0 0 100%;
  scroll-snap-align: start;
  /* Padding is intentionally zero — the image (and only the image)
       fills the slide width edge-to-edge, matching the single-image
       variant's bleed treatment. */
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  /* min-width: 0 lets the slide shrink below the natural width of the
       <img> on narrow viewports, otherwise the track overshoots and
       horizontal scroll appears outside scroll-snap control. */
  min-width: 0;
}

/* Slider images are pinned to a uniform 16/9 frame with object-fit:
   cover so a set of mixed-aspect uploads reads as a tidy series rather
   than a stack of unrelated rectangles. Cropping is the deliberate
   trade-off — editors should pick crops that preserve the subject. */
.vmfrp-slider__slide .vmfrp-image-link__img {
  aspect-ratio: 16 / 9;
  object-fit: cover;
}

/* Arrows + dots share a single row beneath the image. The whole strip
   sits centred under the slider; arrows are flat outline buttons,
   dots are 10px circles. No absolute positioning — the row is a
   normal flex container so the rhythm with the image above and the
   caption below is set by simple block flow.
   ========================================================================== */

.vmfrp-slider__controls {
  display: flex;
  align-items: center;
  /* space-between pushes the prev arrow to the left edge and the next
       arrow to the right edge, with the dots floating in the middle —
       the arrows visually frame the dots. Inline padding inset matches
       the surrounding inner padding so the arrows don't crash into the
       section edge. */
  justify-content: space-between;
  gap: var(--vmfrp-space-2);
  margin-block-start: var(--vmfrp-space-2);
  /* padding-inline: var(--vmfrp-space-4); */
}

.vmfrp-slider__arrow {
  appearance: none;
  background: transparent;
  /* currentColor inherits from the section's data-bg-driven text
       colour — dark on light backgrounds, white on deep-teal — so the
       arrow always has contrast without per-palette overrides. */
  border: 1px solid currentColor;
  color: inherit;
  width: 36px;
  height: 36px;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: 0 0 auto;
  opacity: 0.55;
  transition: opacity 150ms ease;
}

.vmfrp-slider__arrow:hover {
  opacity: 1;
}

.vmfrp-slider__arrow:focus-visible {
  outline: 2px solid currentColor;
  outline-offset: 2px;
  opacity: 1;
}

.vmfrp-slider__arrow svg {
  display: block;
}

.vmfrp-slider__dots {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  justify-content: center;
  gap: var(--vmfrp-space-1);
}

.vmfrp-slider__dot-item {
  margin: 0;
  padding: 0;
  list-style: none;
}

.vmfrp-slider__dot {
  appearance: none;
  background: currentColor;
  opacity: 0.25;
  border: 0;
  width: 10px;
  height: 10px;
  border-radius: 50%;
  padding: 0;
  cursor: pointer;
  transition: opacity 150ms ease;
}

.vmfrp-slider__dot[aria-current="true"] {
  opacity: 1;
}

.vmfrp-slider__dot:focus-visible {
  outline: 2px solid currentColor;
  outline-offset: 2px;
  opacity: 1;
}

/* Caption is rendered once below the controls and updated by JS as
   the active slide changes — pulling captions out of slides keeps the
   track height uniform regardless of which slides have captions. */
.vmfrp-slider__caption {
  width: var(--vmfrp-content-width);
  max-width: var(--vmfrp-content-max);
  margin: var(--vmfrp-space-2) auto 0;
  font-size: 0.875rem;
  color: inherit;
  opacity: 0.7;
  text-align: center;
}

.vmfrp-slider__caption[hidden] {
  display: none;
}

/* Lightbox — single global overlay attached to <body>, populated with
   the clicked section's images only. Scoping happens in JS via the
   trigger's nearest .vmfrp-block--image ancestor.
   ========================================================================== */

.vmfrp-lightbox {
  position: fixed;
  inset: 0;
  z-index: 9999;
  background: rgba(0, 0, 0, 0.94);
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  padding: var(--vmfrp-space-3);
}

.vmfrp-lightbox[hidden] {
  display: none;
}

.vmfrp-lightbox__stage {
  position: relative;
  flex: 1;
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--vmfrp-space-2);
  /* min-height: 0 + flex: 1 = stage shrinks to fit, image height
       is then bounded by the stage instead of overflowing the screen. */
  min-height: 0;
}

.vmfrp-lightbox__image {
  /* Flex item: shrink to whatever space is left after the arrows.
       min-width/height: 0 lets it shrink below intrinsic image size. */
  flex: 1 1 auto;
  min-width: 0;
  min-height: 0;
  max-width: 100%;
  max-height: 100%;
  object-fit: contain;
  display: block;
  /* Drag-to-swipe is wired in JS — disable the browser's native
       image-drag so it doesn't kidnap the gesture. */
  -webkit-user-drag: none;
  user-select: none;
  cursor: grab;
}

.vmfrp-lightbox.is-dragging .vmfrp-lightbox__image {
  cursor: grabbing;
  /* Suppress the height transition while a drag is in flight, since
       the image's transform updates per frame. */
  transition: none;
}

.vmfrp-lightbox__caption {
  color: var(--vmfrp-white);
  margin: var(--vmfrp-space-2) auto 0;
  text-align: center;
  max-width: 60ch;
  font-size: 0.875rem;
  opacity: 0.85;
}

.vmfrp-lightbox__caption[hidden] {
  display: none;
}

.vmfrp-lightbox__counter {
  position: absolute;
  top: var(--vmfrp-space-2);
  left: 50%;
  transform: translateX(-50%);
  color: var(--vmfrp-white);
  font-size: 0.875rem;
  opacity: 0.7;
}

.vmfrp-lightbox__close,
.vmfrp-lightbox__arrow {
  appearance: none;
  /* Solid darker background — works against bright/white images
       (the previous translucent white version disappeared into them)
       and remains visible against the dark backdrop on the sides. */
  background: rgba(20, 20, 20, 0.7);
  color: var(--vmfrp-white);
  border: 1px solid rgba(255, 255, 255, 0.15);
  width: 48px;
  height: 48px;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  transition: background 150ms ease;
  /* Don't shrink under flex pressure — full 48px regardless of how
       narrow the image gets. */
  flex: 0 0 auto;
}

.vmfrp-lightbox__close:hover,
.vmfrp-lightbox__arrow:hover {
  background: rgba(0, 0, 0, 0.85);
}

.vmfrp-lightbox__close:focus-visible,
.vmfrp-lightbox__arrow:focus-visible {
  outline: 2px solid var(--vmfrp-white);
  outline-offset: 2px;
}

.vmfrp-lightbox__close {
  position: absolute;
  top: var(--vmfrp-space-2);
  right: var(--vmfrp-space-2);
  /* Above the stage so the close button always sits in the top-right
       corner regardless of image size. */
  z-index: 1;
}

/* Arrows are *flex items inside the stage* now (was: absolute), which
   pins them to the image's vertical centre regardless of caption
   height, and keeps them on the dark backdrop where they're always
   visible — even against a bright white image. */
.vmfrp-lightbox__arrow[hidden] {
  display: none;
}

.vmfrp-lightbox__close svg,
.vmfrp-lightbox__arrow svg {
  display: block;
}

/* Map block — heading, description and embed read as one framed unit.
   Background palette is intentionally not editor-tunable for this block;
   the field has been removed from ACF and the partial no longer emits
   data-bg, so the styles below define the look outright.
   ========================================================================== */

.vmfrp-block--map {
  background: var(--vmfrp-surface-subtle);
  border: 1px solid var(--vmfrp-border-subtle);
  /* The iframe goes edge-to-edge inside the section, so the map
       block would otherwise contribute 0 to the inter-block gap.
       Margin (not padding) keeps the frame tight — iframe flush at
       the bottom of its border — and puts the breathing room outside
       the framed unit, so the map reads as a discrete framed object
       with separation before the next block. */
  margin-block-end: var(--vmfrp-space-6);
}

.vmfrp-block--map > .vmfrp-block__map {
  display: block;
  width: 100%;
  aspect-ratio: 16 / 9;
  border: 0;
}

@media (max-width: 768px) {
  /* Square the iframe on mobile so the map dominates the heading
       and description above it, instead of the inverted-weight feel
       a 16:9 ratio produces on narrow viewports. */
  .vmfrp-block--map > .vmfrp-block__map {
    aspect-ratio: 1 / 1;
  }
}

/* Cards block — 2-column grid; first card spans the full row when the
   total count is odd, so a lone trailing card never floats half-width.
   The :has(.vmfrp-card:nth-child(odd):last-child) test works because a
   list with an odd number of children has its last child at an odd
   position. Pure CSS, no PHP changes required. Card padding and
   typography are uniform across the set — the full-row span is the
   only thing that distinguishes the featured card.
   ========================================================================== */

.vmfrp-cards {
  list-style: none;
  padding-inline-start: 0;
  margin-block-start: var(--vmfrp-space-3);
  margin-block-end: 0;
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: var(--vmfrp-space-3);

  /* "Has me": promote our parent to a named inline-size container so
       the layout responds to its actual host width, not the viewport.
       The 240px ToC sidebar can squeeze the content column to ~380px
       at 769px viewport — a viewport media query never knows that, but
       a container query does. Pattern: the child declares the parent's
       container requirement via :has(> &), so the grid is portable
       wherever it's dropped without manual container-type wiring. */
  :has(> &) {
    container-type: inline-size;
    container-name: vmfrp-cards-context;
  }
}

/* Featured first card on odd counts: full row. All other styling
   (padding, headline, description) inherits from .vmfrp-card so it
   reads as an equal member of the set. */
.vmfrp-cards:has(.vmfrp-card:nth-child(odd):last-child)
  > .vmfrp-card:first-child {
  grid-column: 1 / -1;
}

.vmfrp-card {
  padding: var(--vmfrp-space-4);
}

/* Icon slot — always rendered, fixed 32×32 so cards stay aligned when
   some rows have icons and others don't. The whole row collapses via
   :has() when no card in the set has an icon. SVG is inlined, so
   stroke="currentColor" in Lucide icons inherits the card's text
   colour automatically — white on deep teal, dark on light, no extra
   plumbing. */
.vmfrp-card__icon {
  width: 32px;
  height: 32px;
  margin-block-end: var(--vmfrp-space-2);
}

.vmfrp-card__icon svg {
  display: block;
  width: 100%;
  height: 100%;
  /* Force stroke and fill to currentColor so the icon picks up the
       card's text colour even if the editor pasted an SVG with a
       hard-coded stroke (e.g. stroke="#fff" from a recoloured Lucide
       export). CSS overrides SVG presentation attributes, so this
       wins without !important. fill stays "none" by default for line
       icons; only fills already set to a colour get coerced. */
  stroke: currentColor;
}

.vmfrp-card__icon svg [fill]:not([fill="none"]) {
  fill: currentColor;
}

/* If no card in this block has an icon, drop the reserved row entirely
   so a section with no icons looks identical to the pre-icon design. */
.vmfrp-cards:not(:has(.vmfrp-card__icon--filled)) .vmfrp-card__icon {
  display: none;
}

.vmfrp-card__headline {
  font-size: 1.375rem;
  line-height: 1.2;
  /* Editorial underline matching the hero title — currentColor so it
       adapts to whichever data-bg the card is using (white-on-teal,
       dark-on-light). */
  border-block-end: 1px solid currentColor;
  padding-block-end: 18px;
}

.vmfrp-card__description {
  margin-block-start: var(--vmfrp-space-2);
}

/* Below this container width, 2-col would give each card less than ~250px,
   too narrow for a multi-word headline + a sentence of description. Drop
   to a single column. Replaces the old viewport-based @media query, which
   couldn't see the ToC sidebar's effect on the actual cards-host width. */
@container vmfrp-cards-context (max-width: 540px) {
  .vmfrp-cards {
    grid-template-columns: 1fr;
  }
}

/* Media Cards block — image-led 2-column grid, same structure as Cards
   but with a fixed-aspect image in place of the icon slot and an
   optional button at the foot of each card.
   ========================================================================== */

.vmfrp-media-cards {
  list-style: none;
  padding-inline-start: 0;
  margin-block-start: var(--vmfrp-space-3);
  margin-block-end: 0;
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: var(--vmfrp-space-3);

  :has(> &) {
    container-type: inline-size;
    container-name: vmfrp-media-cards-context;
  }
}

/* Featured first card on odd counts: span the full row. */
/*.vmfrp-media-cards:has(.vmfrp-media-card:nth-child(odd):last-child)
  > .vmfrp-media-card:first-child {
  grid-column: 1 / -1;
}*/

/* Card shell — no padding here; image is flush to all edges at top,
   body carries its own padding below the image. flex column lets
   the body grow to fill unequal heights within a row. */
.vmfrp-media-card {
  overflow: hidden;
  display: flex;
  flex-direction: column;
}

/* Image zone: fixed 16:9 aspect ratio, cover crop.
   aria-hidden is set on the wrapper so the decorative image
   is not announced to screen readers (the headline carries meaning). */
.vmfrp-media-card__media {
  aspect-ratio: 16 / 9;
  overflow: hidden;
  flex-shrink: 0;
}

.vmfrp-media-card__image {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* Content area inherits the card's data-bg via the [data-bg] rules
   in the theming section. flex:1 + flex column lets the button sit
   at the foot of all cards in a row regardless of text length. */
.vmfrp-media-card__body {
  padding: var(--vmfrp-space-4);
  flex: 1;
  display: flex;
  flex-direction: column;
}

.vmfrp-media-card__headline {
  font-size: 1.375rem;
  line-height: 1.2;
  border-block-end: 1px solid currentColor;
  padding-block-end: 18px;
  margin-block-end: var(--vmfrp-space-2);
}

.vmfrp-media-card__description {
  margin: 0;
}

/* Button — margin-block-start:auto pushes it to the foot of the card
   body so buttons stay bottom-aligned across same-row cards. */
.vmfrp-media-card__link {
  display: inline-block;
  margin-block-start: auto;
  padding-block-start: var(--vmfrp-space-3);
  align-self: flex-start;
  font-weight: 600;
  font-size: 0.9375rem;
  color: inherit;
  text-decoration: underline;
  text-underline-offset: 3px;
  transition: opacity 0.15s ease;
}

.vmfrp-media-card__link:hover,
.vmfrp-media-card__link:focus-visible {
  opacity: 0.75;
}

.vmfrp-media-card__link:focus-visible {
  outline: 2px solid currentColor;
  outline-offset: 2px;
  border-radius: 2px;
}

@container vmfrp-media-cards-context (max-width: 540px) {
  .vmfrp-media-cards {
    grid-template-columns: 1fr;
  }
}

/* Downloads block — list of downloadable files with date badge,
   title + meta, and a download icon. Each row is a single click
   target.
   ========================================================================== */

.vmfrp-downloads {
  list-style: none;
  margin: var(--vmfrp-space-3) 0 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  /* Hairline separators via gap + border on the list. The list's
     border colour bleeds through the gap between rows, so each row
     gets a 1px rule above/below without per-row borders that would
     double up at the seam. */
  gap: 1px;
  background: var(--vmfrp-border-subtle);
  border: 1px solid var(--vmfrp-border-subtle);
}

.vmfrp-download {
  margin: 0;
  padding: 0;
  list-style: none;
  background: var(--vmfrp-white);
}

.vmfrp-download__link {
  display: grid;
  grid-template-columns: auto 1fr auto;
  gap: var(--vmfrp-space-3);
  align-items: center;
  padding: var(--vmfrp-space-2) var(--vmfrp-space-3);
  color: inherit;
  text-decoration: none;
  transition: background-color 0.2s ease;
}

.vmfrp-download__link:hover,
.vmfrp-download__link:focus-visible {
  background: var(--vmfrp-light-grey);
}

.vmfrp-download__link:focus-visible {
  outline: 2px solid var(--vmfrp-project-dark);
  outline-offset: -2px;
}

/* Date badge — three stacked spans, brand teal background, white
   text. Day prominent; month and year secondary. Fixed width so a
   long stack of rows aligns vertically regardless of date contents. */
.vmfrp-download__date {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  background: var(--vmfrp-project-dark);
  color: var(--vmfrp-white);
  width: 56px;
  padding: var(--vmfrp-space-1);
  flex-shrink: 0;
  font-size: 0.625rem;
  line-height: 1.1;
  text-transform: uppercase;
  letter-spacing: 0.04em;
}

.vmfrp-download__date-day {
  font-size: 1.25rem;
  font-weight: 700;
  letter-spacing: -0.01em;
}

.vmfrp-download__date-month,
.vmfrp-download__date-year {
  display: block;
}

.vmfrp-download__info {
  /* min-width: 0 lets the column shrink below intrinsic content
     width — without it, a long filename would push the icon out
     of the row instead of wrapping. */
  min-width: 0;
}

.vmfrp-download__name {
  margin: 0;
  font-size: 1rem;
  font-weight: 600;
  line-height: 1.3;
}

.vmfrp-download__meta {
  margin: 4px 0 0;
  font-size: 0.8125rem;
  color: inherit;
  opacity: 0.7;
  line-height: 1.4;
}

/* Pipe separator between type and size, but only when both are
   present. ::before on the second span is conditional via the
   previous-sibling selector (sort of) — we just use a + combinator
   so the separator only renders when something precedes it. */
.vmfrp-download__meta-type + .vmfrp-download__meta-size::before {
  content: " | ";
  margin-inline: 4px;
}

.vmfrp-download__icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 36px;
  height: 36px;
  background: var(--vmfrp-project-dark);
  color: var(--vmfrp-white);
  border-radius: 50%;
  flex-shrink: 0;
  transition: transform 0.2s ease;
}

.vmfrp-download__link:hover .vmfrp-download__icon,
.vmfrp-download__link:focus-visible .vmfrp-download__icon {
  /* Subtle "drop" gesture on the download icon — a 2px push
     downward suggests the action without a heavy animation. */
  transform: translateY(2px);
}

.vmfrp-download__icon svg {
  display: block;
}

/* Visually hidden text for screen readers — describes the link
   target completely so the AT user gets the same context that the
   visual user gets from the badge + name + meta layout. */
.vmfrp-download .screen-reader-text {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

/* Dark-section download inversion: badge and icon swap to white surface
   with the section's accent colour as foreground so they don't disappear
   into a same-coloured background. Covers both the literal deep_teal and
   the adaptive project_dark (which resolves to blue on completed projects). */
[data-bg="deep_teal"] .vmfrp-download,
[data-bg="project_dark"] .vmfrp-download {
  background: transparent;
}

[data-bg="deep_teal"] .vmfrp-downloads,
[data-bg="project_dark"] .vmfrp-downloads {
  background: rgba(255, 255, 255, 0.15);
  border-color: rgba(255, 255, 255, 0.15);
}

[data-bg="deep_teal"] .vmfrp-download__link:hover,
[data-bg="deep_teal"] .vmfrp-download__link:focus-visible,
[data-bg="project_dark"] .vmfrp-download__link:hover,
[data-bg="project_dark"] .vmfrp-download__link:focus-visible {
  background: rgba(255, 255, 255, 0.08);
}

[data-bg="deep_teal"] .vmfrp-download__date,
[data-bg="deep_teal"] .vmfrp-download__icon {
  background: var(--vmfrp-white);
  color: var(--vmfrp-deep-teal);
}

[data-bg="project_dark"] .vmfrp-download__date,
[data-bg="project_dark"] .vmfrp-download__icon {
  background: var(--vmfrp-white);
  color: var(--vmfrp-project-dark);
}

/* Links block — same register layout as Downloads, minus date badge
   ========================================================================== */

.vmfrp-links {
  list-style: none;
  margin: var(--vmfrp-space-3) 0 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 1px;
  background: var(--vmfrp-border-subtle);
  border: 1px solid var(--vmfrp-border-subtle);
}

.vmfrp-link {
  margin: 0;
  padding: 0;
  list-style: none;
  background: var(--vmfrp-white);
}

.vmfrp-link__link {
  display: grid;
  grid-template-columns: 1fr auto;
  gap: var(--vmfrp-space-3);
  align-items: center;
  padding: var(--vmfrp-space-2) var(--vmfrp-space-3);
  color: inherit;
  text-decoration: none;
  transition: background-color 0.2s ease;
}

.vmfrp-link__link:hover,
.vmfrp-link__link:focus-visible {
  background: var(--vmfrp-light-grey);
}

.vmfrp-link__link:focus-visible {
  outline: 2px solid var(--vmfrp-project-dark);
  outline-offset: -2px;
}

.vmfrp-link__info {
  min-width: 0;
}

.vmfrp-link__name {
  margin: 0;
  font-size: 1rem;
  font-weight: 600;
  line-height: 1.3;
}

.vmfrp-link__meta {
  margin: 4px 0 0;
  font-size: 0.8125rem;
  color: inherit;
  opacity: 0.7;
  line-height: 1.4;
}

.vmfrp-link__icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 36px;
  height: 36px;
  background: var(--vmfrp-project-dark);
  color: var(--vmfrp-white);
  border-radius: 50%;
  flex-shrink: 0;
  transition: transform 0.2s ease;
}

/* Outward nudge on hover — mirrors the download icon's directional
   hint but gestures toward "leaving the page" rather than "saving". */
.vmfrp-link__link:hover .vmfrp-link__icon,
.vmfrp-link__link:focus-visible .vmfrp-link__icon {
  transform: translate(2px, -2px);
}

.vmfrp-link__icon svg {
  display: block;
}

.vmfrp-link .screen-reader-text {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

[data-bg="deep_teal"] .vmfrp-link,
[data-bg="project_dark"] .vmfrp-link {
  background: transparent;
}

[data-bg="deep_teal"] .vmfrp-links,
[data-bg="project_dark"] .vmfrp-links {
  background: rgba(255, 255, 255, 0.15);
  border-color: rgba(255, 255, 255, 0.15);
}

[data-bg="deep_teal"] .vmfrp-link__link:hover,
[data-bg="deep_teal"] .vmfrp-link__link:focus-visible,
[data-bg="project_dark"] .vmfrp-link__link:hover,
[data-bg="project_dark"] .vmfrp-link__link:focus-visible {
  background: rgba(255, 255, 255, 0.08);
}

[data-bg="deep_teal"] .vmfrp-link__icon {
  background: var(--vmfrp-white);
  color: var(--vmfrp-deep-teal);
}

[data-bg="project_dark"] .vmfrp-link__icon {
  background: var(--vmfrp-white);
  color: var(--vmfrp-project-dark);
}

/* FAQ block — native <details>/<summary> disclosure list
   ========================================================================== */

.vmfrp-faqs {
  margin-block-start: var(--vmfrp-space-3);
  display: flex;
  flex-direction: column;
  gap: var(--vmfrp-space-2);
}

.vmfrp-faq__question {
  cursor: pointer;
}

/* Open state: bold the question (consistent with the ToC's active
   treatment) and add breathing room below the answer to mark the
   section as finished before the eye lands on the next question. */
.vmfrp-faq[open] {
  padding-block-end: var(--vmfrp-space-2);
}

.vmfrp-faq[open] > .vmfrp-faq__question {
  font-weight: 700;
}

.vmfrp-faq__answer {
  margin-block-start: var(--vmfrp-space-2);
  /* Match the inline offset created by the native disclosure marker
       on the <summary>, so question and answer share a left baseline. */
  padding-inline-start: 1.25em;
}

/* Recent Projects — horizontal scroll-snap carousel of sibling projects.
   Sits below the page-layout grid, full content-width, hidden in PHP
   when there are fewer than 5 total projects.
   ========================================================================== */

.vmfrp-recent {
  border-block-start: 1px solid var(--vmfrp-border-subtle);
}

.vmfrp-recent__inner {
  width: var(--vmfrp-content-width);
  max-width: var(--vmfrp-content-max);
  margin-inline: auto;
  padding-block: var(--vmfrp-space-6);
}

/* Header row above the list: title on the left, arrow controls on
   the right. Arrows are hidden until JS adds .has-overflow when the
   carousel actually has content beyond what's visible. */
.vmfrp-recent__header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--vmfrp-space-3);
  margin-block-end: var(--vmfrp-space-3);
}

.vmfrp-recent__heading {
  margin-block-end: 0;
}

.vmfrp-recent__arrows {
  display: none;
  gap: var(--vmfrp-space-1);
  flex-shrink: 0;
}

.vmfrp-recent.has-overflow .vmfrp-recent__arrows {
  display: flex;
}

.vmfrp-recent__arrow {
  appearance: none;
  background: transparent;
  border: 1px solid var(--vmfrp-border-subtle);
  width: 40px;
  height: 40px;
  color: inherit;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}

.vmfrp-recent__arrow:disabled {
  opacity: 0.35;
  cursor: not-allowed;
}

.vmfrp-recent__arrow:focus-visible {
  outline: 2px solid var(--vmfrp-project-dark);
  outline-offset: 2px;
}

.vmfrp-recent__arrow svg {
  display: block;
}

.vmfrp-recent__list {
  list-style: none;
  padding-inline-start: 0;
  margin-block: 0;
  display: flex;
  gap: var(--vmfrp-space-3);
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  /* Hide the native scrollbar — JS-driven arrow buttons are the
       desktop affordance; touch devices swipe natively. */
  scrollbar-width: none;
}

.vmfrp-recent__list::-webkit-scrollbar {
  display: none;
}

@media (hover: hover) {
  /* Mouse-driven device: grab affordance for drag-to-scroll. Touch
       devices skip this — they have native swipe and no cursor. */
  .vmfrp-recent__list {
    cursor: grab;
  }

  .vmfrp-recent__list.is-dragging,
  .vmfrp-recent__list.is-dragging .vmfrp-recent__card {
    cursor: grabbing;
  }
}

.vmfrp-recent__item {
  /* Fixed card width so the count fits naturally to the available
       space — 4 at 1080px content width, stepping down to 3, 2, 1
       as the viewport narrows. No media queries needed; the browser
       fits as many cards as the container allows and scrolls the rest. */
  flex: 0 0 250px;
  scroll-snap-align: start;
}

.vmfrp-recent__card,
.vmfrp-recent__card:hover,
.vmfrp-recent__card:focus,
.vmfrp-recent__card:focus-visible {
  display: block;
  text-decoration: none;
  color: inherit;
}

/* Media wrapper holds the aspect-ratio frame so cards keep a uniform
   height even when a project has no featured image (silent fallback). */
.vmfrp-recent__media {
  aspect-ratio: 5 / 4;
  background: var(--vmfrp-light-grey);
  overflow: hidden;
}

.vmfrp-recent__thumb {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  /* Scale transition driven from the card on hover. Matches the
     [vmfrp_projects] grid so the two project-card surfaces feel like
     one component family. */
  transition: transform 0.4s ease;
}

.vmfrp-recent__card:hover .vmfrp-recent__thumb,
.vmfrp-recent__card:focus-visible .vmfrp-recent__thumb {
  transform: scale(1.03);
}

.vmfrp-recent__name {
  margin-block-start: var(--vmfrp-space-2);
  /* Lock to a card-label scale rather than inheriting Enfold's H3,
       which is meant for body sub-sections. */
  font-size: 1.125rem;
  line-height: 1.3;
  /* Explicit user-select restores the selection highlight inside
       the link. Cancelling dragstart on the carousel keeps the <a>
       flagged as a drag source, which suppresses the highlight even
       though the underlying selection succeeds. */
  user-select: text;
  transition: color 0.2s ease;
}

/* Card hover affordance: title shifts to brand teal. */
.vmfrp-recent__card:hover .vmfrp-recent__name,
.vmfrp-recent__card:focus-visible .vmfrp-recent__name {
  color: var(--vmfrp-project-dark);
}

/* Suppress Enfold's image-hover overlay (the dark disc with the arrow
   icon) on every project-card surface. Enfold injects an .image-overlay
   span next to any image inside a link, regardless of where the link
   leads. The noLightbox class on the cards is the documented opt-out,
   but this rule is belt-and-braces: even if Enfold's JS still injects
   the overlay, it stays hidden. */
.vmfrp-recent__card .image-overlay,
.vmfrp-projects__card .image-overlay {
  display: none;
}

/* Contact section — quiet CTA at the bottom of every project page.
   Sits outside the page-layout's ToC+content grid so it spans the full
   content width.
   ========================================================================== */

.vmfrp-contact {
  background: var(--vmfrp-surface-subtle);
  border-block: 1px solid var(--vmfrp-border-subtle);
}

.vmfrp-contact__inner {
  width: var(--vmfrp-content-width);
  max-width: var(--vmfrp-content-max);
  margin-inline: auto;
  padding-block: var(--vmfrp-space-6);
  /* Centre the closing CTA so the section reads as a deliberate
       end-of-page statement rather than an off-axis afterthought. */
  text-align: center;
}

.vmfrp-contact__body {
  margin-block-start: var(--vmfrp-space-2);
  max-width: 50ch;
  margin-inline: auto;
}

.vmfrp-contact__email {
  display: inline-block;
  margin-block-start: var(--vmfrp-space-3);
  background: var(--vmfrp-project-dark);
  color: var(--vmfrp-white);
  padding-block: var(--vmfrp-space-2);
  padding-inline: var(--vmfrp-space-4);
  border: 1px solid var(--vmfrp-project-dark);
  text-decoration: none;
  font-weight: 700;
}

.vmfrp-contact__email:visited {
  color: var(--vmfrp-white);
}

.vmfrp-contact__email:hover,
.vmfrp-contact__email:focus-visible {
  background: transparent;
  color: var(--vmfrp-project-dark);
}

.vmfrp-contact__email:focus-visible {
  outline: 2px solid var(--vmfrp-project-dark);
  outline-offset: 2px;
}

/* Sign-up CTA — sits between the block content and the contact section.
   Background is --vmfrp-project-dark so it flips teal ↔ blue with project
   status, creating strong contrast against the light contact section below.
   ========================================================================== */

.vmfrp-signup {
  background: var(--vmfrp-project-dark);
  color: var(--vmfrp-white);
}

.vmfrp-signup :is(h1, h2, h3, h4, h5, h6) {
  color: var(--vmfrp-white);
}

.vmfrp-signup__inner {
  width: var(--vmfrp-content-width);
  max-width: var(--vmfrp-content-max);
  margin-inline: auto;
  padding-block: var(--vmfrp-space-6);
  text-align: center;
}

.vmfrp-signup__body {
  margin-block-start: var(--vmfrp-space-2);
  max-width: 50ch;
  margin-inline: auto;
  opacity: 0.9;
}

.vmfrp-signup__btn {
  display: inline-block;
  margin-block-start: var(--vmfrp-space-3);
  background: transparent;
  color: var(--vmfrp-white);
  padding-block: var(--vmfrp-space-2);
  padding-inline: var(--vmfrp-space-4);
  border: 2px solid var(--vmfrp-white);
  text-decoration: none;
  font-weight: 700;
}

.vmfrp-signup__btn:visited {
  color: var(--vmfrp-white);
}

.vmfrp-signup__btn:hover,
.vmfrp-signup__btn:focus-visible {
  background: var(--vmfrp-white);
  color: var(--vmfrp-project-dark);
}

.vmfrp-signup__btn:focus-visible {
  outline: 2px solid var(--vmfrp-white);
  outline-offset: 2px;
}

/* Projects grouped wrapper and status headings
   ========================================================================== */

/* Space between consecutive status groups. The first group has no
   top margin because nothing precedes it inside the wrapper. */
.vmfrp-projects-group + .vmfrp-projects-group {
  margin-block-start: var(--vmfrp-space-6);
}

/* Status label — sits above its grid, visually connecting the heading
   to the cards below via the brand colour and a matching bottom border. */
.vmfrp-projects-group__heading {
  margin-block: 0 var(--vmfrp-space-2);
  font-size: 1.375rem;
  line-height: 1.2;
  color: var(--vmfrp-project-dark);
  border-block-end: 2px solid var(--vmfrp-project-dark);
  padding-block-end: var(--vmfrp-space-1);
}

/* Projects grid — [vmfrp_projects] shortcode. Same card vocabulary as
   the recent-projects carousel (5/4 image, title beneath, deep-teal
   hover), laid out as a 3 → 2 → 1 column grid that responds to the
   container it's dropped into (not the viewport).
   ========================================================================== */

.vmfrp-projects {
  /* Container query context — breakpoints below respond to the grid's
       own inline size, so the shortcode degrades correctly whether it's
       in a full-width section or a narrow column. */
  container-type: inline-size;
  background: var(--vmfrp-white);
  padding: var(--vmfrp-space-4);
  margin-block: 0;
  list-style: none;
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: var(--vmfrp-space-4) var(--vmfrp-space-3);
}

/* Beat Enfold's `.entry-content-wrapper li { margin-left: 1em }` and
   any inherited bullet styling. Specificity (0,2,0) defeats Enfold's
   (0,1,1) without resorting to !important. */
.vmfrp-projects > .vmfrp-projects__item {
  margin: 0;
  padding: 0;
  list-style: none;
}

/* Container queries fire when the grid's own inline-size is known.
   Viewport media queries are the fallback for Enfold contexts where the
   wrapping section reports a wider container than the visible viewport. */
@container (max-width: 800px) {
  .vmfrp-projects {
    grid-template-columns: repeat(2, 1fr);
  }
}

@container (max-width: 550px) {
  .vmfrp-projects {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 800px) {
  .vmfrp-projects {
    grid-template-columns: repeat(2, 1fr);
  }
}

@media (max-width: 550px) {
  .vmfrp-projects {
    grid-template-columns: 1fr;
  }
}

.vmfrp-projects__card,
.vmfrp-projects__card:hover,
.vmfrp-projects__card:focus,
.vmfrp-projects__card:focus-visible {
  display: flex;
  flex-direction: column;
  text-decoration: none;
  color: inherit;
}

.vmfrp-projects__media {
  aspect-ratio: 5 / 4;
  background: var(--vmfrp-light-grey);
  overflow: hidden;
}

.vmfrp-projects__thumb {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform 0.4s ease;
}

.vmfrp-projects__card:hover .vmfrp-projects__thumb,
.vmfrp-projects__card:focus-visible .vmfrp-projects__thumb {
  transform: scale(1.03);
}

.vmfrp-projects__band {
  background: var(--vmfrp-project-dark);
  color: var(--vmfrp-white);
  padding: var(--vmfrp-space-3);
  /* min-height = eyebrow line + gap + 2 title lines + vertical padding,
     so single-line titles don't shrink the band below a consistent height. */
  min-height: calc(
    0.7rem * 1.4 + 0.35rem + 1.125rem * 1.3 * 2 + var(--vmfrp-space-3) * 2
  );
}

.vmfrp-projects__eyebrow {
  margin-block: 0 0.35rem;
  font-size: 0.7rem;
  font-weight: 400;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  opacity: 0.7;
}

.vmfrp-projects__name {
  color: var(--vmfrp-white) !important;
  margin-block: 0;
  /* Lock to a card-label scale rather than inheriting Enfold's H3. */
  font-size: 1.125rem;
  line-height: 1.3;
  /* 2-line clamp keeps the band a predictable height regardless of title length. */
  display: -webkit-box;
  -webkit-line-clamp: 2;
  line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

.vmfrp-projects__card:focus-visible {
  outline: 2px solid var(--vmfrp-project-dark);
  outline-offset: 4px;
}

/* Enfold full-width container override — removes the inner container's
   max-width and padding so shortcode content can bleed edge-to-edge.
   ========================================================================== */

.full-width-container .container {
  max-width: 100% !important;
  width: 100% !important;
  padding: 0;

  .avia_codeblock_section {
    margin-block-start: -40px;
  }
}
