/* ==========================================================================
   Shared components
   --------------------------------------------------------------------------
   Reusable patterns used across pages. Page-specific layouts belong in
   assets/css/pages/<page>.css. Values come from variables.css.

   Contents
     1. Header and brand
     2. Navigation (mobile panel + desktop bar)
     3. Buttons and text links
     4. Eyebrow and section heading
     5. Page intro
     6. Media frames and cards
     7. Contact list and CTA band
     8. Footer
     9. Floating actions
    10. Form fields
    11. Reveal-on-scroll
    12. How it works step cards
    13. Page banner
   ========================================================================== */

/* 1. Header and brand ------------------------------------------------------
   The header floats over the page with a transparent background. Once the
   page scrolls (main.js adds .is-scrolled) a liquid-glass layer fades in. */
.site-header {
  position: fixed;
  inset: 0 0 auto;
  z-index: var(--z-header);
  min-height: var(--header-height);
}

/* The glass lives on a pseudo-element: backdrop-filter on the header itself
   would make it the containing block of the fixed mobile nav panel. */
.site-header::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  background-color: var(--header-glass-bg);
  -webkit-backdrop-filter: var(--header-glass-filter);
  backdrop-filter: var(--header-glass-filter);
  border-bottom: var(--border-width) solid var(--header-glass-edge);
  box-shadow: var(--shadow-md);
  opacity: 0;
  transition: opacity var(--duration-base) var(--ease-standard);
}

.site-header.is-scrolled::before,
.site-header.is-nav-open::before {
  opacity: 1;
}

/* Solid behind the open mobile menu so bar and panel read as one surface */
.site-header.is-nav-open::before {
  background-color: var(--color-bg);
}

/* Each page's first section runs up behind the header; the transparent
   border (which shows the section's own background) clears its content.
   border-box origin stops background images and gradients tiling into it. */
main> :first-child {
  border-top: var(--header-height) solid transparent;
  background-origin: border-box;
}

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

.site-brand {
  display: inline-flex;
  align-items: center;
  gap: var(--space-3);
  color: var(--color-text);
  text-decoration: none;
}

.site-brand:hover {
  color: var(--color-primary);
}

.site-brand__logo {
  height: var(--header-logo-height);
  width: auto;
}

.site-brand__name {
  font-size: var(--fs-h4);
  line-height: 1;
  white-space: nowrap;
}

/* 2. Navigation ------------------------------------------------------------ */
.nav-toggle {
  display: inline-grid;
  place-items: center;
  width: var(--btn-height-sm);
  height: var(--btn-height-sm);
  margin-right: calc(var(--space-2) * -1);
  padding: 0;
  color: var(--color-text);
  background: none;
  border: 0;
  border-radius: var(--radius-xs);
  cursor: pointer;
}

.nav-toggle .icon {
  --icon-size: var(--nav-toggle-icon-size);
}

.nav-toggle__close,
.nav-toggle[aria-expanded="true"] .nav-toggle__open {
  display: none;
}

.nav-toggle[aria-expanded="true"] .nav-toggle__close {
  display: block;
}

/* Mobile: full-height panel under the header. Hidden with visibility so
   closed links drop out of the tab order. */
.site-nav {
  position: fixed;
  inset: var(--header-height) 0 0 0;
  display: flex;
  flex-direction: column;
  gap: var(--space-6);
  padding: var(--space-6) var(--page-gutter) calc(var(--space-6) + env(safe-area-inset-bottom));
  overflow-y: auto;
  background-color: var(--color-bg);
  border-top: var(--border-width) solid var(--color-border);
  visibility: hidden;
  opacity: 0;
  transform: translateY(calc(var(--space-2) * -1));
  transition:
    opacity var(--duration-base) var(--ease-standard),
    transform var(--duration-base) var(--ease-standard),
    visibility 0s linear var(--duration-base);
}

.site-header.is-nav-open .site-nav {
  visibility: visible;
  opacity: 1;
  transform: none;
  transition-delay: 0s;
}

