/* ==========================================================================
   City Contractors Portfolio — gallery
   Rendered by [cc_gallery]. Lives inside an Elementor HTML widget, so nearly
   everything here is !important: Elementor's kit styles img, button, a and ul
   globally and will otherwise repaint borders, radii and spacing underneath us.
   ========================================================================== */

.cc-gallery,
.cc-gallery *,
.cc-gallery *::before,
.cc-gallery *::after { box-sizing: border-box; }

.cc-gallery {
  /* Same 1340 line as the header, footer and every page section. */
  max-width: var(--cc-content, 83.75rem);
  margin-inline: auto;
  padding-inline: var(--cc-gutter, 2.75rem);
  padding-block: var(--cc-section-y, clamp(3.5rem, 2rem + 6vw, 8.75rem));
  color: var(--cc-ink, #0A0A0C);
}

/* ---------- Head ---------- */
.cc-gallery__head { max-width: 46rem; margin-bottom: clamp(1.75rem, 1rem + 2.5vw, 3rem); }
.cc-gallery__eyebrow {
  display: inline-flex; align-items: center; gap: var(--cc-sp-3, .75rem);
  margin: 0 0 var(--cc-sp-4, 1rem) !important;
  font-size: var(--cc-fs-caption, .75rem) !important;
  font-weight: 600 !important;
  letter-spacing: var(--cc-ls-caps, .12em) !important;
  text-transform: uppercase !important;
  color: var(--cc-ink-soft, #55534E) !important;
}
.cc-gallery__eyebrow::before {
  content: ""; flex: none; width: 3px; height: 2.1em;
  background: linear-gradient(180deg, transparent, var(--cc-accent) 22%, var(--cc-accent) 78%, transparent) !important;
}
.cc-gallery__title {
  margin: 0 0 var(--cc-sp-4, 1rem) !important;
  font-family: var(--cc-font-display, sans-serif) !important;
  font-size: clamp(1.75rem, 1.05rem + 2.3vw, 2.75rem) !important;
  font-weight: 700 !important;
  line-height: 1.12 !important;
  letter-spacing: -.03em !important;
  color: var(--cc-ink, #0A0A0C) !important;
}
.cc-gallery__intro {
  margin: 0 !important;
  font-size: var(--cc-fs-body, .875rem) !important;
  line-height: 1.8 !important;
  color: var(--cc-ink-soft, #55534E) !important;
}

/* ==========================================================================
   Filters — underline tabs with a sliding indicator, not pills
   ========================================================================== */
.cc-gallery__filters {
  position: relative;
  display: flex;
  /* WRAPS on a wide screen. The tabs are one per project now, so this row holds
     22 names on the commercial gallery rather than four categories — a single
     scrolling line would hide most of them behind a gesture nobody knows to
     make. It still scrolls on a phone, where wrapping 22 names would push the
     photographs off the screen entirely. */
  flex-wrap: wrap;
  gap: clamp(.9rem, .5rem + 1.1vw, 1.6rem);
  row-gap: 0;
  margin-bottom: clamp(1.5rem, 1rem + 1.5vw, 2.5rem);
  padding-bottom: 0 !important;
  border-bottom: 1px solid var(--cc-border, #E0DFDA) !important;
  overflow: visible;
}
@media (max-width: 767px) {
  .cc-gallery__filters {
    flex-wrap: nowrap;
    overflow-x: auto;
    overflow-y: hidden;
    scrollbar-width: none;
    -webkit-overflow-scrolling: touch;
  }
}
.cc-gallery__filters::-webkit-scrollbar { display: none; }

.cc-gallery__filter {
  position: relative;
  flex: none;
  /* Each tab now underlines itself. The single sliding bar only ever knew a
     horizontal offset, so on a wrapped second row it drew under the first. */
  border-bottom: 2px solid transparent !important;
  display: inline-flex; align-items: baseline; gap: 7px;
  padding: 0 0 var(--cc-sp-4, 1rem) !important;
  margin: 0 !important;
  border: 0 !important;
  border-radius: 0 !important;
  background: transparent !important;
  box-shadow: none !important;
  font-family: var(--cc-font-body, sans-serif) !important;
  font-size: var(--cc-fs-sm, .8125rem) !important;
  font-weight: 500 !important;
  letter-spacing: 0 !important;
  text-transform: none !important;
  color: var(--cc-ink-soft, #55534E) !important;
  cursor: pointer;
  white-space: nowrap;
  -webkit-appearance: none; appearance: none;
  -webkit-tap-highlight-color: transparent;
  transition: color .2s ease;
}
.cc-gallery__filter:hover { color: var(--cc-ink, #0A0A0C) !important; }
.cc-gallery__filter.is-active {
  color: var(--cc-ink, #0A0A0C) !important;
  font-weight: 600 !important;
  border-bottom-color: var(--cc-accent) !important;
}
.cc-gallery__filter span {
  font-size: var(--cc-fs-caption, .75rem) !important;
  font-variant-numeric: tabular-nums;
  color: var(--cc-ink-soft, #55534E) !important;
  opacity: .65;
}
.cc-gallery__filter:focus-visible { outline: 2px solid var(--cc-accent); outline-offset: 3px; }

/* One bar that slides, rather than a border per tab appearing and vanishing. */
/* Retired by the wrap above, kept hidden rather than removed so an older
   cached page that still renders the element does not show a stray bar. */
.cc-gallery__ink { display: none !important; }
.cc-gallery__ink--unused {
  position: absolute;
  left: 0; bottom: -1px;
  height: 2px;
  width: 0;
  background: var(--cc-accent) !important;
  border-radius: 2px;
  transition: transform .42s cubic-bezier(.16,1,.3,1), width .42s cubic-bezier(.16,1,.3,1);
  pointer-events: none;
}

/* ==========================================================================
   Grid — every tile the same height, always
   ========================================================================== */
.cc-gallery__grid {
  display: grid;
  grid-template-columns: repeat(var(--cc-gal-cols, 3), minmax(0, 1fr));
  gap: clamp(.75rem, .5rem + .8vw, 1.25rem);
  margin: 0 !important;
  padding: 0 !important;
  list-style: none !important;
}

.cc-gallery__item {
  position: relative;
  display: block !important;
  /* Fixed ratio on the TILE, not the image. Letting the image set the height
     is what produced the ragged rows — every photo has its own aspect. */
  aspect-ratio: 4 / 3 !important;
  width: 100% !important;
  margin: 0 !important;
  padding: 0 !important;
  overflow: hidden !important;
  border: 0 !important;
  border-radius: var(--cc-r-md, 8px) !important;
  background: var(--cc-n-200, #EDEDEA) !important;
  box-shadow: none !important;
  cursor: pointer;
  -webkit-appearance: none; appearance: none;
  -webkit-tap-highlight-color: transparent;
}
.cc-gallery__item[hidden] { display: none !important; }
/* Elementor puts an outline on buttons and links inside its widgets. */
.cc-gallery__item:focus { outline: none !important; }
.cc-gallery__item:focus-visible { outline: 3px solid var(--cc-accent) !important; outline-offset: 3px; }

.cc-gallery__item img {
  width: 100% !important;
  height: 100% !important;
  object-fit: cover !important;
  display: block !important;
  border: 0 !important;
  border-radius: 0 !important;
  box-shadow: none !important;
  max-width: none !important;
  transition: transform .6s cubic-bezier(.16,1,.3,1), filter .6s ease;
  filter: grayscale(.25);
}
.cc-gallery__item:hover img,
.cc-gallery__item:focus-within img { transform: scale(1.05); filter: grayscale(0); }

/* ---- Video tiles -------------------------------------------------------
   Same box as a photo tile. The element is only ever a still here — controls
   are off and it never plays in the grid; tapping opens the lightbox, which
   is where a clip actually runs. */
.cc-gallery__video {
  width: 100% !important;
  height: 100% !important;
  object-fit: cover !important;
  display: block !important;
  border: 0 !important;
  border-radius: 0 !important;
  background: var(--cc-n-200, #EDEDEA);
  transition: transform .6s cubic-bezier(.16,1,.3,1), filter .6s ease;
  filter: grayscale(.25);
  pointer-events: none;   /* the button owns the click, not the player */
}
.cc-gallery__item:hover .cc-gallery__video,
.cc-gallery__item:focus-within .cc-gallery__video { transform: scale(1.05); filter: grayscale(0); }

.cc-gallery__play {
  position: absolute;
  top: 50%; left: 50%;
  translate: -50% -50%;
  z-index: 2;
  display: grid;
  place-items: center;
  width: clamp(48px, 4.4vw, 62px);
  aspect-ratio: 1;
  border-radius: 50%;
  background: rgba(255,255,255,.92);
  color: var(--cc-n-950, #111);
  box-shadow: 0 6px 24px rgba(0,0,0,.22);
  transition: transform .35s cubic-bezier(.16,1,.3,1), background .25s ease;
  pointer-events: none;
}
.cc-gallery__play svg { width: 42%; height: 42%; margin-left: 8%; }
.cc-gallery__item:hover .cc-gallery__play { transform: scale(1.08); background: #fff; }

/* Caption sits on a gradient rather than a solid bar, so it reads on any photo. */
.cc-gallery__item::after {
  content: "";
  position: absolute; inset: auto 0 0 0;
  height: 55%;
  background: linear-gradient(180deg, transparent, rgba(8,8,10,.72)) !important;
  opacity: 0;
  transition: opacity .35s ease;
  pointer-events: none;
}
.cc-gallery__item:hover::after,
.cc-gallery__item::after { opacity: 1 !important; }

.cc-gallery__cap {
  position: absolute;
  left: 0; right: 0; bottom: 0;
  z-index: 2;
  padding: var(--cc-sp-5, 1.25rem) !important;
  font-family: var(--cc-font-display, sans-serif) !important;
  font-size: var(--cc-fs-h6, 1rem) !important;
  font-weight: 600 !important;
  letter-spacing: -.014em !important;
  color: #fff !important;
  text-align: left !important;
  opacity: 0;
  transform: translateY(8px);
  transition: opacity .35s ease, transform .45s cubic-bezier(.16,1,.3,1);
}
/* The name is the point of the card now — it is how a visitor finds the job
   they came for, so it does not wait for a hover that never happens on a
   phone. Hover only lifts it slightly. */
.cc-gallery__cap { opacity: 1 !important; transform: none !important; }

/* Count badge — how many images are behind this tile. */
.cc-gallery__count {
  position: absolute;
  top: var(--cc-sp-4, 1rem); right: var(--cc-sp-4, 1rem);
  z-index: 2;
  display: inline-flex; align-items: center; gap: 5px;
  padding: 5px 10px !important;
  border-radius: 999px !important;
  background: rgba(255,255,255,.92) !important;
  color: var(--cc-ink, #0A0A0C) !important;
  font-size: var(--cc-fs-caption, .75rem) !important;
  font-weight: 600 !important;
  font-variant-numeric: tabular-nums;
  opacity: 0;
  transform: translateY(-6px);
  transition: opacity .3s ease, transform .4s cubic-bezier(.16,1,.3,1);
}
.cc-gallery__item:hover .cc-gallery__count,
.cc-gallery__item:focus-within .cc-gallery__count { opacity: 1; transform: none; }

.cc-gallery__empty {
  margin: 0 !important;
  padding: clamp(3rem, 2rem + 3vw, 5rem) 0 !important;
  text-align: center;
  font-size: var(--cc-fs-body, .875rem) !important;
  color: var(--cc-ink-soft, #55534E) !important;
}
.cc-gallery__empty[hidden] { display: none !important; }

@media (max-width: 1023px) { .cc-gallery__grid { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 599px)  {
  .cc-gallery__grid { grid-template-columns: minmax(0, 1fr); }
  .cc-gallery__item { aspect-ratio: 3 / 2 !important; }
  /* Caption always visible on touch — there is no hover to reveal it. */
  .cc-gallery__item::after,
  .cc-gallery__cap { opacity: 1; transform: none; }
}
@media (hover: none) {
  .cc-gallery__item::after, .cc-gallery__cap { opacity: 1; transform: none; }
}
@media (prefers-reduced-motion: reduce) {
  .cc-gallery__item img, .cc-gallery__cap, .cc-gallery__count, .cc-gallery__ink { transition: none !important; }
  .cc-gallery__item:hover img { transform: none; }
}

/* ==========================================================================
   Lightbox
   A flat white canvas that rises from the bottom. No blur, no darkened page
   behind, no image bleeding behind the frame — one surface.
   ========================================================================== */
/* box-sizing FIRST. The lightbox is appended to <body>, not inside
   .cc-gallery, so it never inherited the border-box rule at the top of this
   file. Under content-box, `height: 100%` plus padding overflows by exactly
   the padding — which is why the image kept getting clipped at the bottom no
   matter how the image itself was sized. */
.cc-lb, .cc-lb *, .cc-lb *::before, .cc-lb *::after { box-sizing: border-box; }

.cc-lb {
  position: fixed;
  inset: 0;
  z-index: 99999;
  display: grid;
  grid-template-rows: auto minmax(0, 1fr) auto;
  background: #fff !important;
  opacity: 0;
  visibility: hidden;
  transform: translateY(100%);
  transition: transform .52s cubic-bezier(.16,1,.3,1), opacity .3s ease, visibility .52s;
}
.cc-lb.is-open { opacity: 1; visibility: visible; transform: none; }

/* ---- Bar ---- */
.cc-lb__bar {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--cc-sp-4, 1rem);
  padding: clamp(.75rem, .5rem + .8vw, 1.25rem) clamp(1rem, .5rem + 2vw, 2.75rem);
}
.cc-lb__meta { min-width: 0; }
.cc-lb__title {
  margin: 0 !important;
  font-family: var(--cc-font-display, sans-serif) !important;
  font-size: var(--cc-fs-h6, 1rem) !important;
  font-weight: 600 !important;
  letter-spacing: -.014em !important;
  color: var(--cc-ink, #0A0A0C) !important;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.cc-lb__pos {
  margin: 2px 0 0 !important;
  font-size: var(--cc-fs-caption, .75rem) !important;
  font-variant-numeric: tabular-nums;
  color: var(--cc-ink-soft, #55534E) !important;
}
.cc-lb__x {
  flex: none;
  display: grid; place-items: center;
  width: 46px !important; height: 46px !important;
  padding: 0 !important;
  border: 1px solid var(--cc-border, #E0DFDA) !important;
  border-radius: 50% !important;
  background: #fff !important;
  color: var(--cc-ink, #0A0A0C) !important;
  cursor: pointer;
  -webkit-appearance: none; appearance: none;
  transition: background-color .2s ease, border-color .2s ease, transform .3s cubic-bezier(.16,1,.3,1);
}
.cc-lb__x:hover { background: var(--cc-ink, #0A0A0C) !important; border-color: var(--cc-ink) !important; color: #fff !important; transform: rotate(90deg); }
.cc-lb__x svg { width: 18px !important; height: 18px !important; display: block !important; }

/* ---- Stage ----
   overflow:hidden and min-height:0 on BOTH the row and the frame. Without
   them a tall image overflows its grid row and paints over the thumbnail
   strip below — which is why the active thumb looked like it had vanished.
   It had not; it was underneath the photograph. */
.cc-lb__stage {
  position: relative;
  display: grid;
  place-items: center;
  min-height: 0;
  overflow: hidden;
  /* Equal breathing room above and below the plate. The stage previously had
     no vertical padding at all, so the image sat hard against the thumbnail
     strip while the bar above left a gap — it read as misaligned because it
     was. One value, used top and bottom. */
  padding: clamp(1rem, .6rem + 1.6vw, 2.25rem) clamp(3.5rem, 2rem + 4vw, 5.5rem);
}
/* THE FRAME is the fixed box; the image just fills it and lets object-fit do
   the scaling. This is the only version that cannot overflow.

   Everything before this sized the IMAGE with percentages — max-height:100%,
   then width:72%, then both as maxima. A percentage height resolves against a
   parent whose own height is content-driven inside a grid row, so the image
   could always end up taller than the visible area and get clipped at the
   bottom. Sizing the container and letting `contain` fit the picture inside it
   removes the possibility rather than tuning around it. */
/* Absolute inset:0 inside a relative frame. An absolutely positioned box
   pinned to all four edges of its containing block cannot be larger than that
   block — there is no arithmetic left for it to get wrong. object-fit then
   scales the picture to fit inside, letterboxing whatever is left over. */
/* Frame fills the stage at 72% width. The IMAGE sizes itself inside it with
   maxima only, so its element box equals the visible picture — which is what
   makes a border-radius land on the photograph instead of on empty margin.

   This is the plain approach. Two earlier attempts drove the frame with
   aspect-ratio instead; both collapsed to 0x0, because the frame's only child
   is absolutely positioned and contributes no intrinsic size, so with no
   definite axis there was nothing to compute from.

   The reason the plain approach is safe NOW and was not before: every sizing
   declaration below carries !important. Hello Elementor ships
   `img { height: auto }`, and without !important that won and the picture
   overflowed. That was the original bug, not the sizing model. */
.cc-lb__frame {
  position: relative;
  width: 72%;
  height: 100%;
  min-height: 0;
  min-width: 0;
  display: grid;
  place-items: center;
}
.cc-lb__img {
  grid-area: 1 / 1;
  position: static !important;
  width: auto !important;
  height: auto !important;
  max-width: 100% !important;
  max-height: 100% !important;
  min-width: 0 !important;
  min-height: 0 !important;
  margin: 0 !important;
  object-fit: contain !important;
  display: block !important;
  border-radius: var(--cc-r-md, 8px) !important;
  opacity: 0;
  transition: opacity .32s ease;
}
.cc-lb__img.is-on { opacity: 1; }

/* Shares the frame's single grid cell with the two images, so swapping
   between a clip and a photo never shifts the layout. */
.cc-lb__video {
  grid-area: 1 / 1;
  position: static !important;
  width: auto !important;
  height: auto !important;
  max-width: 100% !important;
  max-height: 100% !important;
  min-width: 0 !important;
  min-height: 0 !important;
  margin: 0 !important;
  display: block !important;
  background: #000;
  border-radius: var(--cc-r-md, 8px) !important;
  outline: none;
}
.cc-lb__video[hidden] { display: none !important; }

/* ---- Sound toggle -------------------------------------------------------
   Every colour carries !important, exactly as .cc-lb__x does. The theme and
   Elementor both style button:hover, and without !important their rule won a
   colour fight this one had no business losing — the control went white on a
   white panel and the icon vanished with it. */
.cc-lb__sound {
  flex: none;
  display: grid; place-items: center;
  width: 46px !important; height: 46px !important;
  padding: 0 !important;
  /* The bar is space-between with two children; a third would land in the
     middle, so this parks it beside Close. */
  margin-left: auto;
  margin-right: 10px;
  border: 1px solid var(--cc-border, #E0DFDA) !important;
  border-radius: 50% !important;
  background: #fff !important;
  color: var(--cc-ink, #0A0A0C) !important;
  cursor: pointer;
  -webkit-appearance: none; appearance: none;
  transition: background-color .2s ease, border-color .2s ease, color .2s ease,
              transform .3s cubic-bezier(.16,1,.3,1);
}
.cc-lb__sound svg { width: 19px !important; height: 19px !important; display: block !important; }
.cc-lb__sound:hover {
  background: var(--cc-ink, #0A0A0C) !important;
  border-color: var(--cc-ink, #0A0A0C) !important;
  color: #fff !important;
  transform: scale(1.06);
}
.cc-lb__sound:focus-visible { outline: 3px solid var(--cc-accent); outline-offset: 2px; }
.cc-lb__sound[hidden] { display: none !important; }

/* Which icon shows, driven by one class on the button. */
.cc-lb__sound [data-lb-icon-off]          { display: none !important; }
.cc-lb__sound.is-muted [data-lb-icon-on]  { display: none !important; }
.cc-lb__sound.is-muted [data-lb-icon-off] { display: block !important; }

/* Muted is worth reading at a glance, not a swapped glyph on an identical
   button — the two icons differ by one small stroke otherwise. */
.cc-lb__sound.is-muted {
  background: var(--cc-ink, #0A0A0C) !important;
  border-color: var(--cc-ink, #0A0A0C) !important;
  color: #fff !important;
}
.cc-lb__sound.is-muted:hover {
  background: #33333A !important;
  border-color: #33333A !important;
  color: #fff !important;
}

.cc-lb__skel {
  grid-area: 1 / 1;
  width: 100%; height: 100%;
  border-radius: var(--cc-r-md, 8px);
  background: linear-gradient(100deg, #f0f0ee 8%, #e4e4e1 18%, #f0f0ee 33%) 0 0 / 300% 100%;
  animation: cc-skel 1.4s linear infinite;
}
.cc-lb__skel[hidden] { display: none; }
@keyframes cc-skel { to { background-position: -300% 0; } }

/* ---- Arrows, pinned to the screen edges ---- */
.cc-lb__nav {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  z-index: 4;
  display: grid; place-items: center;
  width: 48px !important; height: 48px !important;
  padding: 0 !important;
  border: 1px solid var(--cc-border, #E0DFDA) !important;
  border-radius: 50% !important;
  background: rgba(255,255,255,.94) !important;
  color: var(--cc-ink, #0A0A0C) !important;
  cursor: pointer;
  -webkit-appearance: none; appearance: none;
  transition: background-color .2s ease, border-color .2s ease, opacity .2s ease;
}
.cc-lb__nav--prev { left: clamp(.5rem, .2rem + 1vw, 1.5rem); }
.cc-lb__nav--next { right: clamp(.5rem, .2rem + 1vw, 1.5rem); }
.cc-lb__nav:hover:not(:disabled) { background: var(--cc-ink) !important; border-color: var(--cc-ink) !important; color: #fff !important; }
.cc-lb__nav:disabled { opacity: .28; cursor: default; }
.cc-lb__nav svg { width: 20px !important; height: 20px !important; display: block !important; }

/* ---- Thumbnail strip ----
   Sits ABOVE the stage in z-order and fades at both ends, so a strip that
   scrolls does not just stop dead at the edge of the screen. */
.cc-lb__strip {
  position: relative;
  z-index: 5;
  display: flex;
  /* Centred when the row fits, scrollable from the start when it does not.
     `safe` is the whole point: plain `center` on an overflowing flex row
     pushes the first items past the scroll origin and they become
     unreachable. */
  justify-content: safe center;
  gap: 8px;
  padding: clamp(.75rem, .5rem + 1vw, 1.25rem) clamp(1rem, .5rem + 2vw, 2.75rem) clamp(1rem, .75rem + 1vw, 1.75rem);
  background: #fff !important;
  overflow-x: auto;
  scrollbar-width: none;
  -webkit-overflow-scrolling: touch;
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 4%, #000 96%, transparent);
          mask-image: linear-gradient(90deg, transparent, #000 4%, #000 96%, transparent);
}
.cc-lb__strip::-webkit-scrollbar { display: none; }
.cc-lb__thumb {
  flex: none;
  width: 74px !important; height: 74px !important;
  padding: 0 !important;
  border: 0 !important;
  border-radius: var(--cc-r-sm, 6px) !important;
  overflow: hidden;
  background: var(--cc-n-200, #EDEDEA) !important;
  cursor: pointer;
  opacity: .45;
  -webkit-appearance: none; appearance: none;
  transition: opacity .2s ease, box-shadow .2s ease, transform .3s cubic-bezier(.16,1,.3,1);
}
.cc-lb__thumb img,
.cc-lb__thumb video { width: 100% !important; height: 100% !important; object-fit: cover !important; display: block !important; }

/* A small play mark, so a clip is identifiable in the strip without
   waiting for its first frame to decode. */
.cc-lb__thumb.is-video { position: relative; }
.cc-lb__thumb.is-video::after {
  content: "";
  position: absolute;
  top: 50%; left: 50%;
  translate: -50% -50%;
  width: 0; height: 0;
  border-style: solid;
  border-width: 7px 0 7px 12px;
  border-color: transparent transparent transparent #fff;
  filter: drop-shadow(0 1px 3px rgba(0,0,0,.55));
  pointer-events: none;
}
.cc-lb__thumb:hover { opacity: .8; }
.cc-lb__thumb.is-on { opacity: 1; box-shadow: 0 0 0 2px var(--cc-accent) !important; transform: translateY(-3px); }

body.cc-lb-open { overflow: hidden !important; }

@media (max-width: 599px) {
  .cc-lb__stage { padding: .75rem .5rem; }
  .cc-lb__frame { width: 94%; }
  .cc-lb__nav { width: 42px !important; height: 42px !important; }
  .cc-lb__thumb { width: 58px !important; height: 58px !important; }
}
@media (prefers-reduced-motion: reduce) {
  .cc-lb, .cc-lb__img, .cc-lb__x, .cc-lb__nav { transition: none !important; }
  .cc-lb__skel { animation: none; }
}

/* ---------- Load more + skeletons ---------- */
.cc-gallery__skels {
  display: grid;
  grid-template-columns: repeat(var(--cc-gal-cols, 3), minmax(0, 1fr));
  gap: clamp(.75rem, .5rem + .8vw, 1.25rem);
  margin-top: clamp(.75rem, .5rem + .8vw, 1.25rem);
}
.cc-gallery__skels[hidden] { display: none !important; }
/* Same 4:3 box as a real tile, so revealing the images never reflows the page. */
.cc-gallery__skel {
  aspect-ratio: 4 / 3;
  border-radius: var(--cc-r-md, 8px);
  background: linear-gradient(100deg, #f1f1ef 8%, #e5e5e2 18%, #f1f1ef 33%) 0 0 / 300% 100%;
  animation: cc-skel 1.4s linear infinite;
}
@media (max-width: 599px) { .cc-gallery__skel { aspect-ratio: 3 / 2; } }

.cc-gallery__more { display: flex; justify-content: center; margin-top: clamp(1.5rem, 1rem + 2vw, 2.75rem); }
.cc-gallery__more[hidden] { display: none !important; }
.cc-gallery__morebtn {
  display: inline-flex; align-items: center; gap: 9px;
  padding: 13px 26px !important;
  border: 1px solid var(--cc-border, #E0DFDA) !important;
  border-radius: var(--cc-r-btn, 6px) !important;
  background: #fff !important;
  color: var(--cc-ink, #0A0A0C) !important;
  font-family: var(--cc-font-body, sans-serif) !important;
  font-size: var(--cc-fs-sm, .8125rem) !important;
  font-weight: 600 !important;
  cursor: pointer;
  -webkit-appearance: none; appearance: none;
  transition: background-color .2s ease, border-color .2s ease, color .2s ease;
}
.cc-gallery__morebtn:hover:not(:disabled) {
  background: var(--cc-accent) !important; border-color: var(--cc-accent) !important; color: #fff !important;
}
.cc-gallery__morebtn:disabled { opacity: .5; cursor: default; }
.cc-gallery__morebtn svg { width: 15px !important; height: 15px !important; }

/* Tiles fade in as they are revealed rather than snapping into place. */
.cc-gallery__item.is-new { animation: cc-tile-in .5s cubic-bezier(.16,1,.3,1) both; }
@keyframes cc-tile-in { from { opacity: 0; transform: translateY(14px); } to { opacity: 1; transform: none; } }
@media (prefers-reduced-motion: reduce) {
  .cc-gallery__item.is-new { animation: none; }
  .cc-gallery__skel { animation: none; }
}

/* Vertical panning stays with the browser; horizontal is the swipe. */
.cc-lb__stage { touch-action: pan-y; }

/* ==========================================================================
   [cc_projects] — landing-page teaser
   ========================================================================== */
.cc-teaser, .cc-teaser *, .cc-teaser *::before, .cc-teaser *::after { box-sizing: border-box; }
.cc-teaser {
  max-width: var(--cc-content, 83.75rem);
  margin-inline: auto;
  padding-inline: var(--cc-gutter, 2.75rem);
  padding-block: var(--cc-section-y, clamp(3.5rem, 2rem + 6vw, 8.75rem));
}
.cc-teaser__head { max-width: 46rem; margin-bottom: clamp(1.75rem, 1rem + 2.5vw, 3rem); }
.cc-teaser__eyebrow {
  display: inline-flex; align-items: center; gap: var(--cc-sp-3, .75rem);
  margin: 0 0 var(--cc-sp-4, 1rem) !important;
  font-size: var(--cc-fs-caption, .75rem) !important; font-weight: 600 !important;
  letter-spacing: var(--cc-ls-caps, .12em) !important; text-transform: uppercase !important;
  color: var(--cc-ink-soft, #55534E) !important;
}
.cc-teaser__eyebrow::before {
  content: ""; flex: none; width: 3px; height: 2.1em;
  background: linear-gradient(180deg, transparent, var(--cc-accent) 22%, var(--cc-accent) 78%, transparent) !important;
}
.cc-teaser__title {
  margin: 0 0 var(--cc-sp-4, 1rem) !important;
  font-family: var(--cc-font-display, sans-serif) !important;
  font-size: clamp(1.75rem, 1.05rem + 2.3vw, 2.75rem) !important;
  font-weight: 700 !important; line-height: 1.12 !important; letter-spacing: -.03em !important;
  color: var(--cc-ink, #0A0A0C) !important;
}
.cc-teaser__intro {
  margin: 0 !important; font-size: var(--cc-fs-body, .875rem) !important;
  line-height: 1.8 !important; color: var(--cc-ink-soft, #55534E) !important;
}

.cc-teaser__grid {
  display: grid;
  grid-template-columns: repeat(var(--cc-gal-cols, 3), minmax(0, 1fr));
  gap: clamp(.75rem, .5rem + .8vw, 1.25rem);
}
.cc-teaser__item {
  position: relative;
  display: block !important;
  aspect-ratio: 4 / 3 !important;
  width: 100% !important;
  margin: 0 !important; padding: 0 !important;
  overflow: hidden !important;
  border: 0 !important;
  border-radius: var(--cc-r-md, 8px) !important;
  background: var(--cc-n-200, #EDEDEA) !important;
  cursor: pointer;
  -webkit-appearance: none; appearance: none;
}
.cc-teaser__item:focus { outline: none !important; }
.cc-teaser__item:focus-visible { outline: 3px solid var(--cc-accent) !important; outline-offset: 3px; }
.cc-teaser__item img {
  width: 100% !important; height: 100% !important;
  object-fit: cover !important; display: block !important;
  border: 0 !important; border-radius: 0 !important; max-width: none !important;
  filter: grayscale(.25);
  transition: transform .6s cubic-bezier(.16,1,.3,1), filter .6s ease;
}
.cc-teaser__item:hover img { transform: scale(1.05); filter: grayscale(0); }
.cc-teaser__item::after {
  content: ""; position: absolute; inset: auto 0 0 0; height: 55%;
  background: linear-gradient(180deg, transparent, rgba(8,8,10,.72)) !important;
  opacity: 0; transition: opacity .35s ease; pointer-events: none;
}
.cc-teaser__item:hover::after { opacity: 1; }
.cc-teaser__cap {
  position: absolute; left: 0; right: 0; bottom: 0; z-index: 2;
  padding: var(--cc-sp-5, 1.25rem) !important;
  font-family: var(--cc-font-display, sans-serif) !important;
  font-size: var(--cc-fs-h6, 1rem) !important; font-weight: 600 !important;
  color: #fff !important; text-align: left !important;
  opacity: 0; transform: translateY(8px);
  transition: opacity .35s ease, transform .45s cubic-bezier(.16,1,.3,1);
}
.cc-teaser__item:hover .cc-teaser__cap { opacity: 1; transform: none; }

/* The way out. Same box as a photograph so the grid stays even. */
.cc-teaser__cta {
  position: relative;
  display: flex !important;
  flex-direction: column;
  justify-content: flex-end;
  gap: 6px;
  aspect-ratio: 4 / 3 !important;
  padding: var(--cc-sp-6, 1.5rem) !important;
  border-radius: var(--cc-r-md, 8px) !important;
  text-decoration: none !important;
  color: #fff !important;
  overflow: hidden;
  background-color: var(--cc-accent) !important;
  background-image: linear-gradient(150deg,
    color-mix(in srgb, var(--cc-accent) 88%, #04070A) 0%,
    var(--cc-accent) 48%,
    color-mix(in srgb, var(--cc-accent-lift) 78%, var(--cc-accent)) 100%) !important;
  transition: transform .35s cubic-bezier(.16,1,.3,1), box-shadow .35s ease;
}
.cc-teaser__cta:hover { transform: translateY(-4px); box-shadow: var(--cc-sh-lg, 0 20px 60px rgba(10,10,12,.14)) !important; }
.cc-teaser__cta::after {
  content: ""; position: absolute; left: 50%; top: -20%;
  width: 130%; aspect-ratio: 1; transform: translateX(-50%);
  border-radius: 50%;
  background: radial-gradient(circle, rgba(255,255,255,.16) 0%, transparent 62%) !important;
  pointer-events: none;
}
.cc-teaser__cta-num {
  position: relative; z-index: 1;
  font-family: var(--cc-font-display, sans-serif) !important;
  font-size: clamp(2.25rem, 1.5rem + 2.4vw, 3.5rem) !important;
  font-weight: 800 !important; line-height: 1 !important; letter-spacing: -.04em !important;
  font-variant-numeric: tabular-nums;
}
.cc-teaser__cta-lbl {
  position: relative; z-index: 1;
  font-size: var(--cc-fs-sm, .8125rem) !important; line-height: 1.6 !important;
  color: rgba(255,255,255,.82) !important;
  margin-bottom: var(--cc-sp-4, 1rem);
}
.cc-teaser__cta-btn {
  position: relative; z-index: 1;
  display: inline-flex; align-items: center; gap: 8px;
  align-self: flex-start;
  padding: 10px 18px !important;
  border-radius: var(--cc-r-btn, 6px) !important;
  background: #fff !important;
  color: var(--cc-ink, #0A0A0C) !important;
  font-size: var(--cc-fs-sm, .8125rem) !important; font-weight: 700 !important;
  transition: gap .3s cubic-bezier(.16,1,.3,1);
}
.cc-teaser__cta:hover .cc-teaser__cta-btn { gap: 14px; }
.cc-teaser__cta-btn svg { width: 15px !important; height: 15px !important; }

@media (max-width: 1023px) { .cc-teaser__grid { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 599px) {
  .cc-teaser__grid { grid-template-columns: minmax(0, 1fr); }
  .cc-teaser__item, .cc-teaser__cta { aspect-ratio: 3 / 2 !important; }
  .cc-teaser__item::after, .cc-teaser__cap { opacity: 1; transform: none; }
}
@media (hover: none) { .cc-teaser__item::after, .cc-teaser__cap { opacity: 1; transform: none; } }
