/* ===========================================================================
   VGS Group — homepage and shared sections
   =========================================================================== */

/*
 * Two sections sharing a background stack their padding and open twice the
 * space the site uses everywhere else — 227px against the 112px into a
 * coloured band, where the band's own padding is invisible. Where the tone
 * changes the doubling is wanted; where it does not, the second section drops
 * its top padding.
 */
.section:not(.u-deep):not(.u-inverse):not(.u-raised) + .section:not(.u-deep):not(.u-inverse):not(.u-raised) {
  padding-top: 0;
}

.section__head { margin-bottom: var(--space-xl); }
.section__head h2 { margin-bottom: 0; }

/* --- Hero ----------------------------------------------------------------- */
.hero {
  position: relative;
  isolation: isolate;
  display: flex;
  align-items: flex-end;
  /* The top bar sits above and is not part of the hero, so its height comes
     out or the fold lands below the viewport. The bar is pinned to that token
     rather than sized by its contents, so this is right from first paint --
     when it was a guess that a script corrected on load, the hero resized by
     3-4px and jolted everything under it. */
  min-height: calc(100svh - var(--top-bar-h));
  color: var(--text-inverse);
  overflow: hidden;
  /* The header is in flow above this and translucent over it, so the hero is
     pulled back up under it -- the same arrangement .page-hero--image uses.
     Its hairline border sits outside --header-h and has to come up too, or a
     1px line of page ground shows between the bar and the hero. */
  margin-top: calc(-1 * (var(--header-h) + var(--header-border)));
}

/* Charcoal underneath the photograph, not the page ground.
   The hero image is the largest asset on the page and lands a little after
   first paint on a wide viewport — measured at 53ms on the demo host. With no
   ground of its own the hero showed light page background behind white text
   for that moment, then the dark photograph arrived: light to dark is what
   reads as a flash. Starting dark makes the same 53ms a fade. */
/* The charcoal is the floor. inc/hero.php paints a blurred miniature of the
   photograph on top of it in the head, so the gap before the full image arrives
   resolves from blurry to sharp rather than flashing in over a flat colour. */
.hero__media { position: absolute; inset: 0; z-index: -1; background-color: var(--vgs-charcoal); background-size: cover; background-position: center; }

.hero__image {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* Charcoal rather than neutral black, so the footage sits inside the palette
   instead of merely being darkened. */
.hero__scrim {
  position: absolute;
  inset: 0;
  background:
    /* Flat charcoal tint: unifies the footage with the palette and holds
       contrast steady as the frame changes. */
    linear-gradient(rgba(46, 50, 59, 0.25), rgba(46, 50, 59, 0.25)),
    /* Gradient weighted to the foot, where the headline sits. */
    linear-gradient(to top, rgba(9, 10, 12, 0.90) 0%, rgba(9, 10, 12, 0.55) 45%, rgba(9, 10, 12, 0.30) 100%);
}

/* Footage sits over the still, not instead of it. The still is what paints and
   carries the LCP; this appears on top once the video has a frame, so a refused
   autoplay or a slow connection leaves the photograph rather than a black
   rectangle.

   No transition, deliberately. Fading one into the other blends two different
   frames of a moving shot and the doubling reads as a flash. The script holds
   the video on frame 0 until it is revealed, so this swap puts an identical
   image in place and nothing is seen to happen. */
.hero__video {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  z-index: 1;
  opacity: 0;
  /* Hand the video its own compositing layer so the GPU scales and paints it
     rather than the main thread re-rasterising it against the layer behind.
     backface-visibility is the companion half of the same hack: WebKit has long
     shown a one-frame flicker when a layer is promoted without it. */
  transform: translateZ(0);
  backface-visibility: hidden;
}

.hero__video.is-ready { opacity: 1; }

/* Once the footage is up, take the photograph out of the paint. It sits
   directly behind and is covered anyway, but leaving two stacked layers means
   the browser composites a video layer over a still one every frame, which can
   show as a seam on the handover. visibility rather than display: nothing moves,
   and it comes straight back if autoplay is refused and is-ready is removed. */
.hero__video.is-ready + .hero__image { visibility: hidden; }

/* The scrim has to stay above the footage, or the headline loses its ground. */
.hero__scrim { z-index: 2; }

@media (prefers-reduced-motion: reduce) {
  .hero__video { display: none; }
}

.hero__inner { padding-block: calc(var(--header-h) + var(--space-2xl)) var(--space-3xl); }

/* The hero copy settles in once, on load. Staggered so the headline leads and
   the actions arrive last, rather than the whole block moving as one slab. */
@keyframes vgs-rise {
  from { opacity: 0; transform: translateY(1.25rem); }
  to   { opacity: 1; transform: none; }
}

.hero__title,
.hero__tagline,
.hero__actions {
  animation: vgs-rise 700ms var(--ease) both;
}

.hero__title   { animation-delay: 120ms; }
.hero__tagline { animation-delay: 260ms; }
.hero__actions { animation-delay: 400ms; }

@media (prefers-reduced-motion: reduce) {
  .hero__title,
  .hero__tagline,
  .hero__actions {
    animation: none;
    opacity: 1;
    transform: none;
  }
}

.hero__title {
  max-width: 18ch;
  margin-bottom: var(--space-s);
  color: var(--vgs-snow);
  text-shadow: 0 2px 24px rgba(9, 10, 12, 0.45);
}

.hero__tagline {
  max-width: 46ch;
  font-size: var(--step-1);
  color: var(--vgs-snow);
  margin-bottom: var(--space-l);
}

.hero__actions { display: flex; flex-wrap: wrap; gap: var(--space-s); margin: 0; }
/* Silver rather than snow. It is the only lighter-than-white value in the
   palette, and it keeps the primary action distinct from the ghost button
   beside it — a frosted or charcoal fill collapses into looking like the
   secondary. Silver on charcoal text measures 6.8:1, clear of AA. */
.hero__actions .btn,
.hero__actions .wp-block-button > .wp-block-button__link {
  background: var(--vgs-silver);
  color: var(--vgs-charcoal);
  border-color: var(--vgs-silver);
}
.hero__actions .btn:hover,
.hero__actions .wp-block-button > .wp-block-button__link:hover {
  background: var(--vgs-silver-75);
  border-color: var(--vgs-silver-75);
}
.hero__actions .btn--ghost,
.hero__actions .wp-block-button.is-style-outline > .wp-block-button__link { background: transparent; color: var(--text-inverse); border-color: var(--vgs-snow); }
.hero__actions .btn--ghost:hover,
.hero__actions .wp-block-button.is-style-outline > .wp-block-button__link:hover { background: var(--vgs-snow); color: var(--vgs-charcoal); }
.hero :focus-visible { outline-color: var(--focus-ring-inverse); }

/* --- Intro ---------------------------------------------------------------- */
.intro__inner { text-align: center; }

.intro__title {
  max-width: 22ch;
  margin-inline: auto;
}

/* The heading carries its own break, so it must not be re-balanced or
   collapsed onto one line. */
.intro__title {
  text-wrap: initial;
}

@media (min-width: 64rem) {
  .intro__title { max-width: none; }
}

.intro__body {
  font-size: var(--step-1);
  color: var(--text-muted);
  max-width: 86ch;
  margin-inline: auto;
}

.intro__body + .intro__body { margin-top: var(--space-m); }

/* Rule beneath the heading, drawn out from the centre as it comes into view.
   Drawn at full width by default; only collapsed when the reveal script is
   present to draw it. */
.intro__rule {
  display: block;
  width: min(9rem, 40%);
  height: 2px;
  margin: var(--space-m) auto var(--space-l);
  background: var(--vgs-charcoal);
  transform-origin: center;
}

.has-js .intro__rule {
  transform: scaleX(0);
  transition: transform 900ms var(--ease) 120ms;
}

/* The rule is a core separator in the page's blocks: clear the border and
   opacity WordPress gives separators, so only the drawn bar remains. */
hr.intro__rule { border: 0; opacity: 1; }

.has-js .intro__rule.is-revealed { transform: scaleX(1); }

/* --- Scroll reveal --------------------------------------------------------
   Scoped to .has-js, set by the reveal script itself, so nothing is ever
   hidden unless the code that shows it again is running. */
.has-js [data-reveal]:not(.intro__rule) {
  opacity: 0;
  transform: translateY(1.25rem);
}

.has-js [data-reveal] {
  transition:
    opacity 700ms var(--ease) var(--reveal-delay, 0ms),
    transform 700ms var(--ease) var(--reveal-delay, 0ms);
}

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

/* --- Division grid (2x2) --------------------------------------------------
   Four cards, wide enough that landscape architectural photography still reads.
   VDK separates its divisions by colour; VGS has no accent colour, so the
   difference is carried by the brand's polygon instead — each card wipes open
   on a 45deg angle, alternating direction so the grid does not read as a
   repeating pattern. */
.division-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--space-xs);
  margin: 0;
  padding: 0;
  list-style: none;
}