.site-nav__list {
  display: flex;
  flex-direction: column;
  margin: 0;
  padding: 0;
  list-style: none;
}

.site-nav__link {
  position: relative;
  display: block;
  padding-block: var(--space-3);
  font-family: var(--font-heading);
  font-size: var(--fs-h3);
  line-height: var(--lh-snug);
  color: var(--color-text);
  text-decoration: none;
  border-bottom: var(--border-width) solid var(--color-border);
}

.site-nav__link:hover,
.site-nav__link[aria-current="page"] {
  color: var(--color-primary);
}

.site-nav__cta {
  align-self: flex-start;
}

body.is-nav-open {
  overflow: hidden;
  /* Lock page scroll behind the open mobile menu */
}

/* Desktop bar */
@media (min-width: 992px) {
  .nav-toggle {
    display: none;
  }

  .site-nav {
    position: static;
    flex-direction: row;
    align-items: center;
    gap: var(--nav-link-gap);
    padding: 0;
    overflow: visible;
    background: none;
    border: 0;
    visibility: visible;
    opacity: 1;
    transform: none;
    transition: none;
  }

  .site-nav__list {
    flex-direction: row;
    gap: var(--nav-link-gap);
  }

  .site-nav__link {
    padding-block: var(--space-2);
    font-family: var(--font-body);
    font-size: var(--fs-sm);
    font-weight: var(--fw-medium);
    border-bottom: 0;
  }

  .site-nav__link::after {
    content: "";
    position: absolute;
    left: 0;
    right: 0;
    bottom: 0;
    height: var(--border-width);
    background-color: currentColor;
    transform: scaleX(0);
    transform-origin: left;
    transition: transform var(--duration-base) var(--ease-out);
  }

  .site-nav__link:hover::after,
  .site-nav__link[aria-current="page"]::after {
    transform: scaleX(1);
  }

  .site-nav__cta {
    align-self: auto;
  }
}

/* Fallback when JavaScript is unavailable. Without JS there is no
   .is-scrolled, so it stays solid and one line tall (scrolls sideways). */
.noscript-nav {
  display: flex;
  align-items: center;
  overflow-x: auto;
  white-space: nowrap;
  background-color: var(--color-bg);
  gap: var(--space-3) var(--space-5);
  min-height: var(--header-height);
  padding-inline: var(--page-gutter);
  font-size: var(--fs-sm);
  font-weight: var(--fw-medium);
}

/* 3. Buttons and text links ------------------------------------------------ */
.button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  min-height: var(--btn-height);
  padding: 0 var(--btn-padding-x);
  font-family: var(--font-body);
  font-size: var(--btn-font-size);
  font-weight: var(--btn-font-weight);
  letter-spacing: var(--ls-button);
  line-height: 1.2;
  text-align: center;
  text-decoration: none;
  white-space: nowrap;
  border: var(--border-width) solid transparent;
  border-radius: var(--btn-radius);
  cursor: pointer;
  transition:
    background-color var(--duration-fast) var(--ease-standard),
    border-color var(--duration-fast) var(--ease-standard),
    color var(--duration-fast) var(--ease-standard);
}

.button--primary {
  background-color: var(--color-primary);
  border-color: var(--color-primary);
  color: var(--color-text-inverse);
}

.button--primary:hover {
  background-color: var(--color-primary-hover);
  border-color: var(--color-primary-hover);
  color: var(--color-text-inverse);
}

.button--secondary {
  background-color: transparent;
  border-color: var(--color-primary);
  color: var(--color-primary);
}

.button--secondary:hover {
  background-color: var(--color-primary);
  color: var(--color-text-inverse);
}

/* For use on .section--inverse / green backgrounds */
.button--light {
  background-color: var(--color-text-inverse);
  border-color: var(--color-text-inverse);
  color: var(--color-primary);
}

.button--light:hover {
  background-color: var(--color-surface);
  border-color: var(--color-surface);
  color: var(--color-primary-hover);
}