@media (min-width: 48rem) {
  .division-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

.division-card { margin: 0; }

.division-card__link {
  --tagline-slot: 2.9rem;
  position: relative;
  display: flex;
  align-items: flex-end;
  min-height: 20rem;
  padding: var(--space-l);
  overflow: hidden;
  text-decoration: none;
  color: var(--text-inverse);
  background: var(--vgs-charcoal);
  /*
   * The border is reserved at rest so the card does not shift when it gains
   * one on hover. Clipping the background to the padding box stops that
   * background painting through the transparent border, which otherwise reads
   * as a permanent charcoal frame against the black section.
   */
  border: 2px solid transparent;
  background-clip: padding-box;
  transition: transform var(--dur) var(--ease), border-color var(--dur) var(--ease);
}

@media (min-width: 48rem) {
  .division-card__link { min-height: min(38vh, 22rem); }
}

.division-card__image {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform var(--dur-slow) var(--ease);
}

.division-card__scrim {
  position: absolute;
  inset: 0;
  background: linear-gradient(to top, rgba(9, 10, 12, 0.85) 0%, rgba(9, 10, 12, 0.35) 55%, rgba(9, 10, 12, 0.15) 100%);
}

/* The polygon wipe. Skew holds the brand's 45deg angle at any card size; the
   block is parked below the card and slides up on hover. */
.division-card__wipe {
  position: absolute;
  left: -25%;
  right: -25%;
  bottom: 0;
  height: 78%;
  background: linear-gradient(to top, rgba(46, 50, 59, 0.96) 0%, rgba(46, 50, 59, 0.72) 60%, rgba(46, 50, 59, 0) 100%);
  transform: var(--poly-skew) translateY(105%);
  transform-origin: bottom left;
  transition: transform var(--dur-slow) var(--ease);
}

/* Alternate the wipe direction so a 2x2 grid does not read as one repeated
   motion. Brand rule: keep to a single axis, never rotate. */
.division-card--2 .division-card__wipe,
.division-card--3 .division-card__wipe {
  transform: var(--poly-skew-reverse) translateY(105%);
  transform-origin: bottom right;
}

/*
 * The tagline holds a fixed slot in the flow so every card measures the same,
 * and the whole block is parked down by exactly that slot. At rest the name
 * therefore sits at the foot of the card with no gap beneath it, and the
 * tagline is out of sight below. On hover the block slides up by the same
 * amount: the name rises and the tagline takes the space it leaves.
 */
.division-card__body {
  position: relative;
  display: block;
  transform: translateY(var(--tagline-slot));
  transition: transform var(--dur) var(--ease);
}

.division-card__name {
  /*
   * Two lines of space are reserved and the text sits at the bottom of it, so
   * a one-line name and a two-line one put their last line in the same place.
   * The longest name wraps on narrow cards no matter how the type is sized;
   * reserving the space is what keeps the grid aligned, not preventing the
   * wrap.
   */
  display: flex;
  align-items: flex-end;
  min-height: 2.3em;
  font-family: var(--font-display);
  font-size: clamp(1.05rem, 0.85rem + 0.9vw, 1.5rem);
  font-weight: 700;
  line-height: 1.15;
  letter-spacing: var(--tracking-display);
  text-transform: uppercase;
}

.division-card__tagline {
  display: block;
  margin-top: var(--space-2xs);
  color: var(--vgs-silver);
  font-size: var(--step--1);
  /*
   * The tagline is hidden until hover but still occupies space, so its height
   * decides where the name sits. Left to itself, a one-line tagline and a
   * two-line one put their names at different heights across the grid. Two
   * lines are reserved on every card so the names align regardless.
   */
  /* A fixed slot, not a minimum: the tagline wraps to one or two lines
     depending on card width, and any variation would move the name. */
  height: var(--tagline-slot);
  opacity: 0;
  transform: translateY(0.5rem);
  transition: opacity var(--dur) var(--ease), transform var(--dur) var(--ease);
}

.division-card__link:hover,
.division-card__link:focus-visible {
  border-color: var(--vgs-silver);
  transform: translateY(-4px);
}

.division-card__link:hover .division-card__image,
.division-card__link:focus-visible .division-card__image { transform: scale(1.04); }

.division-card__link:hover .division-card__wipe,
.division-card__link:focus-visible .division-card__wipe {
  transform: var(--poly-skew) translateY(28%);
}

.division-card--2 .division-card__link:hover .division-card__wipe,
.division-card--2 .division-card__link:focus-visible .division-card__wipe,
.division-card--3 .division-card__link:hover .division-card__wipe,
.division-card--3 .division-card__link:focus-visible .division-card__wipe {
  transform: var(--poly-skew-reverse) translateY(28%);
}

.division-card__link:hover .division-card__body,
.division-card__link:focus-visible .division-card__body {
  transform: translateY(0);
}

.division-card__link:hover .division-card__tagline,
.division-card__link:focus-visible .division-card__tagline {
  opacity: 1;
  transform: translateY(0);
}

/* Touch devices get no hover, so the block rests in its raised position with
   the tagline already showing. */
@media (hover: none) {
  .division-card__body { transform: none; }
  .division-card__tagline { opacity: 1; transform: none; }
  .division-card__wipe { transform: var(--poly-skew) translateY(45%); }
  .division-card--2 .division-card__wipe,
  .division-card--3 .division-card__wipe { transform: var(--poly-skew-reverse) translateY(45%); }
}

/* --- Why ------------------------------------------------------------------ */
.why__list {
  display: grid;
  gap: var(--space-l);
  grid-template-columns: 1fr;
  margin: 0;
  padding: 0;
  list-style: none;
}

/* Two columns, not four: at a quarter of the container the longer titles wrap
   to two lines and the rows stop lining up. */
@media (min-width: 40rem) { .why__list { grid-template-columns: repeat(2, minmax(0, 1fr)); } }

@media (min-width: 64rem) {
  .why__list { gap: var(--space-xl) var(--space-2xl); }
}

.why__item {
  padding-top: var(--space-s);
  border-top: 2px solid var(--vgs-charcoal);
}

.why__item-title { font-size: var(--step-1); margin-bottom: var(--space-2xs); }
.why__item p { color: var(--text-muted); font-size: var(--step--1); margin: 0; }

/* --- Stats ---------------------------------------------------------------- */
.stats__list {
  display: grid;
  gap: var(--space-l);
  grid-template-columns: repeat(2, minmax(0, 1fr));
  margin: 0;
  padding: 0;
  list-style: none;
  text-align: center;
}

@media (min-width: 48rem) { .stats__list { grid-template-columns: repeat(4, minmax(0, 1fr)); } }

/* The figure and label are paragraphs in the blocks: no paragraph margin or
   reading measure inside a stat. */
.stats__item > p { margin-bottom: 0; max-width: none; }

.stats__label { overflow-wrap: break-word; }

.stats__figure {
  display: block;
  font-family: var(--font-display);
  font-size: var(--step-5);
  font-weight: 700;
  line-height: 1;
  color: var(--text-inverse);
}

.stats__label {
  display: block;
  margin-top: var(--space-2xs);
  font-size: var(--step--1);
  text-transform: uppercase;
  letter-spacing: var(--tracking-caps);
  color: var(--vgs-silver);
}

/* --- Process -------------------------------------------------------------- */
.process__list {
  display: grid;
  gap: var(--space-l);
  grid-template-columns: 1fr;
  margin: 0;
  padding: 0;
  list-style: none;
  counter-reset: none;
}

/* Two columns, matching why-choose-us: at a quarter width "Design & Product
   Selection" wraps and the rows stop aligning. The numbering carries the
   sequence, so a 2x2 still reads in order. */
@media (min-width: 40rem) { .process__list { grid-template-columns: repeat(2, minmax(0, 1fr)); } }

@media (min-width: 64rem) {
  .process__list { gap: var(--space-xl) var(--space-2xl); }
}

.process__number {
  display: block;
  font-family: var(--font-display);
  font-size: var(--step-2);
  font-weight: 700;
  color: var(--vgs-silver);
  /* Rule sits under the number, matching the one above each why-choose-us
     point, so the two sections share a structure down the page. */
  padding-bottom: var(--space-xs);
  margin-bottom: var(--space-s);
  border-bottom: 2px solid var(--vgs-charcoal);
}

.process__title { font-size: var(--step-1); margin-bottom: var(--space-2xs); }
/* The number is a paragraph too; it keeps its own styling. */
.process__item p:not(.process__number) { color: var(--text-muted); font-size: var(--step--1); margin: 0; }
.process__item .process__number { margin: 0 0 var(--space-s); max-width: none; }

/* --- Work grid ------------------------------------------------------------ */
.work__grid {
  display: grid;
  gap: var(--space-xs);
  grid-template-columns: 1fr;
  margin: 0 0 var(--space-l);
  padding: 0;
  list-style: none;
}

@media (min-width: 40rem) { .work__grid { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (min-width: 64rem) { .work__grid { grid-template-columns: repeat(3, minmax(0, 1fr)); } }

.work__link {
  position: relative;
  display: flex;
  align-items: flex-end;
  min-height: 15rem;
  padding: var(--space-m);
  overflow: hidden;
  text-decoration: none;
  color: var(--text-inverse);
  background: var(--vgs-charcoal);
}

.work__image {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform var(--dur-slow) var(--ease);
}

/* Light at rest so the photograph carries the card; the wipe supplies the
   contrast the text needs once it appears. */
.work__scrim {
  position: absolute;
  inset: 0;
  background: linear-gradient(to top, rgba(9, 10, 12, 0.45) 0%, rgba(9, 10, 12, 0.05) 65%);
}

/* The same polygon wipe as the division cards: skew holds the brand's 45deg
   angle at any card size, and the block is parked below until hovered. */
.work__wipe {
  position: absolute;
  left: -25%;
  right: -25%;
  bottom: 0;
  height: 78%;
  background: linear-gradient(to top, rgba(9, 10, 12, 0.96) 0%, rgba(9, 10, 12, 0.72) 60%, rgba(9, 10, 12, 0) 100%);
  transform: var(--poly-skew) translateY(105%);
  transform-origin: bottom left;
  transition: transform var(--dur-slow) var(--ease);
}

.work__item--2 .work__wipe,
.work__item--3 .work__wipe {
  transform: var(--poly-skew-reverse) translateY(105%);
  transform-origin: bottom right;
}

.work__link:hover .work__image,
.work__link:focus-visible .work__image { transform: scale(1.05); }

.work__link:hover .work__wipe,
.work__link:focus-visible .work__wipe { transform: var(--poly-skew) translateY(22%); }

.work__item--2 .work__link:hover .work__wipe,
.work__item--2 .work__link:focus-visible .work__wipe,
.work__item--3 .work__link:hover .work__wipe,
.work__item--3 .work__link:focus-visible .work__wipe {
  transform: var(--poly-skew-reverse) translateY(22%);
}

/* Neither the name nor the location shows until the card is hovered. */
.work__body {
  position: relative;
  opacity: 0;
  transform: translateY(0.75rem);
  transition: opacity var(--dur) var(--ease), transform var(--dur) var(--ease);
}

.work__link:hover .work__body,
.work__link:focus-visible .work__body {
  opacity: 1;
  transform: none;
}

/* Touch devices never get the hover, so the card rests in its revealed state. */
@media (hover: none) {
  .work__body { opacity: 1; transform: none; }
  .work__wipe { transform: var(--poly-skew) translateY(40%); }
  .work__item--2 .work__wipe,
  .work__item--3 .work__wipe { transform: var(--poly-skew-reverse) translateY(40%); }
}

.work__title {
  display: block;
  font-family: var(--font-display);
  font-size: var(--step-1);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: var(--tracking-display);
}

.work__meta {
  display: block;
  margin-top: 0.15rem;
  font-size: var(--step--1);
  color: var(--vgs-silver);
}

.work__more { margin: 0; }

/* --- CTA ------------------------------------------------------------------ */
.cta__inner { text-align: center; }
.cta__inner p { margin-inline: auto; }
.cta__actions { display: flex; flex-wrap: wrap; gap: var(--space-s); justify-content: center; margin-top: var(--space-l); }

/* A tap-to-call button earns its place on a phone and not on a desktop, where
   the tel: link mostly opens something unwanted. The number itself is not lost
   — it stays in the footer and in the emergency line below. */
@media (min-width: 48rem) {
  .cta__phone { display: none; }
}
/* The 24/7 emergency line. The client asked for it to stand out wherever it
   appears, so it is set in the display face at full contrast, not as a
   footnote. */
.cta__note {
  margin-top: var(--space-l);
  font-family: var(--font-display);
  font-size: var(--step-1);
  font-weight: 700;
  line-height: 1.3;
  color: var(--text-inverse);
}

/* --- Page intro (About and other content pages) ---------------------------
   The section keeps its own bottom padding, because when the next section is
   a different colour that padding is the only space beneath the content — the
   next section's padding sits inside its own band.
   Where the next section shares this background, the two would stack and read
   as twice the space above, so the following section drops its top padding
   instead. */
.page-intro + .section:not(.u-deep):not(.u-inverse):not(.u-raised) { padding-top: 0; }

.page-intro__inner { text-align: center; }


/* Running text keeps a readable measure, but full-width blocks — a media and
   text pair, a wide image — must be free of it, or they are squeezed into a
   text column and stop working as layouts. The measure therefore sits on the
   text children rather than on their container. */
/*
 * The measure is resolved once, here, at the body-text size. ch is relative
 * to each element's own font, so 68ch on a heading is far wider than 68ch on
 * the paragraph below it: headings ran the full container while the text sat
 * in a centred column. Registered as a length, the value computes on this
 * element and children inherit the result, so headings, lists and paragraphs
 * share one column edge.
 */
@property --prose-measure {
  syntax: '<length>';
  inherits: true;
  initial-value: 0px;
}

.page-intro__content {
  --prose-measure: 68ch;
  text-align: left;
  font-size: var(--step-1);
  color: var(--text-muted);
}

.page-intro__content > :is(p, h2, h3, h4, ul, ol, blockquote) {
  max-width: 68ch; /* Fallback where @property is unsupported. */
  max-width: var(--prose-measure);
  margin-inline: auto;
}

/*
 * A lead paragraph with nothing beside it. Left-aligned text centred in a wide
 * container reads as floating — it works on About only because a photograph
 * anchors it. Centred, at the measure the homepage introduction uses, it sits
 * under the hero as a proper opening statement.
 */
.page-intro--lead .page-intro__content { text-align: center; }

.page-intro--lead .page-intro__content > :is(p, h2, h3) {
  max-width: 74ch;
  font-size: var(--step-1);
}

/* Both rules carry the same specificity, so the adjacent-sibling rule wins
   where it applies. Written the other way round — as a p selector — the zero
   margin outranks it and every paragraph runs together. */
.page-intro__content > * { margin-block: 0; }
.page-intro__content > * + * { margin-top: var(--space-m); }

.page-intro__content strong { color: var(--text); }

/* --- Page hero ------------------------------------------------------------
   With a Featured image it is a full-bleed banner; without one it falls back
   to a heading on the page ground, so a page without a photo still reads. */
.page-hero {
  position: relative;
  isolation: isolate;
  padding-block: var(--space-2xl) var(--space-xl);
  text-align: center;
}

/* Without a photo the hero shares the page background and stops reading as a
   band of its own, so it takes charcoal and runs up behind the header. */
.page-hero:not(.page-hero--image) {
  margin-top: calc(-1 * var(--header-h));
  padding-top: calc(var(--header-h) + var(--space-2xl));
  background: var(--vgs-charcoal);
  color: var(--text-inverse);
}

.page-hero:not(.page-hero--image) .page-hero__title { color: var(--vgs-snow); }
.page-hero:not(.page-hero--image) .page-hero__subtitle,
.page-hero:not(.page-hero--image) .post-meta { color: var(--vgs-silver); }
.page-hero:not(.page-hero--image) .post-meta a { color: var(--vgs-silver); }
.page-hero:not(.page-hero--image) :focus-visible { outline-color: var(--focus-ring-inverse); }

.page-hero--image {
  display: flex;
  align-items: center;
  min-height: min(60svh, 32rem);
  padding-block: calc(var(--header-h) + var(--space-2xl)) var(--space-2xl);
  color: var(--text-inverse);
}

.page-hero__media { position: absolute; inset: 0; z-index: -1; overflow: hidden; background-color: var(--vgs-charcoal); background-size: cover; background-position: center; }

.page-hero__image { width: 100%; height: 100%; object-fit: cover; }

.page-hero__scrim {
  position: absolute;
  inset: 0;
  background:
    linear-gradient(rgba(46, 50, 59, 0.25), rgba(46, 50, 59, 0.25)),
    linear-gradient(to top, rgba(9, 10, 12, 0.72) 0%, rgba(9, 10, 12, 0.34) 60%, rgba(9, 10, 12, 0.28) 100%);
}

.page-hero__inner { width: 100%; }

.page-hero__title { margin-bottom: var(--space-2xs); max-width: 22ch; margin-inline: auto; }
.page-hero--image .page-hero__title { color: var(--vgs-snow); text-shadow: 0 2px 24px rgba(9, 10, 12, 0.45); }

.page-hero__subtitle {
  max-width: 52ch;
  margin-inline: auto;
  margin-bottom: 0;
  font-size: var(--step-1);
  color: var(--text-muted);
}

/* On desktop there is room for the subtitle on one line. */
@media (min-width: 64rem) {
  .page-hero__subtitle {
    max-width: none;
    text-wrap: nowrap;
  }
}

.page-hero--image .page-hero__subtitle { color: var(--vgs-silver); }

/* The overlay header needs the hero to start at the top of the page. */
.page-hero--image { margin-top: calc(-1 * (var(--header-h) + var(--header-border))); }

/* --- Core blocks in page content ------------------------------------------
   Styled so the blocks an editor reaches for produce something that matches
   the rest of the site without them having to think about it. */
.page-intro__content .wp-block-media-text {
  gap: clamp(var(--space-l), 4vw, var(--space-2xl));
  margin-block: var(--space-2xl);
  align-items: center;
}

/*
 * The photo holds its place while the text scrolls past it. This is the
 * default rather than something to opt into, so a block rebuilt from scratch
 * behaves the same as this one.
 *
 * It costs nothing where it cannot apply: sticky only moves an element that
 * has room to move, so when the image is as tall as the text — or taller — it
 * simply sits still.
 *
 * align-self must be start. A stretched grid item fills the whole row, leaving
 * no room to move within, and sticky then silently does nothing. Setting it on
 * the media alone keeps the container centring the text, so a short paragraph
 * beside a tall photo still reads as a pair.
 */
.page-intro__content .wp-block-media-text__media {
  position: sticky;
  top: calc(var(--header-h) + var(--space-m));
  align-self: start;
}

.admin-bar .page-intro__content .wp-block-media-text__media {
  top: calc(var(--header-h) + var(--space-m) + var(--admin-bar-h));
}

/* Opt out by adding is-not-sticky under Advanced → Additional CSS class. */
.page-intro__content .wp-block-media-text.is-not-sticky .wp-block-media-text__media {
  position: static;
}

/* Stack on phones — two narrow columns serve neither the text nor the photo. */
@media (max-width: 47.9375rem) {
  .page-intro__content .wp-block-media-text {
    display: block;
  }

  /* Stacked, the image follows the text, so the separation belongs above it —
     as a bottom margin it lands outside the block instead of between them. */
  .page-intro__content .wp-block-media-text__media {
    margin-top: var(--space-m);
    margin-bottom: 0;
  }

  /* Image first, when the block is set that way. */
  .page-intro__content .wp-block-media-text.has-media-on-the-left .wp-block-media-text__media {
    margin-top: 0;
    margin-bottom: var(--space-m);
  }

  /* Stacked: the photo and the text are no longer side by side, so there is
     nothing for it to stick alongside. */
  .page-intro__content .wp-block-media-text__media { position: static; }
}

.page-intro__content .wp-block-media-text__media img {
  width: 100%;
  height: auto;
  border-radius: var(--radius);
}

.page-intro__content .wp-block-media-text__content {
  padding: 0;
}

.page-intro__content .wp-block-media-text__content > * + * { margin-top: var(--space-s); }
.page-intro__content .wp-block-media-text__content > p { max-width: none; margin-inline: 0; }

/* The paragraph's own trailing margin sits inside the block and pushes the
   next section down past the spacing above the story. */
.page-intro__content .wp-block-media-text__content > :first-child { margin-top: 0; }
.page-intro__content .wp-block-media-text__content > :last-child { margin-bottom: 0; }

.page-intro__content :is(h2, h3) {
  color: var(--text);
  margin-bottom: var(--space-2xs);
}

.page-intro__content h2 { font-size: var(--step-3); }
.page-intro__content h3 { font-size: var(--step-2); }

.page-intro__content .wp-block-image img { border-radius: var(--radius); }
.page-intro__content figure { margin-inline: 0; }

/*
 * Blocks carry their own vertical margins so they breathe between paragraphs,
 * but at the top or bottom of the content those margins stack on the section
 * padding and open a gap far larger than the rhythm between every other
 * section. Declared last so it wins on source order at equal specificity.
 */
.page-intro__content > :first-child { margin-top: 0; }
.page-intro__content > :last-child { margin-bottom: 0; }

/* --- Contact cards --------------------------------------------------------- */
.contact-cards {
  display: grid;
  gap: var(--space-l);
  grid-template-columns: 1fr;
  margin: 0;
  padding: 0;
  list-style: none;
  text-align: left;
}


/* Four cards in a 2x2, matching the why-choose-us and process grids. Three
   columns orphans the fourth card; four columns squeezes each one until the
   address and the hours both break mid-phrase. */
@media (min-width: 48rem) {
  .contact-cards { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--space-xl); }
}

.contact-card {
  padding-top: var(--space-s);
  border-top: 2px solid var(--vgs-charcoal);
}

.contact-card__label {
  font-size: var(--step--1);
  text-transform: uppercase;
  letter-spacing: var(--tracking-caps);
  color: var(--text-muted);
  margin-bottom: var(--space-2xs);
}

.contact-card__value {
  display: block;
  font-family: var(--font-display);
  font-size: var(--step-2);
  font-weight: 700;
  line-height: 1.2;
  color: var(--text);
  text-decoration: none;
  overflow-wrap: anywhere;   /* A long address should wrap, not overflow. */
}

a.contact-card__value:hover,
a.contact-card__value:focus-visible { text-decoration: underline; text-underline-offset: 0.15em; }

.contact-card__value--address { font-style: normal; }

.contact-card__note {
  margin: var(--space-2xs) 0 0;
  font-size: var(--step--1);
  color: var(--text-muted);
  max-width: 34ch;
}

/* The 24/7 line, raised to match the CTA band's emphasis. */
.contact-card__note--emergency {
  font-size: var(--step-0);
  font-weight: 600;
  color: var(--text);
}

/* --- Blog ------------------------------------------------------------------ */
.blog__layout {
  display: grid;
  gap: var(--space-2xl) var(--space-xl);
  grid-template-columns: 1fr;
  align-items: start;
}

@media (min-width: 64rem) {
  .blog__layout { grid-template-columns: minmax(0, 1fr) 17rem; }
}

.blog__main { min-width: 0; }

/* --- Post card ------------------------------------------------------------- */
.post-card {
  display: grid;
  gap: var(--space-m);
  grid-template-columns: 1fr;
  padding-bottom: var(--space-l);
  margin-bottom: var(--space-l);
  border-bottom: 1px solid var(--border);
}

@media (min-width: 40rem) {
  .post-card { grid-template-columns: 14rem minmax(0, 1fr); gap: var(--space-l); }
}

/* No rule under the final card, and no space reserved for one. Left in, the
   padding and margin sat on top of the layout's row gap, which reads as a
   large hole above the sidebar once the two columns stack. Pagination brings
   its own margin-top, so it stays clear either way. */
.post-card:last-of-type {
  padding-bottom: 0;
  margin-bottom: 0;
  border-bottom: 0;
}

.post-card__media { display: block; overflow: hidden; border-radius: var(--radius); }

.post-card__media img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  aspect-ratio: 4 / 3;
  transition: transform var(--dur-slow) var(--ease);
}

.post-card:hover .post-card__media img { transform: scale(1.04); }

.post-card__title { font-size: var(--step-2); margin-bottom: var(--space-2xs); }
.post-card__title a { text-decoration: none; }
.post-card__title a:hover { text-decoration: underline; text-underline-offset: 0.15em; }

.post-card__excerpt { color: var(--text-muted); margin-bottom: var(--space-2xs); }

.post-card__more { margin: 0; }

.post-card__more a {
  font-family: var(--font-display);
  font-size: var(--step--1);
  text-transform: uppercase;
  letter-spacing: var(--tracking-caps);
  text-decoration: none;
}

.post-card__more a:hover { text-decoration: underline; text-underline-offset: 0.2em; }

/* --- Post meta -------------------------------------------------------------- */
.post-meta {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2xs) var(--space-s);
  margin: 0 0 var(--space-2xs);
  font-size: var(--step--1);
  color: var(--text-muted);
  max-width: none;
}

.post-meta a { color: inherit; }
.post-meta__cats { text-transform: uppercase; letter-spacing: var(--tracking-caps); }

/* --- Sidebar ---------------------------------------------------------------- */
.blog-sidebar { display: grid; gap: var(--space-xl); }

@media (min-width: 64rem) {
  /* Holds its place while the article scrolls past. The grid already aligns
     items to the start, which is what leaves room for it to move. */
  .blog-sidebar {
    position: sticky;
    top: calc(var(--header-h) + var(--space-m));
  }

  .admin-bar .blog-sidebar { top: calc(var(--header-h) + var(--space-m) + var(--admin-bar-h)); }
}

.blog-sidebar__title {
  font-size: var(--step--1);
  text-transform: uppercase;
  letter-spacing: var(--tracking-caps);
  color: var(--text-muted);
  padding-bottom: var(--space-2xs);
  margin-bottom: var(--space-s);
  border-bottom: 2px solid var(--vgs-charcoal);
}

.blog-sidebar__list { margin: 0; padding: 0; list-style: none; display: grid; gap: var(--space-xs); }

.blog-sidebar__list li { display: flex; justify-content: space-between; gap: var(--space-xs); }

.blog-sidebar__list a { text-decoration: none; }
.blog-sidebar__list a:hover { text-decoration: underline; text-underline-offset: 0.15em; }