.button--outline-light {
  background-color: transparent;
  border-color: var(--color-text-inverse);
  color: var(--color-text-inverse);
}

.button--outline-light:hover {
  background-color: var(--color-text-inverse);
  color: var(--color-primary);
}

/* Rounded ends, used for content buttons on the Home and Services pages */
.button--pill {
  border-radius: var(--radius-pill);
}

.button--sm {
  min-height: var(--btn-height-sm);
  padding-inline: var(--btn-padding-x-sm);
}

.button--block {
  width: 100%;
}

.button:disabled,
.button[aria-disabled="true"] {
  opacity: 0.55;
  cursor: not-allowed;
  pointer-events: none;
}

.button-group {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-3);
}

.text-link {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  font-weight: var(--fw-semibold);
  font-size: var(--fs-sm);
  letter-spacing: var(--ls-button);
  text-decoration: none;
}

.text-link .icon {
  transition: transform var(--duration-base) var(--ease-out);
}

.text-link:hover {
  text-decoration: underline;
}

.text-link:hover .icon {
  transform: translateX(var(--space-1));
}

/* 4. Eyebrow and section heading ------------------------------------------- */
.eyebrow {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  margin-bottom: var(--space-4);
  font-family: var(--font-body);
  font-size: var(--fs-xs);
  font-weight: var(--fw-semibold);
  letter-spacing: var(--ls-eyebrow);
  line-height: var(--lh-snug);
  text-transform: uppercase;
  color: var(--color-accent-text);
}

.eyebrow::before {
  content: "";
  flex: 0 0 var(--space-6);
  height: var(--border-width);
  background-color: currentColor;
}

.section--inverse .eyebrow,
.site-footer .eyebrow {
  color: var(--color-text-inverse-muted);
}

.section-heading {
  max-width: var(--container-narrow);
  margin-bottom: var(--space-7);
}

.section-heading__title {
  margin-bottom: var(--space-4);
}

.section-heading__intro {
  margin-bottom: 0;
  font-size: var(--fs-lg);
  color: var(--color-text-muted);
  max-width: var(--measure-narrow);
}

.section--inverse .section-heading__intro {
  color: var(--color-text-inverse-muted);
}

.section-heading--center {
  margin-inline: auto;
  text-align: center;
}

.section-heading--center .eyebrow {
  justify-content: center;
}

.section-heading--center .section-heading__intro {
  margin-inline: auto;
}

/* Outlined pill above a heading, and the italic green word inside headings,
   e.g. <h2>How Our <span class="accent-word">Laundry</span> Service Works</h2>.
   Pages using .accent-word load DM Serif Display's italic (ital@0;1). */
.pill-label {
  display: inline-block;
  margin-bottom: var(--space-4);
  padding: var(--space-1) var(--space-4);
  font-size: var(--fs-sm);
  font-weight: var(--fw-medium);
  color: var(--color-primary);
  background-color: var(--color-surface);
  border: var(--border-width) solid color-mix(in srgb, var(--color-primary) 35%, transparent);
  border-left-width: 3px;
  border-radius: var(--radius-pill);
}

.accent-word {
  font-style: italic;
  color: var(--color-accent-text);
}

/* 5. Page intro (top of interior pages) ------------------------------------ */
.page-intro {
  padding-block: var(--section-space-tight);
  border-bottom: var(--border-width) solid var(--color-border);
}

.page-intro__title {
  max-width: 18ch;
  margin-bottom: 0;
}

.page-intro__lede {
  margin-top: var(--space-5);
  margin-bottom: 0;
}

.page-intro__actions {
  margin-top: var(--space-6);
}

/* 6. Media frames and cards -------------------------------------------------
   .media-frame crops any <img> to a fixed aspect ratio so layouts don't
   shift while images load. Always give the <img> width/height attributes. */
.media-frame {
  position: relative;
  overflow: hidden;
  aspect-ratio: var(--media-ratio, 4 / 5);
  background-color: var(--color-media-placeholder);
  border-radius: var(--radius-sm);
}