.blog-sidebar__count { color: var(--text-muted); font-size: var(--step--1); }

.blog-sidebar__list--recent li { flex-direction: column; gap: 2px; }
.blog-sidebar__list--recent time { font-size: var(--step--1); color: var(--text-muted); }

/* --- Single post ------------------------------------------------------------ */

/* The article already sits in a column beside the sidebar, so that column is
   the measure. Constraining the text again inside it leaves the paragraphs
   narrower than the image above them and visibly inset from it. */
.post-single .page-intro__content > :is(p, h2, h3, h4, ul, ol, blockquote) {
  max-width: none;
  margin-inline: 0;
}

/* The non-image rule adds the header height to the top, so the visible space
   above the title would otherwise be larger than the space below the meta. */
.post-hero { padding-block: var(--space-2xl); }
/* A post title is a sentence, where every other page title on the site is a
   word or two. At the shared display step a 55-character headline set five
   lines at 390px. This starts a step lower on a phone and converges on the
   same size by 1700px, so tablet and desktop keep the two-line setting they
   already had. */
.post-hero .page-hero__title {
  max-width: 26ch;
  font-size: clamp(2.07rem, 1.354rem + 3.29vw, 4.74rem);
}
.post-hero .post-meta {
  justify-content: center;
  /* Its trailing margin sits inside the hero and makes the space below the
     meta larger than the space above the title. */
  margin-bottom: 0;
}