.media-frame>img,
.media-frame>picture>img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.media-frame--square {
  --media-ratio: 1 / 1;
}

.media-frame--landscape {
  --media-ratio: 3 / 2;
}

.media-frame--wide {
  --media-ratio: 16 / 9;
}

.media-frame--tall {
  --media-ratio: 3 / 4;
}

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

  .media-frame--zoom>img,
  .media-frame--zoom>picture>img {
    transition: transform var(--duration-slow) var(--ease-out);
  }

  .media-frame--zoom:hover>img,
  .media-frame--zoom:hover>picture>img,
  .media-card:hover .media-frame--zoom>img,
  .media-card:hover .media-frame--zoom>picture>img {
    transform: scale(1.03);
  }
}

/* Editorial card: image + text, no box by default. */
.media-card {
  position: relative;
  display: flex;
  flex-direction: column;
  height: 100%;
}

.media-card__body {
  display: flex;
  flex-direction: column;
  flex: 1;
  padding-top: var(--space-5);
}

.media-card__title {
  font-size: var(--fs-h4);
  margin-bottom: var(--space-3);
}

.media-card__text {
  color: var(--color-text-muted);
  margin-bottom: var(--space-4);
}

.media-card__footer {
  margin-top: auto;
}

/* Makes the whole card clickable via its title link while keeping one tab stop. */
.media-card__link {
  color: inherit;
  text-decoration: none;
}

.media-card__link::after {
  content: "";
  position: absolute;
  inset: 0;
}

.media-card__link:focus-visible {
  outline: none;
}

.media-card:has(.media-card__link:focus-visible) {
  outline: var(--focus-ring-width) solid var(--color-focus);
  outline-offset: var(--focus-ring-offset);
}

/* Boxed variant for text-only cards. */
.media-card--surface {
  padding: var(--space-6);
  background-color: var(--color-surface);
  border: var(--border-width) solid var(--color-border);
  border-radius: var(--radius-sm);
}

.media-card--surface .media-card__body {
  padding-top: 0;
}

/* 7. Contact list and CTA band --------------------------------------------- */
.contact-list {
  display: grid;
  gap: var(--space-5);
  margin: 0;
  padding: 0;
  list-style: none;
}

.contact-list__item {
  display: flex;
  align-items: flex-start;
  gap: var(--space-4);
}

.contact-list__icon {
  display: grid;
  place-items: center;
  flex: 0 0 auto;
  width: var(--btn-height-sm);
  height: var(--btn-height-sm);
  color: var(--color-primary);
  border: var(--border-width) solid var(--color-border);
  border-radius: var(--radius-pill);
}

.contact-list__label {
  display: block;
  margin-bottom: var(--space-1);
  font-size: var(--fs-xs);
  font-weight: var(--fw-semibold);
  letter-spacing: var(--ls-eyebrow);
  text-transform: uppercase;
  color: var(--color-text-muted);
}

.contact-list__value {
  color: var(--color-text);
}

a.contact-list__value {
  text-decoration: none;
}

a.contact-list__value:hover {
  color: var(--color-primary);
  text-decoration: underline;
}

.cta-band {
  display: grid;
  gap: var(--space-6);
  padding: var(--space-7) var(--space-6);
  background-color: var(--color-surface);
  border: var(--border-width) solid var(--color-border);
  border-radius: var(--radius-sm);
}

.cta-band__title {
  margin-bottom: var(--space-3);
}

.cta-band__text {
  margin-bottom: 0;
  color: var(--color-text-muted);
  max-width: var(--measure-narrow);
}

.cta-band--inverse {
  --bs-heading-color: var(--color-text-inverse);
  background-color: var(--color-surface-inverse);
  border-color: var(--color-surface-inverse);
  color: var(--color-text-inverse);
}

.cta-band--inverse .cta-band__text {
  color: var(--color-text-inverse-muted);
}

@media (min-width: 768px) {
  .cta-band {
    grid-template-columns: 1fr auto;
    align-items: center;
    padding: var(--space-8);
  }
}

/* 8. Footer ---------------------------------------------------------------- */
.site-footer {
  --bs-heading-color: var(--color-text-inverse);
  /* Extra bottom room so the floating actions never cover footer text on small screens */
  padding-top: var(--footer-padding-y);
  padding-bottom: calc(var(--space-5) + var(--fab-clearance));
  background-color: var(--color-primary-hover);
  color: var(--color-text-inverse-muted);
  font-size: var(--fs-sm);
}

.site-footer a {
  color: var(--color-text-inverse);
  text-decoration: none;
}

.site-footer a:hover {
  color: var(--color-text-inverse);
  text-decoration: underline;
}

.site-footer__grid {
  display: grid;
  gap: var(--space-7);
}

.site-footer__brand {
  margin-bottom: var(--space-3);
  font-size: var(--fs-h3);
  color: var(--color-text-inverse);
}

.site-footer__logo {
  width: auto;
  height: var(--footer-logo-height);
  margin-bottom: var(--space-4);
}

.site-footer__tagline {
  margin-bottom: 0;
  max-width: 28ch;
}

.site-footer__heading {
  margin-bottom: var(--space-4);
}

.site-footer__list {
  display: grid;
  gap: var(--space-3);
  margin: 0;
  padding: 0;
  list-style: none;
}

.site-footer__list .icon {
  margin-right: var(--space-2);
}

.site-footer__bottom {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  gap: var(--space-2) var(--space-5);
  margin-top: var(--space-8);
  padding-top: var(--space-5);
  border-top: var(--border-width) solid color-mix(in srgb, var(--color-text-inverse) 20%, transparent);
  font-size: var(--fs-xs);
}

.site-footer__bottom p {
  margin: 0;
}

.site-footer__legal {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2) var(--space-5);
  margin: 0;
  padding: 0;
  list-style: none;
}