.post-single__media { margin: 0 0 var(--space-l); }
.post-single__media img { width: 100%; height: auto; border-radius: var(--radius); }

/* --- Share ------------------------------------------------------------------- */
.post-share {
  margin-top: var(--space-xl);
  padding-block: var(--space-l);
  border-top: 1px solid var(--border);
  text-align: center;
}

.post-share__title {
  font-size: var(--step--1);
  text-transform: uppercase;
  letter-spacing: var(--tracking-caps);
  color: var(--text-muted);
  margin-bottom: var(--space-s);
}

.post-share__list {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: var(--space-2xs);
  margin: 0;
  padding: 0;
  list-style: none;
}

/* The palette carries no brand colours, so the marks are set in charcoal
   rather than each network's own colour. */
.post-share__link {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  padding: 0;
  color: var(--text-muted);
  background: transparent;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  cursor: pointer;
  transition: color var(--dur-fast) var(--ease), border-color var(--dur-fast) var(--ease);
}

.post-share__link:hover,
.post-share__link:focus-visible {
  color: var(--text);
  border-color: var(--vgs-charcoal);
}

/* Out of flow: the confirmation is transient, and reserving a line for it
   permanently unbalances the block against its own padding. */
.post-share__status {
  position: absolute;
  inset-inline: 0;
  margin: var(--space-2xs) 0 0;
  font-size: var(--step--1);
  color: var(--text-muted);
}