@media (min-width: 768px) {
  .site-footer__grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (min-width: 992px) {
  .site-footer {
    padding-bottom: var(--space-5);
  }

  .site-footer__grid {
    grid-template-columns: 2fr 1fr 1.5fr;
  }

  /* Keep bottom-bar text clear of the floating action column */
  .site-footer__bottom {
    padding-right: calc(var(--fab-size) + var(--fab-offset));
  }
}

/* 9. Floating actions ------------------------------------------------------ */
.floating-actions {
  position: fixed;
  right: calc(var(--fab-offset) + env(safe-area-inset-right));
  bottom: calc(var(--fab-offset) + env(safe-area-inset-bottom));
  z-index: var(--z-fab);
  display: flex;
  flex-direction: column;
  gap: var(--fab-gap);
  margin: 0;
  padding: 0;
  list-style: none;
  transition:
    opacity var(--duration-base) var(--ease-standard),
    visibility 0s linear 0s;
}

body.is-nav-open .floating-actions {
  visibility: hidden;
  opacity: 0;
  transition-delay: 0s, var(--duration-base);
}

.fab {
  display: grid;
  place-items: center;
  width: var(--fab-size);
  height: var(--fab-size);
  color: var(--color-text-inverse);
  background-color: var(--color-primary);
  border-radius: var(--radius-pill);
  /* Background-coloured ring keeps the button's edge visible over the green footer */
  box-shadow: 0 0 0 var(--fab-ring-width) var(--color-bg), var(--shadow-md);
  text-decoration: none;
  transition:
    background-color var(--duration-fast) var(--ease-standard),
    transform var(--duration-fast) var(--ease-standard);
}

.fab .icon {
  --icon-size: var(--fab-icon-size);
}

.fab:hover {
  color: var(--color-text-inverse);
  background-color: var(--color-primary-hover);
  transform: translateY(var(--fab-hover-lift));
}

/* Double ring stays visible over both light content and the green footer */
.fab:focus-visible {
  outline: var(--focus-ring-width) solid var(--color-focus);
  outline-offset: var(--focus-ring-offset);
  box-shadow: 0 0 0 var(--focus-ring-offset) var(--color-bg);
}

/* Call in the logo grey so WhatsApp stays the primary action. White icon:
   ivory on this grey falls under 3:1. */
.fab--call {
  color: var(--color-surface);
  background-color: var(--color-neutral);
}

.fab--call:hover {
  color: var(--color-surface);
  background-color: var(--color-neutral-hover);
}

/* 10. Form fields -----------------------------------------------------------
   Pattern for the future contact form:

   <div class="field">
     <label class="field__label" for="name">Name <span class="field__required">(required)</span></label>
     <input class="field__control" id="name" name="name" type="text"
            autocomplete="name" required aria-describedby="name-hint name-error">
     <p class="field__hint" id="name-hint">…</p>
     <p class="field__error" id="name-error" hidden>…</p>
   </div>

   Set aria-invalid="true" on the control and remove [hidden] from the error
   when validation fails. */
.field {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  margin-bottom: var(--space-5);
}

.field__label {
  font-size: var(--fs-sm);
  font-weight: var(--fw-semibold);
  color: var(--color-text);
}

.field__required {
  font-weight: var(--fw-regular);
  color: var(--color-text-muted);
}

.field__control {
  width: 100%;
  min-height: var(--input-height);
  padding: var(--space-3) var(--input-padding-x);
  font: inherit;
  color: var(--color-text);
  background-color: var(--color-surface);
  border: var(--border-width) solid var(--color-border-strong);
  border-radius: var(--input-radius);
  transition: border-color var(--duration-fast) var(--ease-standard);
}

.field__control:hover {
  border-color: var(--color-text-muted);
}

.field__control:focus-visible {
  border-color: var(--color-primary);
  outline: var(--focus-ring-width) solid var(--color-focus);
  outline-offset: var(--focus-ring-offset-tight);
}

.field__control::placeholder {
  color: var(--color-text-muted);
  opacity: 1;
}

textarea.field__control {
  min-height: var(--textarea-min-height);
  resize: vertical;
}

.field__control[aria-invalid="true"] {
  border-color: var(--color-error);
}

.field__hint,
.field__error {
  margin: 0;
  font-size: var(--fs-sm);
}

.field__hint {
  color: var(--color-text-muted);
}

.field__error {
  color: var(--color-error);
  font-weight: var(--fw-medium);
}

/* 11. Reveal-on-scroll ------------------------------------------------------
   Add data-reveal to an element. main.js adds .has-reveal to <html> only when
   IntersectionObserver is supported and motion is allowed, so content is
   never hidden if JavaScript fails. Optional stagger: style="--reveal-delay: 120ms". */
@media (prefers-reduced-motion: no-preference) {
  .has-reveal [data-reveal] {
    opacity: 0;
    transform: translateY(var(--reveal-distance));
    transition:
      opacity var(--duration-slow) var(--ease-out),
      transform var(--duration-slow) var(--ease-out);
    transition-delay: var(--reveal-delay, 0ms);
  }

  .has-reveal [data-reveal].is-revealed {
    opacity: 1;
    transform: none;
  }
}

/* 12. How it works step cards ---------------------------------------------
   Shared by the Home and Services pages. Markup: <ol class="steps-grid">
   of <li><article class="step-card">, each with a .media-frame photo. */
.steps-grid {
  display: grid;
  gap: var(--space-6);
  margin: 0;
  padding: 0;
  list-style: none;
}

/* Keeps the card's offset frame (z-index: -1) above the section background */
.steps-grid>li {
  isolation: isolate;
}

.step-card {
  position: relative;
  height: 100%;
  padding: var(--space-3) var(--space-3) var(--space-5);
  background-color: var(--color-surface);
  border: var(--border-width) solid var(--color-border);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-md);
  transition: box-shadow var(--duration-base) var(--ease-standard);
}