.post-share { position: relative; }

/* --- Previous / next --------------------------------------------------------- */
.post-nav {
  display: grid;
  gap: var(--space-m);
  grid-template-columns: 1fr;
  /* The share block above supplies the separation with its own padding. */
  padding-top: var(--space-l);
  border-top: 1px solid var(--border);
}

@media (min-width: 40rem) { .post-nav { grid-template-columns: 1fr 1fr; } }

.post-nav__link {
  display: flex;
  align-items: center;
  gap: var(--space-2xs);
  min-width: 0;
  text-decoration: none;
}

.post-nav__link--next { justify-content: flex-end; text-align: right; }

.post-nav__text { min-width: 0; }

.post-nav__arrow { flex: none; color: var(--text-muted); }
.post-nav__link:hover .post-nav__arrow { color: var(--text); }

.post-nav__label {
  display: block;
  font-size: var(--step--1);
  text-transform: uppercase;
  letter-spacing: var(--tracking-caps);
  color: var(--text-muted);
}

/* One line with an ellipsis, so a long title and a short one occupy the same
   height and the two sides stay level. */
.post-nav__title {
  display: block;
  font-family: var(--font-display);
  font-weight: 700;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.post-nav__link:hover .post-nav__title { text-decoration: underline; text-underline-offset: 0.15em; }

/* --- Related ------------------------------------------------------------------ */
.related { margin-top: var(--space-2xl); }

.related__title {
  font-size: var(--step-2);
  padding-bottom: var(--space-2xs);
  margin-bottom: var(--space-l);
  border-bottom: 2px solid var(--vgs-charcoal);
}

.related__list {
  display: grid;
  gap: var(--space-l) var(--space-xl);
  grid-template-columns: 1fr;
  margin: 0;
  padding: 0;
  list-style: none;
}

@media (min-width: 40rem) { .related__list { grid-template-columns: repeat(2, minmax(0, 1fr)); } }

/* Thumbnail beside the title rather than above it: with a full-width image
   each entry takes as much room as a post card, and a list of six dwarfs the
   article it belongs to. */
.related__link {
  display: grid;
  grid-template-columns: 7rem minmax(0, 1fr);
  /* Two rows so the title and date stack in the second column. With a single
     row the date becomes a third item and wraps beneath the thumbnail. */
  grid-template-rows: auto auto;
  column-gap: var(--space-s);
  align-items: start;
  text-decoration: none;
}

.related__link img {
  grid-column: 1;
  grid-row: 1 / span 2;
  align-self: start;
  width: 100%;
  aspect-ratio: 4 / 3;
  object-fit: cover;
  border-radius: var(--radius);
  margin: 0;
}

.related__name { grid-column: 2; grid-row: 1; }
.related__date { grid-column: 2; grid-row: 2; }

.related__name {
  display: block;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: var(--step-0);
  line-height: 1.25;
}
.related__link:hover .related__name { text-decoration: underline; text-underline-offset: 0.15em; }
.related__date { display: block; margin-top: 2px; font-size: var(--step--1); color: var(--text-muted); }

/* --- Pagination ---------------------------------------------------------------- */
.pagination { margin-top: var(--space-xl); }

.pagination .nav-links {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2xs);
  align-items: center;
}

.pagination .page-numbers {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 2.5rem;
  height: 2.5rem;
  padding-inline: var(--space-2xs);
  font-family: var(--font-display);
  font-size: var(--step--1);
  text-decoration: none;
  border: 1px solid var(--border);
  border-radius: var(--radius);
}

.pagination .page-numbers.current { background: var(--vgs-charcoal); color: var(--text-inverse); border-color: var(--vgs-charcoal); }
.pagination .page-numbers:hover:not(.current) { border-color: var(--vgs-charcoal); }

.blog-sidebar__tags {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2xs);
  margin: 0;
  padding: 0;
  list-style: none;
}