.step-card:hover {
  box-shadow: var(--shadow-brand);
}

/* Offset frame behind the card: shown on the featured card and on hover */
.step-card::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  border: 3px solid var(--color-primary);
  border-radius: var(--radius-md);
  opacity: 0;
  transform: rotate(0deg);
  transition:
    opacity var(--duration-base) var(--ease-standard),
    transform var(--duration-base) var(--ease-out);
}


.step-card:hover::before {
  opacity: 1;
  transform: rotate(-3deg) scale(1.02);
}

/* Holds the photo frame plus the number badge, which overlaps the frame's
   bottom edge and so must sit outside its overflow clip. */
.step-card__media {
  position: relative;
  margin-bottom: var(--space-6);
}

.step-card__media .media-frame {
  --media-ratio: 16 / 10;
}

/* Hovering anywhere on the card zooms its photo; the transition comes from
   .media-frame--zoom. */
@media (prefers-reduced-motion: no-preference) {
  .step-card:hover .media-frame--zoom>img {
    transform: scale(1.06);
  }
}

.step-card__num {
  position: absolute;
  right: var(--space-5);
  bottom: 0;
  display: grid;
  place-items: center;
  width: 2.5rem;
  height: 2.5rem;
  font-size: var(--fs-sm);
  font-weight: var(--fw-semibold);
  color: var(--color-text-inverse);
  background-color: var(--color-primary);
  border: 3px solid var(--color-surface);
  border-radius: var(--radius-pill);
  transform: translateY(50%);
}

.step-card__title {
  margin-bottom: var(--space-2);
  padding-inline: var(--space-3);
  font-size: var(--fs-h4);
}

.step-card__text {
  margin: 0;
  padding-inline: var(--space-3);
  font-size: var(--fs-sm);
  color: var(--color-text-muted);
}

.steps-actions {
  justify-content: center;
  margin-top: var(--space-8);
}

@media (min-width: 576px) {
  .steps-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (min-width: 992px) {
  .steps-grid {
    grid-template-columns: repeat(4, minmax(0, 1fr));
  }
}

/* 13. Page banner -------------------------------------------------------------
   Top of the About, Services and Contact pages: a cover photo under a brand
   gradient, with the h1 and one short line near the bottom left. Must be the
   first child of <main>; the header clearance border stays the page colour
   (background-clip), so the photo starts right under the header.

   <section class="page-banner" aria-labelledby="page-title">
     <img class="page-banner__img" … alt="" fetchpriority="high">
     <div class="site-container page-banner__content">
       <h1 class="page-banner__title" id="page-title">…</h1>
       <p class="page-banner__text">…</p>
     </div>
   </section> */
.page-banner {
  --bs-heading-color: var(--color-text-inverse);
  position: relative;
  isolation: isolate;
  color: var(--color-text-inverse);
  background-color: var(--color-primary-hover);
  /* Shows until the photo loads */
  background-clip: padding-box;
}

/* Photo, then the gradient over it, both behind the text */
.page-banner__img,
.page-banner::after {
  position: absolute;
  inset: 0;
  z-index: -1;
}

.page-banner__img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: 70% 50%;
  /* Photos are cropped with their subject right of centre */
}

.page-banner::after {
  content: "";
  background-image: var(--gradient-banner-sm);
}

.page-banner__content {
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  min-height: var(--banner-height);
  padding-block: var(--space-7) var(--space-6);
}

.page-banner__title {
  margin-bottom: var(--space-3);
}

.page-banner__text {
  max-width: var(--measure-narrow);
  margin-bottom: 0;
}

.page-banner .accent-word {
  color: var(--color-accent-inverse);
}

@media (min-width: 992px) {
  .page-banner::after {
    background-image: var(--gradient-banner);
  }

  .page-banner__content {
    padding-bottom: var(--space-7);
  }

  /* Keep the text on the solid part of the gradient */
  .page-banner__title,
  .page-banner__text {
    max-width: min(var(--measure-narrow), 40vw);
  }
}