.blog-sidebar__tags a {
  display: inline-block;
  padding: 0.3em 0.7em;
  font-size: var(--step--1);
  text-decoration: none;
  color: var(--text-muted);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  transition: border-color var(--dur-fast) var(--ease), color var(--dur-fast) var(--ease);
}

.blog-sidebar__tags a:hover,
.blog-sidebar__tags a:focus-visible {
  color: var(--text);
  border-color: var(--vgs-charcoal);
  text-decoration: none;
}

/* --- Our Work archive ------------------------------------------------------- */
.project-filters { margin-bottom: var(--space-xl); }

.project-filters__list {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2xs);
  margin: 0;
  padding: 0;
  list-style: none;
}

.project-filters__pill {
  display: inline-block;
  padding: 0.5em 1em;
  font-family: var(--font-display);
  font-size: var(--step--1);
  text-transform: uppercase;
  letter-spacing: var(--tracking-caps);
  text-decoration: none;
  color: var(--text-muted);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  transition: color var(--dur-fast) var(--ease), border-color var(--dur-fast) var(--ease), background-color var(--dur-fast) var(--ease);
}

.project-filters__pill:hover,
.project-filters__pill:focus-visible {
  color: var(--text);
  border-color: var(--vgs-charcoal);
}

.project-filters__pill.is-current {
  color: var(--text-inverse);
  background: var(--vgs-charcoal);
  border-color: var(--vgs-charcoal);
}

.work__grid--archive { margin-bottom: 0; }
.work-archive__empty { color: var(--text-muted); }

/* --- Single project --------------------------------------------------------- */
.project__layout {
  display: grid;
  gap: var(--space-2xl) var(--space-xl);
  grid-template-columns: 1fr;
  align-items: start;
}

@media (min-width: 64rem) {
  .project__layout { grid-template-columns: minmax(0, 1fr) 18rem; }

  .project__summary {
    position: sticky;
    top: calc(var(--header-h) + var(--space-m));
  }

  .admin-bar .project__summary { top: calc(var(--header-h) + var(--space-m) + var(--admin-bar-h)); }
}

.project__main { min-width: 0; }

.project-gallery {
  display: grid;
  gap: var(--space-xs);
  grid-template-columns: repeat(2, minmax(0, 1fr));
  margin: 0;
  padding: 0;
  list-style: none;
}

@media (min-width: 48rem) { .project-gallery { grid-template-columns: repeat(3, minmax(0, 1fr)); } }

/* The first photograph leads. It spans two rows as well as two columns —
   spanning columns alone stretches the cell beside it to match its height,
   leaving a block of dead space under a small image. */
.project-gallery__item:first-child {
  grid-column: span 2;
  grid-row: span 2;
}

.project-gallery__item:first-child .project-gallery__link,
.project-gallery__item:first-child img { height: 100%; }
.project-gallery__item:first-child img { aspect-ratio: auto; }

.project-gallery__link {
  display: block;
  overflow: hidden;
  border-radius: var(--radius);
  cursor: zoom-in;
}

.project-gallery__link img {
  width: 100%;
  height: 100%;
  aspect-ratio: 4 / 3;
  object-fit: cover;
  transition: transform var(--dur-slow) var(--ease);
}

.project-gallery__link:hover img,
.project-gallery__link:focus-visible img { transform: scale(1.04); }

.project__summary-title {
  font-size: var(--step--1);
  text-transform: uppercase;
  letter-spacing: var(--tracking-caps);
  color: var(--text-muted);
  padding-bottom: var(--space-2xs);
  margin-bottom: var(--space-s);
  border-bottom: 2px solid var(--vgs-charcoal);
}

.project__facts { margin: 0; display: grid; gap: var(--space-s); }

.project__fact dt {
  font-size: var(--step--1);
  text-transform: uppercase;
  letter-spacing: var(--tracking-caps);
  color: var(--text-muted);
  margin-bottom: 2px;
}

.project__fact dd {
  margin: 0;
  font-family: var(--font-display);
  font-weight: 700;
  line-height: 1.3;
}

.project__fact dd a { text-decoration: none; }
.project__fact dd a:hover { text-decoration: underline; text-underline-offset: 0.15em; }

/* Partners reuse the summary heading, spaced as a second block under the facts. */
.project__partners-title { margin-top: var(--space-l); }

.project__partners {
  display: grid;
  gap: var(--space-2xs);
  margin: 0;
  padding: 0;
  list-style: none;
  font-family: var(--font-display);
  font-weight: 700;
  line-height: 1.3;
}

.project__partners a {
  text-decoration: underline;
  text-decoration-color: var(--vgs-silver);
  text-underline-offset: 0.2em;
}

.project__partners a:hover { text-decoration-color: currentColor; }

.project__description { margin-top: var(--space-l); font-size: var(--step--1); color: var(--text-muted); }
.project__description > * + * { margin-top: var(--space-s); }

.project-nav { margin-top: var(--space-2xl); }
.project__back { margin-top: var(--space-l); }

/* --- Lightbox ---------------------------------------------------------------- */
.lightbox {
  position: fixed;
  inset: 0;
  z-index: 200;
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  /*
   * A definite row height, not one sized by the image. Left to the content the
   * row grows with a portrait photograph and shrinks with a landscape one, so
   * the arrows shift between frames — and the image's own max-height has
   * nothing fixed to resolve against, letting tall images overflow.
   */
  grid-template-rows: minmax(0, 1fr);
  align-items: center;
  gap: var(--space-s);
  padding: var(--space-l) var(--space-2xs) 4.5rem;
  background: rgba(9, 10, 12, 0.94);
  /* A flick that reaches the end of the overlay should stop there rather than
     carry on into the page behind it. */
  overscroll-behavior: contain;
}

.lightbox[hidden] { display: none; }

.lightbox__figure {
  grid-column: 2;
  margin: 0;
  display: grid;
  place-items: center;
  /* Both minimums must be zero or the track refuses to shrink below the
     image's intrinsic size, which is what lets a tall photograph overflow. */
  min-width: 0;
  min-height: 0;
  width: 100%;
  height: 100%;
}

/*
 * Bounded by a definite length rather than a percentage. Inside a centred grid
 * area a percentage height on a replaced element does not resolve — the image
 * falls back to its intrinsic aspect ratio and a portrait photograph renders
 * at full height and overflows. The calc mirrors the container's own padding:
 * 2rem at the top, 4.5rem at the foot for the caption bar.
 */
.lightbox__image {
  max-width: 100%;
  max-height: calc(100svh - 6.5rem);
  width: auto;
  height: auto;
  object-fit: contain;
}

/* The arrows sit in the same fixed row, so they hold their position as the
   picture changes shape. */
.lightbox__arrow { align-self: center; }

/* Thin chevrons at the edges rather than buttons with chrome, so nothing
   competes with the photograph. */
.lightbox__arrow {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 64px;
  height: 64px;
  padding: 0;
  color: rgba(238, 242, 247, 0.75);
  background: transparent;
  border: 0;
  cursor: pointer;
  transition: color var(--dur-fast) var(--ease);
}

.lightbox__arrow:hover { color: var(--vgs-snow); }
.lightbox__arrow:focus-visible { outline: 2px solid var(--vgs-snow); outline-offset: 2px; }
.lightbox__prev { grid-column: 1; }
.lightbox__next { grid-column: 3; }
.lightbox__arrow[hidden] { visibility: hidden; display: inline-flex; }

.lightbox__close {
  position: absolute;
  top: var(--space-s);
  right: var(--space-s);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 48px;
  height: 48px;
  padding: 0;
  color: rgba(238, 242, 247, 0.75);
  background: transparent;
  border: 0;
  cursor: pointer;
}

.lightbox__close:hover { color: var(--vgs-snow); }
.lightbox__close:focus-visible { outline: 2px solid var(--vgs-snow); outline-offset: 2px; }

/* Caption bar along the foot, as on the reference. */
.lightbox__bar {
  position: absolute;
  inset-inline: 0;
  bottom: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-s);
  min-height: 3.25rem;
  padding: var(--space-2xs) var(--space-l);
  background: rgba(9, 10, 12, 0.85);
  border-top: 1px solid rgba(238, 242, 247, 0.12);
}

.lightbox__caption {
  margin: 0;
  max-width: 60ch;
  font-size: var(--step--1);
  color: var(--vgs-snow);
  text-align: center;
}

.lightbox__caption[hidden] { display: none; }

.lightbox__count {
  margin: 0;
  font-family: var(--font-display);
  font-size: var(--step--1);
  letter-spacing: var(--tracking-caps);
  color: var(--vgs-silver);
}

@media (max-width: 47.9375rem) {
  .lightbox { gap: 0; padding-inline: 0; }
  .lightbox__arrow { width: 44px; }
  .lightbox__arrow svg { width: 34px; height: 34px; }
}

/* --- Divisions landing -------------------------------------------------------
   The cards are the page, so the grid fills the screen below the header
   instead of sitting inside a section with padding above and below it. */
.divisions-landing {
  display: flex;
  align-items: stretch;
  /*
   * Pulled up behind the header, as the heroes are. Left below it the glass bar
   * blurs the page's own light background instead of this black band, and the
   * navigation reads grey against every other page's dark bar.
   */
  margin-top: calc(-1 * var(--header-h));
  min-height: 100svh;
  padding-top: var(--header-h);
}

.admin-bar .divisions-landing { min-height: calc(100svh - var(--admin-bar-h)); }

/* Edge to edge: no container width and no gutters, so nothing shows around
   the grid. */
.divisions-landing__inner {
  width: 100%;
  max-width: none;
  padding-inline: 0;
  display: flex;
  flex-direction: column;
}

.divisions-landing__head {
  margin-bottom: var(--space-l);
  padding-inline: var(--gutter);
  text-align: center;
}


.divisions-landing__intro {
  max-width: 62ch;
  margin-inline: auto;
  color: var(--vgs-silver);
}

.divisions-landing__intro > * { margin: 0; max-width: none; }
.divisions-landing__intro > * + * { margin-top: var(--space-s); }

/* The grid takes the remaining height in two equal rows, and each card fills
   its cell, so the four together cover the screen exactly. */
.division-grid--fill {
  flex: 1 1 auto;
  gap: 2px;
}

@media (min-width: 48rem) {
  .division-grid--fill {
    grid-template-rows: repeat(2, minmax(0, 1fr));
    min-height: 0;
  }

  .division-grid--fill .division-card { min-height: 0; }

  .division-grid--fill .division-card__link {
    min-height: 0;
    height: 100%;
  }
}

/* One column on a phone, where four full-height cards would mean four screens
   of scrolling before anything else. */
@media (max-width: 47.9375rem) {
  .division-grid--fill .division-card__link { min-height: 42svh; }
}

/* --- Services on a division page ---------------------------------------------- */
.services__list {
  display: grid;
  gap: var(--space-xl) var(--space-2xl);
  grid-template-columns: 1fr;
  margin: 0;
  padding: 0;
  list-style: none;
}

@media (min-width: 48rem) { .services__list { grid-template-columns: repeat(2, minmax(0, 1fr)); } }

.service {
  padding-top: var(--space-s);
  border-top: 2px solid var(--vgs-charcoal);
}

.service__name { font-size: var(--step-1); margin-bottom: var(--space-2xs); }

.service__body { color: var(--text-muted); font-size: var(--step--1); }
.service__body > * { margin: 0; max-width: none; }
.service__body > * + * { margin-top: var(--space-2xs); }

.service__suppliers {
  margin-top: var(--space-s);
  padding-top: var(--space-xs);
  border-top: 1px solid var(--border-subtle);
}

.service__suppliers-title {
  font-size: var(--step--1);
  text-transform: uppercase;
  letter-spacing: var(--tracking-caps);
  color: var(--text-muted);
  margin-bottom: var(--space-2xs);
}

.service__supplier-list { margin: 0; padding: 0; list-style: none; display: grid; gap: var(--space-2xs); }

.service__supplier {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: var(--space-2xs) var(--space-s);
  font-size: var(--step--1);
}

.service__supplier-name { font-family: var(--font-display); font-weight: 700; }

/* --- Supplier links on a division page ------------------------------------------
   Each supplier once, however many services list it, with its site and guides.
   The section only renders once at least one supplier has a link. */
.suppliers__list {
  display: grid;
  gap: var(--space-m) var(--space-xl);
  grid-template-columns: 1fr;
  margin: 0;
  padding: 0;
  list-style: none;
}

@media (min-width: 48rem) { .suppliers__list { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (min-width: 64rem) { .suppliers__list { grid-template-columns: repeat(3, minmax(0, 1fr)); } }

.supplier {
  padding-top: var(--space-s);
  border-top: 2px solid var(--vgs-charcoal);
}

.supplier__name { font-size: var(--step-0); margin-bottom: var(--space-2xs); }

.supplier__links {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2xs) var(--space-m);
  margin: 0;
  padding: 0;
  list-style: none;
  font-size: var(--step--1);
}

.supplier__links a {
  color: var(--text);
  text-decoration-color: var(--vgs-silver);
  text-underline-offset: 0.25em;
}

.supplier__links a:hover { text-decoration-color: currentColor; }

/* Hours run to several lines, so they read as text rather than as a single
   large value like the phone number or address. */
.contact-card__value--hours {
  font-family: var(--font-body);
  font-size: var(--step-0);
  font-weight: 400;
  line-height: 1.6;
  letter-spacing: normal;
  text-transform: none;
}

/* --- Social links --------------------------------------------------------
   Sits under the footer tagline. Hidden entirely when no profile URL is set,
   so the row never appears as an empty gap. */
.social {
  display: flex;
  gap: var(--space-xs);
  margin: var(--space-m) 0 0;
  padding: 0;
  list-style: none;
}

.social__link {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 40px;
  height: 40px;
  border: 1px solid var(--vgs-charcoal-75);
  border-radius: var(--radius);
  color: var(--text-inverse-muted);
  transition: color var(--dur) var(--ease), border-color var(--dur) var(--ease);
}

.social__link:hover,
.social__link:focus-visible {
  color: var(--text-inverse);
  border-color: var(--vgs-silver);
}

.social__icon { display: block; }
